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.

840 lines
22 KiB

  1. /************************************************************************
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name :
  4. cssup.cxx
  5. Abstract :
  6. Support routines for international character (cs) support.
  7. Author :
  8. Mike Warning MikeW August 1999.
  9. Revision History :
  10. ***********************************************************************/
  11. #include "ndrp.h"
  12. #include "cssup.h"
  13. BOOL GetThreadACP(
  14. unsigned long *cp,
  15. error_status_t *pStatus)
  16. /*++
  17. Routine Description :
  18. Get the current codepage of this thread.
  19. Arguments :
  20. cp -- Pointer to where to return the codepage
  21. pStatus -- Pointer to where to return the status of the operation
  22. Return :
  23. TRUE and RPC_S_OK if we we're able to determine the codepage, FALSE
  24. and a Win32 derived error code if not.
  25. --*/
  26. {
  27. CPINFOEX info;
  28. if ( ! GetCPInfoEx( CP_THREAD_ACP, 0, &info ) )
  29. {
  30. *pStatus = HRESULT_FROM_WIN32( GetLastError() );
  31. return FALSE;
  32. }
  33. *pStatus = RPC_S_OK;
  34. *cp = info.CodePage;
  35. return TRUE;
  36. }
  37. ulong TranslateCodeset(
  38. ulong Codeset)
  39. /*++
  40. Routine Description :
  41. Translate the given generic codeset value (CP_ACP, CP_OEMCP, or
  42. CP_THREAD_ACP) to it's true value.
  43. Arguments :
  44. Codeset -- The value to translate
  45. Return :
  46. The true value.
  47. --*/
  48. {
  49. CPINFOEX info;
  50. if ( ! GetCPInfoEx( Codeset, 0, &info ) )
  51. RpcRaiseException( HRESULT_FROM_WIN32( GetLastError () ) );
  52. return info.CodePage;
  53. }
  54. ulong
  55. NdrpGetSetCSTagMarshall(
  56. PMIDL_STUB_MESSAGE pStubMsg,
  57. uchar * pMemory,
  58. NDR_CS_TAG_FORMAT * pTagFormat)
  59. /*++
  60. Routine Description :
  61. Extract the codeset referred to by pTagFormat and save it in the stub
  62. message for later buffer sizing / marshalling.
  63. Arguments :
  64. pStubMsg -- The stub message
  65. pMemory -- (possibly) The pointer to the tag value
  66. pTagFormat -- Pointer to FC_CS_TAG in the format string
  67. Return :
  68. The codeset
  69. --*/
  70. {
  71. ulong Codeset;
  72. InitializeStubCSInfo( pStubMsg );
  73. //
  74. // If there is no tag getting routine then the value of the tag is on
  75. // the stack like a normal parameter. If there is a tag routine, then
  76. // the parameter is NOT on the stack (pMemory is invalid) and we need
  77. // to call the tag routine to get the value.
  78. //
  79. if ( NDR_INVALID_TAG_ROUTINE_INDEX == pTagFormat->TagRoutineIndex )
  80. {
  81. Codeset = * (ulong *) pMemory;
  82. }
  83. else
  84. {
  85. CS_TAG_GETTING_ROUTINE *TagRoutines;
  86. CS_TAG_GETTING_ROUTINE GetTagRoutine;
  87. ulong SendingCodeset;
  88. ulong DesiredReceivingCodeset;
  89. ulong ReceivingCodeset;
  90. error_status_t status;
  91. if ( ! pStubMsg->IsClient )
  92. DesiredReceivingCodeset =
  93. pStubMsg->pCSInfo->DesiredReceivingCodeset;
  94. TagRoutines = pStubMsg->StubDesc->CsRoutineTables->pTagGettingRoutines;
  95. GetTagRoutine = TagRoutines[ pTagFormat->TagRoutineIndex ];
  96. GetTagRoutine(
  97. pStubMsg->RpcMsg->Handle,
  98. ! pStubMsg->IsClient,
  99. &SendingCodeset,
  100. &DesiredReceivingCodeset,
  101. &ReceivingCodeset,
  102. &status );
  103. if ( RPC_S_OK != status )
  104. RpcRaiseException( status );
  105. if ( pTagFormat->Flags.STag )
  106. Codeset = SendingCodeset;
  107. else if ( pTagFormat->Flags.DRTag )
  108. Codeset = DesiredReceivingCodeset;
  109. else
  110. Codeset = ReceivingCodeset;
  111. }
  112. //
  113. // Don't allow generic psuedo codesets on the wire. Translate them to
  114. // thier real values
  115. //
  116. // REVIEW: The is true for the standard sizing/translation routines but
  117. // for user specified ones they should ideally be able to do
  118. // anything they want.
  119. //
  120. if ( CP_ACP == Codeset || CP_OEMCP == Codeset || CP_THREAD_ACP == Codeset )
  121. Codeset = TranslateCodeset( Codeset );
  122. //
  123. // Save the values away in the stub message for array size/marshal/etc.
  124. //
  125. if ( pTagFormat->Flags.STag )
  126. pStubMsg->pCSInfo->WireCodeset = Codeset;
  127. if (pTagFormat->Flags.DRTag )
  128. pStubMsg->pCSInfo->DesiredReceivingCodeset = Codeset;
  129. return Codeset;
  130. }
  131. ulong
  132. NdrpGetSetCSTagUnmarshall(
  133. PMIDL_STUB_MESSAGE pStubMsg,
  134. NDR_CS_TAG_FORMAT * pTagFormat)
  135. /*++
  136. Routine Description :
  137. Extract the codeset in the buffer and save it in the stub
  138. message for later memory sizing / unmarshalling.
  139. Arguments :
  140. pStubMsg -- The stub message
  141. pTagFormat -- Pointer to FC_CS_TAG in the format string
  142. Return :
  143. The codeset
  144. --*/
  145. {
  146. ulong Codeset;
  147. InitializeStubCSInfo( pStubMsg );
  148. Codeset = * (ulong *) pStubMsg->Buffer;
  149. if ( pTagFormat->Flags.STag && ! pStubMsg->IsClient )
  150. pStubMsg->pCSInfo->WireCodeset = Codeset;
  151. if ( pTagFormat->Flags.DRTag )
  152. pStubMsg->pCSInfo->DesiredReceivingCodeset = Codeset;
  153. if ( pTagFormat->Flags.RTag && pStubMsg->IsClient )
  154. pStubMsg->pCSInfo->WireCodeset = Codeset;
  155. return Codeset;
  156. }
  157. void GenericBufferSize(
  158. unsigned long DestCodeSet,
  159. unsigned long SourceCodeSet,
  160. unsigned long SourceBufferSize,
  161. IDL_CS_CONVERT * ConversionType,
  162. unsigned long * DestBufferSize,
  163. error_status_t * status)
  164. /*++
  165. Routine Description :
  166. Estimate the length of the buffer needed to hold [SourceBufferSize]
  167. characters if they we're translated into [DestCodeSet].
  168. Arguments :
  169. DestCodeSet - The codeset that the data will be translated to
  170. SourceCodeSet - The source codeset
  171. SourceBufferSize - The number of characters in the source codeset
  172. ConversionType - Returns whether or not conversion is needed
  173. DestBufferSize - Where to put the estimated buffer size
  174. status - The return status
  175. --*/
  176. {
  177. int DestMaxCharSize;
  178. *status = NO_ERROR;
  179. // Determine the maximum size of a character on the wire in bytes
  180. if ( CP_UNICODE == DestCodeSet )
  181. {
  182. DestMaxCharSize = 2;
  183. }
  184. else
  185. {
  186. CPINFO cpinfo;
  187. if ( ! GetCPInfo( DestCodeSet, &cpinfo ) )
  188. {
  189. *status = HRESULT_FROM_WIN32( GetLastError() );
  190. return;
  191. }
  192. DestMaxCharSize = cpinfo.MaxCharSize;
  193. }
  194. // Worst case: each char in the local buffer expands to the maximum number
  195. // of bytes for a char in the network codeset
  196. if ( NULL != DestBufferSize )
  197. *DestBufferSize = SourceBufferSize * DestMaxCharSize;
  198. if ( SourceCodeSet == DestCodeSet )
  199. *ConversionType = IDL_CS_NO_CONVERT;
  200. else
  201. *ConversionType = IDL_CS_NEW_BUFFER_CONVERT;
  202. }
  203. void RPC_ENTRY
  204. cs_byte_net_size(
  205. RPC_BINDING_HANDLE hBinding,
  206. unsigned long NetworkCodeSet,
  207. unsigned long LocalBufferSize,
  208. IDL_CS_CONVERT * ConversionType,
  209. unsigned long * NetworkBufferSize,
  210. error_status_t * status)
  211. /*++
  212. Routine Description :
  213. Estimate the length of the buffer needed to hold [LocalBufferSize]
  214. characters if they are translated from the current thread codeset
  215. into [NetworkCodeSet].
  216. Arguments :
  217. hBinding - The RPC binding handle
  218. NetworkCodeSet - The codeset that the data will be translated to
  219. LocalBufferSize - The number of bytes in the data
  220. ConversionType - Returns whether the conversion can be done inplace
  221. NetworkBufferSize - Where to put the estimated buffer size
  222. status - The return status
  223. --*/
  224. {
  225. ulong LocalCP;
  226. if ( ! GetThreadACP( &LocalCP, status ) )
  227. return;
  228. // No conversion is necessary if the local and destination codesets are
  229. // the same.
  230. GenericBufferSize(
  231. NetworkCodeSet,
  232. LocalCP,
  233. LocalBufferSize,
  234. ConversionType,
  235. NetworkBufferSize,
  236. status);
  237. }
  238. void RPC_ENTRY
  239. wchar_t_net_size(
  240. RPC_BINDING_HANDLE hBinding,
  241. unsigned long NetworkCodeSet,
  242. unsigned long LocalBufferSize,
  243. IDL_CS_CONVERT * ConversionType,
  244. unsigned long * NetworkBufferSize,
  245. error_status_t * status)
  246. /*++
  247. Routine Description :
  248. Estimate the length of the buffer needed to hold [LocalBufferSize]
  249. characters if they are translated from the current thread codeset
  250. into [NetworkCodeSet].
  251. Arguments :
  252. hBinding - The RPC binding handle
  253. NetworkCodeSet - The codeset that the data will be translated to
  254. LocalBufferSize - The number of bytes in the data
  255. ConversionType - Returns whether the conversion can be done inplace
  256. NetworkBufferSize - Where to put the estimated buffer size
  257. status - The return status
  258. --*/
  259. {
  260. ulong LocalCP = CP_UNICODE;
  261. GenericBufferSize(
  262. NetworkCodeSet,
  263. LocalCP,
  264. LocalBufferSize,
  265. ConversionType,
  266. NetworkBufferSize,
  267. status);
  268. }
  269. void RPC_ENTRY
  270. cs_byte_local_size(
  271. RPC_BINDING_HANDLE hBinding,
  272. unsigned long NetworkCodeSet,
  273. unsigned long NetworkBufferSize,
  274. IDL_CS_CONVERT * ConversionType,
  275. unsigned long * LocalBufferSize,
  276. error_status_t * status)
  277. /*++
  278. Routine Description :
  279. Estimate the length of the buffer needed to hold [NetworkBufferSize]
  280. characters if they are translated from [NetworkCodeSet] to the local
  281. thread codeset.
  282. Arguments :
  283. hBinding - The RPC binding handle
  284. NetworkCodeSet - The codeset that the data will be translated to
  285. NetworkBufferSize - The number of bytes in the data
  286. ConversionType - Returns whether the conversion can be done inplace
  287. LocalBufferSize - Where to put the estimated buffer size
  288. status - The return status
  289. --*/
  290. {
  291. ulong LocalCP;
  292. if ( ! GetThreadACP(&LocalCP, status) )
  293. return;
  294. // In Unicode the minimum character size is 2 so we can save a bit of
  295. // memory cutting the apparent source buffer size
  296. if ( CP_UNICODE == NetworkCodeSet )
  297. NetworkBufferSize /= 2;
  298. GenericBufferSize(
  299. LocalCP,
  300. NetworkCodeSet,
  301. NetworkBufferSize,
  302. ConversionType,
  303. LocalBufferSize,
  304. status);
  305. }
  306. void RPC_ENTRY
  307. wchar_t_local_size(
  308. RPC_BINDING_HANDLE hBinding,
  309. unsigned long NetworkCodeSet,
  310. unsigned long NetworkBufferSize,
  311. IDL_CS_CONVERT * ConversionType,
  312. unsigned long * LocalBufferSize,
  313. error_status_t * status)
  314. /*++
  315. Routine Description :
  316. Estimate the length of the buffer needed to hold [NetworkBufferSize]
  317. characters if they are translated from [NetworkCodeSet] to the local
  318. thread codeset.
  319. Arguments :
  320. hBinding - The RPC binding handle
  321. NetworkCodeSet - The codeset that the data will be translated to
  322. NetworkBufferSize - The number of bytes in the data
  323. ConversionType - Returns whether the conversion can be done inplace
  324. LocalBufferSize - Where to put the estimated buffer size
  325. status - The return status
  326. --*/
  327. {
  328. ulong LocalCP = CP_UNICODE;
  329. // In Unicode the minimum character size is 2 so we can save a bit of
  330. // memory cutting the apparent source buffer size
  331. if ( CP_UNICODE == NetworkCodeSet )
  332. NetworkBufferSize /= 2;
  333. // No conversion is necessary if the local and destination codesets are
  334. // the same.
  335. GenericBufferSize(
  336. LocalCP,
  337. NetworkCodeSet,
  338. NetworkBufferSize,
  339. ConversionType,
  340. LocalBufferSize,
  341. status);
  342. }
  343. void GenericCSConvert(
  344. unsigned long DestCodeSet,
  345. void *DestData,
  346. unsigned long DestBufferSize,
  347. unsigned long SourceCodeSet,
  348. void *SourceData,
  349. unsigned long SourceBufferSize,
  350. unsigned long *BytesWritten,
  351. error_status_t *status)
  352. /*++
  353. Routine Description :
  354. Convert data from one character encoding to another.
  355. Arguments :
  356. DestCodeSet - The target encoding
  357. DestData - The target buffer
  358. DestBufferSize - The size of the target buffer in bytes
  359. SourceCodeset - The source encoding
  360. SourceData - The source data
  361. SourceBufferSize - The size of the source data in bytes
  362. BytesWritten - The number of bytes written to the target buffer
  363. status - The return status
  364. --*/
  365. {
  366. wchar_t *TempBuffer = NULL;
  367. ulong BytesWrittenBuffer;
  368. *status = RPC_S_OK;
  369. // BytesWritten can be NULL in various circumstances. Make the following
  370. // code a bit more generic by making sure it always points at something.
  371. if ( NULL == BytesWritten )
  372. BytesWritten = &BytesWrittenBuffer;
  373. // If the source and destination code sets are the same, just memcpy.
  374. // If there are 0 bytes in the source we don't need to do anything.
  375. if ( DestCodeSet == SourceCodeSet || 0 == SourceBufferSize)
  376. {
  377. if ( DestBufferSize < SourceBufferSize )
  378. {
  379. *status = RPC_S_BUFFER_TOO_SMALL;
  380. return;
  381. }
  382. CopyMemory( DestData, SourceData, SourceBufferSize );
  383. *BytesWritten = SourceBufferSize;
  384. return;
  385. }
  386. // We can't convert from a non-Unicode codeset to a different non-Unicode
  387. // codeset in one go, we have to convert to Unicode first. So regardless
  388. // of what the destionation is supposed to be make the source Unicode.
  389. if ( CP_UNICODE != SourceCodeSet )
  390. {
  391. ulong TempBufferSize;
  392. if ( CP_UNICODE != DestCodeSet )
  393. {
  394. TempBufferSize = SourceBufferSize * 2;
  395. TempBuffer = (wchar_t *) I_RpcAllocate( TempBufferSize );
  396. if ( NULL == TempBuffer )
  397. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  398. }
  399. else
  400. {
  401. TempBufferSize = DestBufferSize;
  402. TempBuffer = (wchar_t *) DestData;
  403. }
  404. *BytesWritten = MultiByteToWideChar(
  405. SourceCodeSet,
  406. 0,
  407. (char *) SourceData,
  408. SourceBufferSize,
  409. TempBuffer,
  410. TempBufferSize / 2 );
  411. if ( 0 == *BytesWritten )
  412. *status = GetLastError();
  413. *BytesWritten *= 2;
  414. SourceData = TempBuffer;
  415. SourceBufferSize = *BytesWritten;
  416. }
  417. // Convert to the destination codeset if it's not Unicode.
  418. if ( RPC_S_OK == *status && CP_UNICODE != DestCodeSet )
  419. {
  420. *BytesWritten = WideCharToMultiByte(
  421. DestCodeSet,
  422. 0,
  423. (wchar_t *) SourceData,
  424. SourceBufferSize / 2,
  425. (char *) DestData,
  426. DestBufferSize,
  427. NULL,
  428. NULL);
  429. if ( 0 == *BytesWritten )
  430. *status = HRESULT_FROM_WIN32( GetLastError() );
  431. }
  432. if ( TempBuffer != DestData )
  433. I_RpcFree( TempBuffer );
  434. }
  435. void RPC_ENTRY
  436. cs_byte_to_netcs(
  437. RPC_BINDING_HANDLE hBinding,
  438. unsigned long NetworkCodeSet,
  439. cs_byte * LocalData,
  440. unsigned long LocalDataLength,
  441. byte * NetworkData,
  442. unsigned long * NetworkDataLength,
  443. error_status_t * status)
  444. /*++
  445. Routine Description :
  446. Convert data from the current thread codeset to the network codeset
  447. Arguments :
  448. hBinding - The RPC binding handle
  449. NetworkCodeSet - The target codeset
  450. LocalData - The source data
  451. LocalDataLength - The size of the source data in bytes
  452. NetworkData - The target buffer
  453. NetworkDataLength - The number of bytes written to the target buffer
  454. status - The return status
  455. --*/
  456. {
  457. unsigned long LocalCP;
  458. if ( ! GetThreadACP( &LocalCP, status ) )
  459. return;
  460. //
  461. // For reasons known only to the gods, DCE didn't think it important to
  462. // include the size of the destination buffer as a parameter. It
  463. // *shouldn't* be an issue because in theory XXX_net_size was called to
  464. // properly size the buffer. Just to be inconsistent, they did include
  465. // it in XXX_from_netcs.
  466. //
  467. GenericCSConvert(
  468. NetworkCodeSet,
  469. NetworkData,
  470. INT_MAX,
  471. LocalCP,
  472. LocalData,
  473. LocalDataLength,
  474. NetworkDataLength,
  475. status);
  476. }
  477. void RPC_ENTRY
  478. wchar_t_to_netcs(
  479. RPC_BINDING_HANDLE hBinding,
  480. unsigned long NetworkCodeSet,
  481. wchar_t * LocalData,
  482. unsigned long LocalDataLength,
  483. byte * NetworkData,
  484. unsigned long * NetworkDataLength,
  485. error_status_t * status)
  486. /*++
  487. Routine Description :
  488. Convert data from Unicode to the network codeset
  489. Arguments :
  490. hBinding - The RPC binding handle
  491. NetworkCodeSet - The target codeset
  492. LocalData - The source data
  493. LocalDataLength - The size of the source data in bytes
  494. NetworkData - The target buffer
  495. NetworkDataLength - The number of bytes written to the target buffer
  496. status - The return status
  497. --*/
  498. {
  499. unsigned long LocalCP = CP_UNICODE;
  500. //
  501. // For reasons known only to the gods, DCE didn't think it important to
  502. // include the size of the destination buffer as a parameter. It
  503. // *shouldn't* be an issue because in theory XXX_net_size was called to
  504. // properly size the buffer. Just to be inconsistent, they did include
  505. // it in XXX_from_netcs.
  506. //
  507. GenericCSConvert(
  508. NetworkCodeSet,
  509. NetworkData,
  510. INT_MAX,
  511. LocalCP,
  512. LocalData,
  513. LocalDataLength * 2, // We want bytes not chars
  514. NetworkDataLength,
  515. status);
  516. }
  517. void RPC_ENTRY
  518. cs_byte_from_netcs(
  519. RPC_BINDING_HANDLE hBinding,
  520. unsigned long NetworkCodeSet,
  521. cs_byte * NetworkData,
  522. unsigned long NetworkDataLength,
  523. unsigned long LocalDataBufferSize,
  524. byte * LocalData,
  525. unsigned long * LocalDataLength,
  526. error_status_t * status)
  527. /*++
  528. Routine Description :
  529. Convert data from the network codeset to the current thread codeset
  530. Arguments :
  531. hBinding - The RPC binding handle
  532. NetworkCodeSet - The source codeset
  533. NetworkData - The source data
  534. NetworkDataLength - The size of the source data in bytes
  535. LocalDataBufferSize - the size of the target buffer in bytes
  536. LocalData - The target buffer
  537. LocalDataLength - The number written to the target buffer
  538. status - The return status
  539. --*/
  540. {
  541. unsigned long LocalCP;
  542. if ( ! GetThreadACP( &LocalCP, status ) )
  543. return;
  544. GenericCSConvert(
  545. LocalCP,
  546. LocalData,
  547. LocalDataBufferSize,
  548. NetworkCodeSet,
  549. NetworkData,
  550. NetworkDataLength,
  551. LocalDataLength,
  552. status);
  553. }
  554. void RPC_ENTRY
  555. wchar_t_from_netcs(
  556. RPC_BINDING_HANDLE hBinding,
  557. unsigned long NetworkCodeSet,
  558. wchar_t * NetworkData,
  559. unsigned long NetworkDataLength,
  560. unsigned long LocalDataBufferSize,
  561. byte * LocalData,
  562. unsigned long * LocalDataLength,
  563. error_status_t * status)
  564. /*++
  565. Routine Description :
  566. Convert data from the network codeset to the current thread codeset
  567. Arguments :
  568. hBinding - The RPC binding handle
  569. NetworkCodeSet - The source codeset
  570. NetworkData - The source data
  571. NetworkDataLength - The size of the source data in bytes
  572. LocalDataBufferSize - the size of the target buffer in bytes
  573. LocalData - The target buffer
  574. LocalDataLength - The number written to the target buffer
  575. status - The return status
  576. --*/
  577. {
  578. unsigned long LocalCP = CP_UNICODE;
  579. GenericCSConvert(
  580. LocalCP,
  581. LocalData,
  582. LocalDataBufferSize * 2, // Bytes not chars
  583. NetworkCodeSet,
  584. NetworkData,
  585. NetworkDataLength,
  586. LocalDataLength,
  587. status);
  588. if ( LocalDataLength )
  589. *LocalDataLength /= 2; // Chars not bytes
  590. }
  591. void RPC_ENTRY
  592. RpcCsGetTags(
  593. handle_t hBinding,
  594. int ServerSide,
  595. unsigned long * SendingTag,
  596. unsigned long * DesiredReceivingTag,
  597. unsigned long * ReceivingTag,
  598. error_status_t * status)
  599. /*++
  600. Routine Description :
  601. Determine the codesets to use
  602. Arguments :
  603. hBinding - The RPC binding handle
  604. ServerSide - FALSE if this is the client
  605. SendingTag - Pointer to the returned sending tag
  606. DesiredReceivingTag - Pointer to the returned desired receiving tag
  607. ReceivingTag - Pointer to the returned receiving tag
  608. status - The return status
  609. Notes :
  610. On the server side, DesiredReceivingTag is an input instead of an output.
  611. The ReceivingTag will be set to this value.
  612. --*/
  613. {
  614. ulong Codeset;
  615. if ( ! GetThreadACP( &Codeset, status ) )
  616. return;
  617. if ( SendingTag )
  618. * SendingTag = Codeset;
  619. if ( DesiredReceivingTag && ! ServerSide )
  620. * DesiredReceivingTag = Codeset;
  621. if ( ReceivingTag )
  622. {
  623. if ( ServerSide && DesiredReceivingTag )
  624. * ReceivingTag = * DesiredReceivingTag;
  625. else
  626. * ReceivingTag = Codeset;
  627. }
  628. * status = RPC_S_OK;
  629. }