Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

847 lines
23 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. fcache.cxx
  5. Abstract:
  6. This module supports functions for file caching for servers
  7. Author:
  8. Murali R. Krishnan ( MuraliK ) 11-Oct-1995
  9. Environment:
  10. Win32 Apps
  11. Project:
  12. Internet Services Common DLL
  13. Functions Exported:
  14. Revision History:
  15. Obtained from old inetsvcs.dll
  16. --*/
  17. /************************************************************
  18. * Include Headers
  19. ************************************************************/
  20. #include <tcpdllp.hxx>
  21. #include <issched.hxx>
  22. #include <tsunami.hxx>
  23. #include <iistypes.hxx>
  24. #include <festrcnv.h>
  25. # include "inetreg.h"
  26. //
  27. // Prototypes
  28. //
  29. //
  30. // Globals
  31. //
  32. /************************************************************
  33. * Functions
  34. ************************************************************/
  35. //
  36. // We need a wrapper class for the file data because
  37. // everything in the blob cache must be derived from
  38. // BLOB_HEADER.
  39. //
  40. class FILE_DATA : public BLOB_HEADER
  41. {
  42. public:
  43. BYTE * pbData;
  44. };
  45. BOOL
  46. CheckOutCachedFile(
  47. IN const CHAR * pchFile,
  48. IN TSVC_CACHE * pTsvcCache,
  49. IN HANDLE hToken,
  50. OUT BYTE * * ppbData,
  51. OUT DWORD * pcbData,
  52. IN BOOL fMayCacheAccessToken,
  53. OUT PCACHE_FILE_INFO pCacheFileInfo,
  54. IN int nCharset,
  55. OUT PSECURITY_DESCRIPTOR* ppSecDesc,
  56. IN BOOL fUseWin32Canon
  57. )
  58. /*++
  59. Description:
  60. Attempts to retrieve the passed file from the cache. If it's not
  61. cached, then we read the file and add it to the cache.
  62. Arguments:
  63. pchFile - Fully qualified file to retrieve
  64. pTsvcCache - Cache object to charge memory against
  65. hToken - Impersonation token to open the file with
  66. pcbData - Receives pointer to first byte of data, used as handle to
  67. free data
  68. pcbSize - Size of output buffer
  69. pCacheFileInfo - File cache information
  70. nCharset - Charset (if this isn't SJIS, we convert it to SJIS
  71. before Check-In)
  72. ppSecDesc - Returns security descriptor if not null
  73. fUseWin32Canon - The resource has not been canonicalized and it's ok
  74. to use the win32 canonicalization code
  75. Returns:
  76. TRUE if successful, FALSE otherwise
  77. Notes:
  78. The file is extended by two bytes and is appended with two zero bytes,
  79. thus callers are guaranteed of a zero terminated text file.
  80. --*/
  81. {
  82. TS_OPEN_FILE_INFO * pFile = NULL;
  83. DWORD cbLow, cbHigh;
  84. BYTE * pbData = NULL;
  85. FILE_DATA * pFileData = NULL;
  86. BOOL fCached = TRUE;
  87. PSECURITY_DESCRIPTOR pSecDesc;
  88. BYTE * pbBuff = NULL;
  89. int cbSJISSize;
  90. const ULONG cchFile = strlen(pchFile);
  91. //
  92. // Is the file already in the cache?
  93. //
  94. if ( !TsCheckOutCachedBlob( *pTsvcCache,
  95. pchFile,
  96. cchFile,
  97. RESERVED_DEMUX_FILE_DATA,
  98. (VOID **) &pFileData,
  99. hToken,
  100. fMayCacheAccessToken,
  101. ppSecDesc ))
  102. {
  103. DWORD dwOptions;
  104. if ( GetLastError() == ERROR_ACCESS_DENIED )
  105. {
  106. return FALSE;
  107. }
  108. //
  109. // The file isn't in the cache so open the file and get its size
  110. //
  111. fCached = FALSE;
  112. dwOptions = (fMayCacheAccessToken ? TS_CACHING_DESIRED :
  113. TS_DONT_CACHE_ACCESS_TOKEN) |
  114. (fUseWin32Canon ? TS_USE_WIN32_CANON : 0);
  115. if ( !(pFile = TsCreateFile( *pTsvcCache,
  116. pchFile,
  117. hToken,
  118. dwOptions )) ||
  119. !pFile->QuerySize( &cbLow, &cbHigh ))
  120. {
  121. goto ErrorExit;
  122. }
  123. //
  124. // Limit the file size to 128k
  125. //
  126. if ( cbHigh || cbLow > 131072L )
  127. {
  128. SetLastError( ERROR_NOT_SUPPORTED );
  129. goto ErrorExit;
  130. }
  131. if ( CODE_ONLY_SBCS != nCharset )
  132. {
  133. if ( !( pbBuff = pbData = (BYTE *)LocalAlloc( LPTR, cbLow ) ) )
  134. {
  135. SetLastError( ERROR_NOT_ENOUGH_MEMORY);
  136. goto ErrorExit;
  137. }
  138. }
  139. else {
  140. if ( !TsAllocate( *pTsvcCache,
  141. cbLow + sizeof(WCHAR) + sizeof(FILE_DATA),
  142. (VOID **) &pFileData ))
  143. {
  144. goto ErrorExit;
  145. }
  146. pbData = pFileData->pbData = (BYTE *) (pFileData + 1);
  147. }
  148. //
  149. // Read the file data
  150. //
  151. if ( !DoSynchronousReadFile(
  152. pFile->QueryFileHandle(),
  153. (PCHAR)pbData,
  154. cbLow,
  155. pcbData,
  156. NULL ))
  157. {
  158. goto ErrorExit;
  159. }
  160. if ( CODE_ONLY_SBCS != nCharset )
  161. {
  162. pbData = NULL;
  163. //
  164. // get the length after conversion
  165. //
  166. cbSJISSize = UNIX_to_PC( GetACP(),
  167. nCharset,
  168. pbBuff,
  169. *pcbData,
  170. NULL,
  171. 0 );
  172. DBG_ASSERT( cbSJISSize <= (int)cbLow );
  173. if ( !TsAllocate( *pTsvcCache,
  174. cbSJISSize + sizeof(WCHAR) + sizeof(FILE_DATA),
  175. (VOID **) &pFileData ))
  176. {
  177. goto ErrorExit;
  178. }
  179. pbData = pFileData->pbData = (BYTE *) (pFileData + 1);
  180. //
  181. // conversion
  182. //
  183. UNIX_to_PC( GetACP(),
  184. nCharset,
  185. pbBuff,
  186. *pcbData,
  187. pbData,
  188. cbSJISSize );
  189. *pcbData = cbLow = cbSJISSize;
  190. }
  191. DBG_ASSERT( *pcbData <= cbLow );
  192. //
  193. // Zero terminate the file for both ANSI and Unicode files
  194. //
  195. *((WCHAR UNALIGNED *)(pbData + cbLow)) = L'\0';
  196. *pcbData += sizeof(WCHAR);
  197. //
  198. // Add this blob to the cache manager and check it out, if it fails,
  199. // we just free it below
  200. //
  201. if ( TsCacheDirectoryBlob( *pTsvcCache,
  202. pchFile,
  203. cchFile,
  204. RESERVED_DEMUX_FILE_DATA,
  205. pFileData,
  206. TRUE,
  207. pSecDesc = TsGetFileSecDesc( pFile ) ) )
  208. {
  209. fCached = TRUE;
  210. }
  211. else
  212. {
  213. if ( pSecDesc )
  214. {
  215. LocalFree( pSecDesc );
  216. }
  217. }
  218. if ( ppSecDesc )
  219. {
  220. *ppSecDesc = TsGetFileSecDesc( pFile );
  221. }
  222. DBG_REQUIRE( TsCloseHandle( *pTsvcCache,
  223. pFile ));
  224. pFile = NULL;
  225. }
  226. else
  227. {
  228. //
  229. // File was in the cache
  230. //
  231. pbData = pFileData->pbData;
  232. //
  233. // Calculate the length to return, including the double null
  234. // Note: assuming no nulls in the middle of the file here
  235. //
  236. *pcbData = strlen( (CHAR *) pbData ) + sizeof(WCHAR);
  237. }
  238. pCacheFileInfo->pbData = *ppbData = pbData;
  239. pCacheFileInfo->dwCacheFlags = fCached;
  240. pCacheFileInfo->pFileData = pFileData;
  241. if ( pbBuff )
  242. {
  243. LocalFree( pbBuff );
  244. }
  245. return TRUE;
  246. ErrorExit:
  247. if ( pFile )
  248. {
  249. DBG_REQUIRE( TsCloseHandle( *pTsvcCache,
  250. pFile ));
  251. }
  252. if ( pbBuff )
  253. {
  254. if ( pbBuff == pbData )
  255. {
  256. pbData = NULL;
  257. }
  258. LocalFree( pbBuff );
  259. }
  260. if ( pbData )
  261. {
  262. if ( fCached )
  263. {
  264. DBG_REQUIRE( TsCheckInCachedBlob( pFileData ));
  265. }
  266. else
  267. {
  268. DBG_REQUIRE( TsFree( *pTsvcCache,
  269. pFileData ));
  270. }
  271. }
  272. return FALSE;
  273. }
  274. BOOL
  275. CheckOutCachedFileFromURI(
  276. IN PVOID URIFile,
  277. IN const CHAR * pchFile,
  278. IN TSVC_CACHE * pTsvcCache,
  279. IN HANDLE hToken,
  280. OUT BYTE * * ppbData,
  281. OUT DWORD * pcbData,
  282. IN BOOL fMayCacheAccessToken,
  283. OUT PCACHE_FILE_INFO pCacheFileInfo,
  284. IN int nCharset,
  285. OUT PSECURITY_DESCRIPTOR* ppSecDesc,
  286. IN BOOL fUseWin32Canon
  287. )
  288. /*++
  289. Description:
  290. Attempts to retrieve the passed file from the cache. If it's not
  291. cached, then we read the file and add it to the cache.
  292. Arguments:
  293. pchFile - Fully qualified file to retrieve
  294. pTsvcCache - Cache object to charge memory against
  295. hToken - Impersonation token to open the file with
  296. pcbData - Receives pointer to first byte of data, used as handle to
  297. free data
  298. pcbSize - Size of output buffer
  299. pCacheFileInfo - File cache information
  300. nCharset - Charset (if this isn't SJIS, we convert it to SJIS
  301. before Check-In)
  302. ppSecDesc - Returns security descriptor if not null
  303. fUseWin32Canon - The resource has not been canonicalized and it's ok
  304. to use the win32 canonicalization code
  305. Returns:
  306. TRUE if successful, FALSE otherwise
  307. Notes:
  308. The file is extended by two bytes and is appended with two zero bytes,
  309. thus callers are guaranteed of a zero terminated text file.
  310. --*/
  311. {
  312. DWORD cbLow, cbHigh;
  313. BYTE * pbData = NULL;
  314. FILE_DATA * pFileData = NULL;
  315. BOOL fCached = TRUE;
  316. PSECURITY_DESCRIPTOR pSecDesc;
  317. BYTE * pbBuff = NULL;
  318. int cbSJISSize;
  319. const ULONG cchFile = strlen(pchFile);
  320. TS_OPEN_FILE_INFO * pFile = (LPTS_OPEN_FILE_INFO)URIFile;
  321. //
  322. // Is the file already in the cache?
  323. //
  324. if ( !TsCheckOutCachedBlob( *pTsvcCache,
  325. pchFile,
  326. cchFile,
  327. RESERVED_DEMUX_FILE_DATA,
  328. (VOID **) &pFileData,
  329. hToken,
  330. fMayCacheAccessToken,
  331. ppSecDesc ))
  332. {
  333. if ( GetLastError() == ERROR_ACCESS_DENIED )
  334. {
  335. return FALSE;
  336. }
  337. //
  338. // The file isn't in the cache so open the file and get its size
  339. //
  340. fCached = FALSE;
  341. if ( !pFile->QuerySize( &cbLow, &cbHigh ))
  342. {
  343. goto ErrorExit;
  344. }
  345. //
  346. // Limit the file size to 128k
  347. //
  348. if ( cbHigh || cbLow > 131072L )
  349. {
  350. SetLastError( ERROR_NOT_SUPPORTED );
  351. goto ErrorExit;
  352. }
  353. if ( CODE_ONLY_SBCS != nCharset )
  354. {
  355. if ( !( pbBuff = pbData = (BYTE *)LocalAlloc( LPTR, cbLow ) ) )
  356. {
  357. SetLastError( ERROR_NOT_ENOUGH_MEMORY);
  358. goto ErrorExit;
  359. }
  360. }
  361. else {
  362. if ( !TsAllocate( *pTsvcCache,
  363. cbLow + sizeof(WCHAR) + sizeof(FILE_DATA),
  364. (VOID **) &pFileData ))
  365. {
  366. goto ErrorExit;
  367. }
  368. pbData = pFileData->pbData = (BYTE *) (pFileData + 1);
  369. }
  370. //
  371. // Read the file data
  372. //
  373. if ( !DoSynchronousReadFile(
  374. pFile->QueryFileHandle(),
  375. (PCHAR)pbData,
  376. cbLow,
  377. pcbData,
  378. NULL ))
  379. {
  380. goto ErrorExit;
  381. }
  382. if ( CODE_ONLY_SBCS != nCharset )
  383. {
  384. pbData = NULL;
  385. //
  386. // get the length after conversion
  387. //
  388. cbSJISSize = UNIX_to_PC( GetACP(),
  389. nCharset,
  390. pbBuff,
  391. *pcbData,
  392. NULL,
  393. 0 );
  394. DBG_ASSERT( cbSJISSize <= (int)cbLow );
  395. if ( !TsAllocate( *pTsvcCache,
  396. cbSJISSize + sizeof(WCHAR) + sizeof(FILE_DATA),
  397. (VOID **) &pFileData ))
  398. {
  399. goto ErrorExit;
  400. }
  401. pbData = pFileData->pbData = (BYTE *) (pFileData + 1);
  402. //
  403. // conversion
  404. //
  405. UNIX_to_PC( GetACP(),
  406. nCharset,
  407. pbBuff,
  408. *pcbData,
  409. pbData,
  410. cbSJISSize );
  411. *pcbData = cbLow = cbSJISSize;
  412. }
  413. DBG_ASSERT( *pcbData <= cbLow );
  414. //
  415. // Zero terminate the file for both ANSI and Unicode files
  416. //
  417. *((WCHAR UNALIGNED *)(pbData + cbLow)) = L'\0';
  418. *pcbData += sizeof(WCHAR);
  419. //
  420. // Add this blob to the cache manager and check it out, if it fails,
  421. // we just free it below
  422. //
  423. if ( TsCacheDirectoryBlob( *pTsvcCache,
  424. pchFile,
  425. cchFile,
  426. RESERVED_DEMUX_FILE_DATA,
  427. pFileData,
  428. TRUE,
  429. pSecDesc = TsGetFileSecDesc( pFile ) ) )
  430. {
  431. fCached = TRUE;
  432. }
  433. else
  434. {
  435. if ( pSecDesc )
  436. {
  437. LocalFree( pSecDesc );
  438. }
  439. }
  440. if ( ppSecDesc )
  441. {
  442. *ppSecDesc = TsGetFileSecDesc( pFile );
  443. }
  444. }
  445. else
  446. {
  447. //
  448. // File was in the cache
  449. //
  450. pbData = pFileData->pbData;
  451. //
  452. // Calculate the length to return, including the double null
  453. // Note: assuming no nulls in the middle of the file here
  454. //
  455. *pcbData = strlen( (CHAR *) pbData ) + sizeof(WCHAR);
  456. }
  457. pCacheFileInfo->pbData = *ppbData = pbData;
  458. pCacheFileInfo->dwCacheFlags = fCached;
  459. pCacheFileInfo->pFileData = pFileData;
  460. if ( pbBuff )
  461. {
  462. LocalFree( pbBuff );
  463. }
  464. return TRUE;
  465. ErrorExit:
  466. if ( pbBuff )
  467. {
  468. if ( pbBuff == pbData )
  469. {
  470. pbData = NULL;
  471. }
  472. LocalFree( pbBuff );
  473. }
  474. if ( pbData )
  475. {
  476. if ( fCached )
  477. {
  478. DBG_REQUIRE( TsCheckInCachedBlob( pFileData ));
  479. }
  480. else
  481. {
  482. DBG_REQUIRE( TsFree( *pTsvcCache,
  483. pFileData ));
  484. }
  485. }
  486. return FALSE;
  487. }
  488. BOOL
  489. CheckInCachedFile(
  490. IN TSVC_CACHE * pTsvcCache,
  491. IN PCACHE_FILE_INFO pCacheFileInfo
  492. )
  493. /*++
  494. Description:
  495. Checks in or frees a cached file
  496. Arguments:
  497. pTsvcCache - Cache object to charge memory against
  498. pCacheFileInfo - Pointer to file cache information
  499. Returns:
  500. TRUE if successful, FALSE otherwise
  501. Notes:
  502. --*/
  503. {
  504. BOOL fRet;
  505. DBG_ASSERT( (pCacheFileInfo->dwCacheFlags == FALSE) || (
  506. pCacheFileInfo->dwCacheFlags == TRUE) );
  507. //
  508. // If we cached the item, check it back in to the cache, otherwise
  509. // free the associated memory
  510. //
  511. if ( pCacheFileInfo->dwCacheFlags )
  512. {
  513. DBG_REQUIRE( fRet = TsCheckInCachedBlob( pCacheFileInfo->pFileData ));
  514. }
  515. else
  516. {
  517. DBG_REQUIRE( fRet = TsFree( *pTsvcCache,
  518. pCacheFileInfo->pFileData ));
  519. }
  520. return fRet;
  521. }
  522. //
  523. // Taken from NCSA HTTP and wwwlib.
  524. //
  525. // NOTE: These conform to RFC1113, which is slightly different then the Unix
  526. // uuencode and uudecode!
  527. //
  528. const int _pr2six[256]={
  529. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  530. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
  531. 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
  532. 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
  533. 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
  534. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  535. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  536. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  537. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  538. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  539. 64,64,64,64,64,64,64,64,64,64,64,64,64
  540. };
  541. char _six2pr[64] = {
  542. 'A','B','C','D','E','F','G','H','I','J','K','L','M',
  543. 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
  544. 'a','b','c','d','e','f','g','h','i','j','k','l','m',
  545. 'n','o','p','q','r','s','t','u','v','w','x','y','z',
  546. '0','1','2','3','4','5','6','7','8','9','+','/'
  547. };
  548. const int _pr2six64[256]={
  549. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  550. 64,64,64,64,64,64,64,64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
  551. 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,
  552. 40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
  553. 0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  554. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  555. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  556. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  557. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  558. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  559. 64,64,64,64,64,64,64,64,64,64,64,64,64
  560. };
  561. char _six2pr64[64] = {
  562. '`','!','"','#','$','%','&','\'','(',')','*','+',',',
  563. '-','.','/','0','1','2','3','4','5','6','7','8','9',
  564. ':',';','<','=','>','?','@','A','B','C','D','E','F',
  565. 'G','H','I','J','K','L','M','N','O','P','Q','R','S',
  566. 'T','U','V','W','X','Y','Z','[','\\',']','^','_'
  567. };
  568. BOOL uudecode(char * bufcoded,
  569. BUFFER * pbuffdecoded,
  570. DWORD * pcbDecoded,
  571. BOOL fBase64
  572. )
  573. {
  574. int nbytesdecoded;
  575. char *bufin = bufcoded;
  576. unsigned char *bufout;
  577. int nprbytes;
  578. int *pr2six = (int*)(fBase64 ? _pr2six64 : _pr2six);
  579. /* Strip leading whitespace. */
  580. while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
  581. /* Figure out how many characters are in the input buffer.
  582. * If this would decode into more bytes than would fit into
  583. * the output buffer, adjust the number of input bytes downwards.
  584. */
  585. bufin = bufcoded;
  586. while(pr2six[*(bufin++)] <= 63);
  587. nprbytes = DIFF(bufin - bufcoded) - 1;
  588. nbytesdecoded = ((nprbytes+3)/4) * 3;
  589. if ( !pbuffdecoded->Resize( nbytesdecoded + 4 ))
  590. return FALSE;
  591. bufout = (unsigned char *) pbuffdecoded->QueryPtr();
  592. bufin = bufcoded;
  593. while (nprbytes > 0) {
  594. *(bufout++) =
  595. (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
  596. *(bufout++) =
  597. (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
  598. *(bufout++) =
  599. (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
  600. bufin += 4;
  601. nprbytes -= 4;
  602. }
  603. if(nprbytes & 03) {
  604. if(pr2six[bufin[-2]] > 63)
  605. nbytesdecoded -= 2;
  606. else
  607. nbytesdecoded -= 1;
  608. }
  609. ((CHAR *)pbuffdecoded->QueryPtr())[nbytesdecoded] = '\0';
  610. if ( pcbDecoded )
  611. *pcbDecoded = nbytesdecoded;
  612. return TRUE;
  613. }
  614. //
  615. // NOTE NOTE NOTE
  616. // If the buffer length isn't a multiple of 3, we encode one extra byte beyond the
  617. // end of the buffer. This garbage byte is stripped off by the uudecode code, but
  618. // -IT HAS TO BE THERE- for uudecode to work. This applies not only our uudecode, but
  619. // to every uudecode() function that is based on the lib-www distribution [probably
  620. // a fairly large percentage].
  621. //
  622. BOOL uuencode( BYTE * bufin,
  623. DWORD nbytes,
  624. BUFFER * pbuffEncoded,
  625. BOOL fBase64 )
  626. {
  627. unsigned char *outptr;
  628. unsigned int i;
  629. char *six2pr = fBase64 ? _six2pr64 : _six2pr;
  630. BOOL fOneByteDiff = FALSE;
  631. BOOL fTwoByteDiff = FALSE;
  632. unsigned int iRemainder = 0;
  633. unsigned int iClosestMultOfThree = 0;
  634. //
  635. // Resize the buffer to 133% of the incoming data
  636. //
  637. if ( !pbuffEncoded->Resize( nbytes + ((nbytes + 3) / 3) + 4))
  638. return FALSE;
  639. outptr = (unsigned char *) pbuffEncoded->QueryPtr();
  640. iRemainder = nbytes % 3; //also works for nbytes == 1, 2
  641. fOneByteDiff = (iRemainder == 1 ? TRUE : FALSE);
  642. fTwoByteDiff = (iRemainder == 2 ? TRUE : FALSE);
  643. iClosestMultOfThree = ((nbytes - iRemainder)/3) * 3 ;
  644. //
  645. // Encode bytes in buffer up to multiple of 3 that is closest to nbytes.
  646. //
  647. for (i=0; i< iClosestMultOfThree ; i += 3) {
  648. *(outptr++) = six2pr[*bufin >> 2]; /* c1 */
  649. *(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
  650. *(outptr++) = six2pr[((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)];/*c3*/
  651. *(outptr++) = six2pr[bufin[2] & 077]; /* c4 */
  652. bufin += 3;
  653. }
  654. //
  655. // We deal with trailing bytes by pretending that the input buffer has been padded with
  656. // zeros. Expressions are thus the same as above, but the second half drops off b'cos
  657. // ( a | ( b & 0) ) = ( a | 0 ) = a
  658. //
  659. if (fOneByteDiff)
  660. {
  661. *(outptr++) = six2pr[*bufin >> 2]; /* c1 */
  662. *(outptr++) = six2pr[((*bufin << 4) & 060)]; /* c2 */
  663. //pad with '='
  664. *(outptr++) = '='; /* c3 */
  665. *(outptr++) = '='; /* c4 */
  666. }
  667. else if (fTwoByteDiff)
  668. {
  669. *(outptr++) = six2pr[*bufin >> 2]; /* c1 */
  670. *(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
  671. *(outptr++) = six2pr[((bufin[1] << 2) & 074)];/*c3*/
  672. //pad with '='
  673. *(outptr++) = '='; /* c4 */
  674. }
  675. //encoded buffer must be zero-terminated
  676. *outptr = '\0';
  677. return TRUE;
  678. }
  679. /************************ End of File ***********************/
  680.