ODUtil.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /* OpenDoors Online Software Programming Toolkit
  2. * (C) Copyright 1991 - 1999 by Brian Pirie.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. *
  19. * File: ODUtil.c
  20. *
  21. * Description: Implements the non-platform specific utility functions that
  22. * are defined in odutil.h. Platform specific utility functions
  23. * are implemented in odplat.c.
  24. *
  25. *
  26. * Revisions: Date Ver Who Change
  27. * ---------------------------------------------------------------
  28. * Nov 01, 1994 6.00 BP Created.
  29. * Dec 31, 1994 6.00 BP Added ODMakeFilename().
  30. * Nov 13, 1995 6.00 BP 32-bit portability.
  31. * Nov 23, 1995 6.00 BP Added ODDWordDivide().
  32. * Nov 23, 1995 6.00 BP Added ODDStringHasTail().
  33. * Nov 23, 1995 6.00 BP Added ODFileSize().
  34. * Nov 24, 1995 6.00 BP ODMakeFilename(): handle empty path.
  35. * Feb 19, 1996 6.00 BP Changed version number to 6.00.
  36. * Mar 03, 1996 6.10 BP Begin version 6.10.
  37. * Mar 06, 1996 6.10 BP Added ODDWordMultiply().
  38. * Aug 10, 2003 6.23 SH *nix support
  39. */
  40. #define BUILDING_OPENDOORS
  41. #include <string.h>
  42. #include <stdio.h>
  43. #include "OpenDoor.h"
  44. #include "ODStr.h"
  45. #include "ODUtil.h"
  46. #include "ODGen.h"
  47. /* ========================================================================= */
  48. /* General string manipulation functions. */
  49. /* ========================================================================= */
  50. /* ----------------------------------------------------------------------------
  51. * ODStringCopy()
  52. *
  53. * Safely copies one string to another. Unlike strncpy(), ODStringCopy()
  54. * ensures that the destination string is always '\0' terminated.
  55. *
  56. * Parameters: pszDest - Pointer to destination string to which to copy
  57. * characters.
  58. *
  59. * pszSource - Pointer to source string from which to copy
  60. * characters.
  61. *
  62. * nSizeOfDest - Maximum number of characters to place in pszDest,
  63. * INCLUDING the '\0' string terminator.
  64. *
  65. * Return: void
  66. */
  67. void ODStringCopy(char *pszDest, CONST char *pszSource, INT nSizeofDest)
  68. {
  69. ASSERT(pszDest != NULL);
  70. ASSERT(pszSource != NULL);
  71. ASSERT(nSizeofDest > 0);
  72. /* Copy at most the specified number of bytes from source to dest, using */
  73. /* (presumably well optimized) strncpy(). */
  74. strncpy(pszDest, pszSource, nSizeofDest);
  75. /* Ensure that destination string is '\0' terminated. This will not */
  76. /* already be the case if strlen(pszSource) >= nSizeofDest. */
  77. pszDest[nSizeofDest - 1] = '\0';
  78. }
  79. /* ----------------------------------------------------------------------------
  80. * ODStringCToPascal()
  81. *
  82. * Converts a string from C's zero-terminated string format to Pascal's
  83. * length byte + string data format.
  84. *
  85. * Parameters: psPascalString - Pointer to the destination string.
  86. *
  87. * btMaxPascalLength - Size of the destination string, as declared
  88. * in Pascal.
  89. *
  90. * pszCString - Pointer to the source string, in C format.
  91. *
  92. * Return: A pointer to psPascalString.
  93. */
  94. char *ODStringCToPascal(char *psPascalString, BYTE btMaxPascalLength,
  95. char *pszCString)
  96. {
  97. BYTE btCStringLength = strlen(pszCString);
  98. ASSERT(psPascalString != NULL);
  99. ASSERT(btMaxPascalLength > 0);
  100. ASSERT(pszCString != NULL);
  101. memcpy((char *)psPascalString + 1,
  102. pszCString, *psPascalString = (btCStringLength < btMaxPascalLength)
  103. ? btCStringLength : btMaxPascalLength);
  104. return(psPascalString);
  105. }
  106. /* ----------------------------------------------------------------------------
  107. * ODStringPascalToC()
  108. *
  109. * Converts a string from Pascal's length byte + string data format to C's
  110. * zero-terminated string format.
  111. *
  112. * Parameters: pszCString - Pointer to destination string.
  113. *
  114. * psPascalString - Pointer to Pascal format source string.
  115. *
  116. * btMaxLength - Length of C string.
  117. *
  118. * Return: A pointer to pszCString.
  119. */
  120. char *ODStringPascalToC(char *pszCString, char *psPascalString,
  121. BYTE btMaxLength)
  122. {
  123. ASSERT(pszCString != NULL);
  124. ASSERT(psPascalString != NULL);
  125. ASSERT(btMaxLength > 0);
  126. if(*(BYTE *)psPascalString <= btMaxLength)
  127. {
  128. memcpy(pszCString, (char *)psPascalString + 1, *psPascalString);
  129. pszCString[(int)psPascalString[0]] = '\0';
  130. }
  131. else
  132. {
  133. pszCString[0] = '\0';
  134. }
  135. return(pszCString);
  136. }
  137. /* ----------------------------------------------------------------------------
  138. * ODStringHasTail()
  139. *
  140. * Determines whether a string ends in exactly the specified sequence of
  141. * characters.
  142. *
  143. * Parameters: pszFullString - String to examine.
  144. *
  145. * pszTail - String to look for at the end of
  146. * pszFullString.
  147. *
  148. * Return: TRUE if the pszFullString does end with pszTail, FALSE if
  149. * it does not.
  150. */
  151. BOOL ODStringHasTail(char *pszFullString, char *pszTail)
  152. {
  153. INT nTailLength = strlen(pszTail);
  154. INT nFullStringLength = strlen(pszFullString);
  155. ASSERT(pszFullString != NULL);
  156. ASSERT(pszTail != NULL);
  157. if(nFullStringLength < nTailLength)
  158. {
  159. return(FALSE);
  160. }
  161. return(stricmp(pszFullString + (nFullStringLength - nTailLength), pszTail) == 0);
  162. }
  163. /* ========================================================================= */
  164. /* File-related functions. */
  165. /* ========================================================================= */
  166. /* ----------------------------------------------------------------------------
  167. * ODMakeFilename()
  168. *
  169. * Generates a fully-qualified filename from a path and base filename.
  170. *
  171. * Parameters: pszOut - String to store generated filename in.
  172. *
  173. * pszPath - Directory name. May be the same as pszOut, or
  174. * may be different.
  175. *
  176. * pszFilename - Base filename.
  177. *
  178. * nMaxOutSize - Size of pszOut. This value should be one more
  179. * than the maximum number of characters to be
  180. * stored in the output string.
  181. *
  182. * Return: kODRCSuccess on success, or an error code on failure.
  183. */
  184. tODResult ODMakeFilename(char *pszOut, CONST char *pszPath,
  185. CONST char *pszFilename, INT nMaxOutSize)
  186. {
  187. /* Validate parameters in debug mode */
  188. ASSERT(pszPath != NULL);
  189. ASSERT(pszFilename != NULL);
  190. ASSERT(pszOut != NULL);
  191. ASSERT(pszFilename != pszOut);
  192. ASSERT(nMaxOutSize > 0);
  193. /* Check that there is enough room in the destination string to hold */
  194. /* both source strings plus possibly an additional \-seperator. */
  195. if((INT)(strlen(pszPath) + strlen(pszFilename) + 1) > nMaxOutSize - 1)
  196. {
  197. return(kODRCFilenameTooLong);
  198. }
  199. /* Copy path to output filename, if the addresses are different. */
  200. if(pszPath != pszOut)
  201. {
  202. strcpy(pszOut, pszPath);
  203. }
  204. /* Ensure there is a trailing backslash, if path was not empty. */
  205. #ifdef ODPLAT_NIX
  206. #else
  207. if(pszOut[strlen(pszOut) - 1] != DIRSEP && strlen(pszOut) > 0)
  208. {
  209. strcat(pszOut, DIRSEP_STR);
  210. }
  211. #endif
  212. /* Append base filename. */
  213. strcat(pszOut, pszFilename);
  214. return(kODRCSuccess);
  215. }
  216. /* ----------------------------------------------------------------------------
  217. * ODFileSize()
  218. *
  219. * Determines the size of a currently open file.
  220. *
  221. * Parameters: pfFile - Pointer to an already open file to examine.
  222. *
  223. * Return: The size of the file. In the case of a file that is open in
  224. * binary mode, this will be the file length in bytes.
  225. */
  226. DWORD ODFileSize(FILE *pfFile)
  227. {
  228. DWORD dwOriginal;
  229. DWORD dwFileSize;
  230. ASSERT(pfFile != NULL);
  231. dwOriginal = ftell(pfFile);
  232. fseek(pfFile, 0L, SEEK_END);
  233. dwFileSize = ftell(pfFile);
  234. fseek(pfFile, dwOriginal, SEEK_SET);
  235. return(dwFileSize);
  236. }
  237. /* ========================================================================= */
  238. /* DWORD math functions. */
  239. /* ========================================================================= */
  240. /* ----------------------------------------------------------------------------
  241. * ODDWordShiftLeft()
  242. *
  243. * Shifts a DWORD to the left by the specified number of bits.
  244. *
  245. * Parameters: dwValue - Value to be shifted.
  246. *
  247. * btDistance - Distance to shift dwValue by.
  248. *
  249. * Return: Result of the shift operation.
  250. */
  251. DWORD ODDWordShiftLeft(DWORD dwValue, BYTE btDistance)
  252. {
  253. WORD wUpper;
  254. WORD wLower;
  255. wLower = (WORD)dwValue;
  256. wUpper = *(WORD *)(((BYTE *)(&dwValue)) + 2);
  257. while(btDistance--)
  258. {
  259. wUpper <<= 1;
  260. wUpper |= (wLower & 0x8000) >> 15;
  261. wLower <<= 1;
  262. }
  263. dwValue = wLower;
  264. *(WORD *)(((BYTE *)(&dwValue)) + 2) = wUpper;
  265. return(dwValue);
  266. }
  267. /* ----------------------------------------------------------------------------
  268. * ODDWordShiftRight()
  269. *
  270. * Shifts a DWORD to the right by the specified number of bits.
  271. *
  272. * Parameters: dwValue - Value to be shifted.
  273. *
  274. * btDistance - Distance to shift dwValue by.
  275. *
  276. * Return: Result of the shift operation.
  277. */
  278. DWORD ODDWordShiftRight(DWORD dwValue, BYTE btDistance)
  279. {
  280. WORD wUpper;
  281. WORD wLower;
  282. wLower = (WORD)dwValue;
  283. wUpper = *(WORD *)(((BYTE *)(&dwValue)) + 2);
  284. while(btDistance--)
  285. {
  286. wLower >>= 1;
  287. wLower |= (wUpper & 0x0001) << 15;
  288. wUpper >>= 1;
  289. }
  290. dwValue=wLower;
  291. *(WORD *)(((BYTE *)(&dwValue)) + 2) = wUpper;
  292. return(dwValue);
  293. }
  294. /* ----------------------------------------------------------------------------
  295. * ODDWordDivide()
  296. *
  297. * Divides one DWORD by another DWORD, calculating the quotient and remainder.
  298. *
  299. * Parameters: pdwQuotient - Location where the quotient should be stored,
  300. * or NULL if quotient is not required.
  301. *
  302. * pdwRemainder - Location where remainder should be stored,
  303. * or NULL if remainder is not required.
  304. *
  305. * dwDividend - Dividend to be divided by divisor.
  306. *
  307. * dwDivisor - Divisor to divide dividend by.
  308. *
  309. * Return: TRUE on success or FALSE on failure.
  310. */
  311. BOOL ODDWordDivide(DWORD *pdwQuotient, DWORD *pdwRemainder,
  312. DWORD dwDividend, DWORD dwDivisor)
  313. {
  314. INT nTimes = 0;
  315. DWORD dwQuotient;
  316. DWORD dwRemainder;
  317. /* Check for divide by zero in debug versions. */
  318. ASSERT(dwDivisor != 0);
  319. /* Check that divisor is not zero. (An attempt to divide by zero will */
  320. /* put this algorithm into an infinite loop, rather than triggering */
  321. /* a divide fault.) */
  322. if(dwDivisor == 0L)
  323. {
  324. return(FALSE);
  325. }
  326. /* Initialize remainder to be entire dividend */
  327. dwRemainder = dwDividend;
  328. /* Initialize quotient to 0 */
  329. dwQuotient = 0L;
  330. /* Determine largest required multiple of divisor */
  331. while(dwRemainder >= dwDivisor)
  332. {
  333. dwDivisor = ODDWordShiftLeft(dwDivisor, 1);
  334. ++nTimes;
  335. }
  336. /* Loop across for all multiples of divisor, beginning with the largest */
  337. do
  338. {
  339. dwQuotient = ODDWordShiftLeft(dwQuotient, 1);
  340. /* If current remainder is >= this multiple of the divisor */
  341. if(dwRemainder >= dwDivisor)
  342. {
  343. /* Subtract the multiple of the divisor from the remainder */
  344. dwRemainder -= dwDivisor;
  345. /* The next bit of the quotient should be a 1 */
  346. dwQuotient |= 1L;
  347. }
  348. /* Divide current multiple of divisor by two */
  349. dwDivisor = ODDWordShiftRight(dwDivisor, 1);
  350. /* Repeat for all multiples of the divisor */
  351. } while(nTimes--);
  352. /* If caller asked for quotient, then return it */
  353. if(pdwQuotient != NULL)
  354. {
  355. *pdwQuotient = dwQuotient;
  356. }
  357. /* If caller asked for remainder, then return it */
  358. if(pdwRemainder != NULL)
  359. {
  360. *pdwRemainder = dwRemainder;
  361. }
  362. return(TRUE);
  363. }
  364. /* ----------------------------------------------------------------------------
  365. * ODDWordDivide()
  366. *
  367. * Multiplies one DWORD by another, returning the product. Multiplication
  368. * is performed by using at most 32 additions.
  369. *
  370. * Parameters: dwMultiplicand - The multiplicand.
  371. *
  372. * dwMultiplier - The multiplier.
  373. *
  374. * Return: Result of the multiplication.
  375. */
  376. DWORD ODDWordMultiply(DWORD dwMultiplicand, DWORD dwMultiplier)
  377. {
  378. DWORD dwResult = 0;
  379. /* Loop while multiplier is not zero */
  380. while(dwMultiplier != 0)
  381. {
  382. /* If least significant bit of multiplier is set */
  383. if(dwMultiplier & 0x00000001)
  384. {
  385. /* Add multiplicand to product */
  386. dwResult += dwMultiplicand;
  387. }
  388. /* Shift multiplicand left one bit */
  389. dwMultiplicand = ODDWordShiftLeft(dwMultiplicand, 1);
  390. /* Shift multiplier right one bit */
  391. dwMultiplier = ODDWordShiftRight(dwMultiplier, 1);
  392. }
  393. /* Return the final result to the caller. */
  394. return(dwResult);
  395. }