Leaked source code of windows server 2003
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.

765 lines
20 KiB

  1. /*++
  2. Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. geo.c
  5. Abstract:
  6. This file contains the system APIs that provide geographical information.
  7. Private APIs found in this file:
  8. GetIS0639
  9. GetGeoLCID
  10. External Routines found in this file:
  11. GetGeoInfoW
  12. GetUserGeoID
  13. SetUserGeoID
  14. EnumSystemGeoID
  15. Revision History:
  16. 11-20-99 WeiWu Created
  17. 03-07-00 lguindon Began Geo API port
  18. --*/
  19. //
  20. // Include Files.
  21. //
  22. #include "nls.h"
  23. #include "nlssafe.h"
  24. //
  25. // Global Variables.
  26. //
  27. PGEOTABLEHDR gpGeoTableHdr = NULL;
  28. PGEOINFO gpGeoInfo = NULL;
  29. PGEOLCID gpGeoLCID = NULL;
  30. ////////////////////////////////////////////////////////////////////////////
  31. //
  32. // GetGeoLCID
  33. //
  34. // Returns the Locale ID associated with the Language Identifier and
  35. // Geographical Identifier. This routine scans the mapping table for the
  36. // corresponding combination. If nothing is found, the function returns
  37. // 0 as the Locale Identifier.
  38. //
  39. ////////////////////////////////////////////////////////////////////////////
  40. LCID GetGeoLCID(
  41. GEOID GeoId,
  42. LANGID LangId)
  43. {
  44. int ctr1, ctr2;
  45. if (pTblPtrs->pGeoInfo == NULL)
  46. {
  47. if (GetGeoFileInfo())
  48. {
  49. return (0);
  50. }
  51. }
  52. //
  53. // Search for GEOID.
  54. //
  55. // Note: We can have more then one Language ID for one GEOID.
  56. //
  57. for (ctr1 = 0; ctr1 < pTblPtrs->nGeoLCID; ctr1++)
  58. {
  59. if (GeoId == pTblPtrs->pGeoLCID[ctr1].GeoId)
  60. {
  61. //
  62. // Search for Language ID
  63. //
  64. for (ctr2 = ctr1;
  65. ctr2 < pTblPtrs->nGeoLCID && pTblPtrs->pGeoLCID[ctr2].GeoId == GeoId;
  66. ctr2++)
  67. {
  68. if (pTblPtrs->pGeoLCID[ctr2].LangId == LangId)
  69. {
  70. return (pTblPtrs->pGeoLCID[ctr2].lcid);
  71. }
  72. }
  73. break;
  74. }
  75. }
  76. //
  77. // Nothing found, return zero
  78. //
  79. return ((LCID)0);
  80. }
  81. //-------------------------------------------------------------------------//
  82. // EXTERNAL API ROUTINES //
  83. //-------------------------------------------------------------------------//
  84. ////////////////////////////////////////////////////////////////////////////
  85. //
  86. // GetGeoInfoW
  87. //
  88. // Retrieves information about a geographical location on earth. The
  89. // required size is the number of characters. If cchData is zero, the
  90. // function returns the number of characters needed to copy to caller's
  91. // buffer. Otherwise, the function returns the number of characters copied
  92. // to caller's buffer if caller provided proper lpGeoData and cchData.
  93. // The function returns zero in the case of failure.
  94. //
  95. ////////////////////////////////////////////////////////////////////////////
  96. int WINAPI GetGeoInfoW(
  97. GEOID GeoId,
  98. DWORD GeoType,
  99. LPWSTR lpGeoData,
  100. int cchData,
  101. LANGID LangId)
  102. {
  103. int ctr1, ctr2, ctr3;
  104. int Length = 0;
  105. LPWSTR pString = NULL;
  106. WCHAR pTemp[MAX_REG_VAL_SIZE] = {0};
  107. LCID Locale;
  108. LANGID DefaultLangId;
  109. PLOC_HASH pHashN;
  110. //
  111. // Invalid Parameter Check:
  112. // - count is negative
  113. // - NULL data pointer AND count is not zero
  114. // - invalid lang id
  115. //
  116. // NOTE: Invalid geo id is checked in the binary search below.
  117. // Invalid type is checked in the switch statement below.
  118. //
  119. Locale = MAKELCID(LangId, SORT_DEFAULT);
  120. VALIDATE_LOCALE(Locale, pHashN, FALSE);
  121. if ((cchData < 0) ||
  122. ((lpGeoData == NULL) && (cchData > 0)) ||
  123. (pHashN == NULL))
  124. {
  125. SetLastError(ERROR_INVALID_PARAMETER);
  126. return (0);
  127. }
  128. //
  129. // Check if the section is mapped into memory.
  130. //
  131. if (pTblPtrs->pGeoInfo == NULL)
  132. {
  133. if (GetGeoFileInfo())
  134. {
  135. return (0);
  136. }
  137. }
  138. //
  139. // Check if we are dealing with an invalid geoid.
  140. //
  141. if (GeoId == GEOID_NOT_AVAILABLE)
  142. {
  143. return (0);
  144. }
  145. //
  146. // Initialize variables for the binary search.
  147. //
  148. ctr1 = 0;
  149. ctr2 = pTblPtrs->nGeoInfo - 1;
  150. ctr3 = ctr2 >> 1;
  151. //
  152. // Binary search GEO data.
  153. //
  154. while (ctr1 <= ctr2)
  155. {
  156. if (GeoId == pTblPtrs->pGeoInfo[ctr3].GeoId)
  157. {
  158. //
  159. // Jump out of the loop.
  160. //
  161. break;
  162. }
  163. else
  164. {
  165. if (GeoId < pTblPtrs->pGeoInfo[ctr3].GeoId)
  166. {
  167. ctr2 = ctr3 - 1;
  168. }
  169. else
  170. {
  171. ctr1 = ctr3 + 1;
  172. }
  173. ctr3 = (ctr1 + ctr2) >> 1;
  174. }
  175. }
  176. //
  177. // See if we have found the requested element.
  178. //
  179. if (ctr1 > ctr2)
  180. {
  181. //
  182. // Could not find the Geo ID.
  183. //
  184. SetLastError(ERROR_INVALID_PARAMETER);
  185. return (0);
  186. }
  187. //
  188. // Get the appropriate information based on the requested GeoType.
  189. //
  190. switch (GeoType)
  191. {
  192. case ( GEO_NATION ) :
  193. {
  194. if (pTblPtrs->pGeoInfo[ctr3].GeoClass == GEOCLASS_NATION)
  195. {
  196. NlsConvertIntegerToString(
  197. (UINT)(pTblPtrs->pGeoInfo[ctr3].GeoId),
  198. 10,
  199. 0,
  200. pTemp,
  201. MAX_REG_VAL_SIZE );
  202. pString = pTemp;
  203. }
  204. break;
  205. }
  206. case ( GEO_LATITUDE ) :
  207. {
  208. pString = pTblPtrs->pGeoInfo[ctr3].szLatitude;
  209. break;
  210. }
  211. case ( GEO_LONGITUDE ) :
  212. {
  213. pString = pTblPtrs->pGeoInfo[ctr3].szLongitude;
  214. break;
  215. }
  216. case ( GEO_ISO2 ) :
  217. {
  218. pString = pTblPtrs->pGeoInfo[ctr3].szISO3166Abbrev2;
  219. break;
  220. }
  221. case ( GEO_ISO3 ) :
  222. {
  223. pString = pTblPtrs->pGeoInfo[ctr3].szISO3166Abbrev3;
  224. break;
  225. }
  226. case ( GEO_RFC1766 ) :
  227. {
  228. //
  229. // Check if it's a valid LANGID. If not, get the default.
  230. //
  231. if (LangId == 0)
  232. {
  233. LangId = GetUserDefaultLangID();
  234. }
  235. //
  236. // Make the corresponding LCID.
  237. //
  238. Locale = MAKELCID(LangId, SORT_DEFAULT);
  239. //
  240. // Get IS0639 value associated with the LANGID.
  241. //
  242. if (!GetLocaleInfoW( Locale,
  243. LOCALE_SISO639LANGNAME,
  244. pTemp,
  245. MAX_REG_VAL_SIZE ))
  246. {
  247. //
  248. // Try the Primary Language Identifier.
  249. //
  250. DefaultLangId = MAKELANGID(PRIMARYLANGID(LangId), SUBLANG_DEFAULT);
  251. if (DefaultLangId != LangId)
  252. {
  253. Locale = MAKELCID(DefaultLangId, SORT_DEFAULT);
  254. GetLocaleInfoW( Locale,
  255. LOCALE_SISO639LANGNAME,
  256. pTemp,
  257. MAX_REG_VAL_SIZE );
  258. }
  259. }
  260. if (pTemp[0] != 0)
  261. {
  262. //
  263. // Construct the name to fit the form xx-yy where
  264. // xx is ISO639_1 name associated with the LANGID
  265. // and yy is the ISO3166 name 2 char abreviation.
  266. //
  267. if( FAILED(StringCchCatW(pTemp, ARRAYSIZE(pTemp), L"-")) ||
  268. FAILED(StringCchCatW(pTemp, ARRAYSIZE(pTemp), pTblPtrs->pGeoInfo[ctr3].szISO3166Abbrev2)))
  269. {
  270. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  271. return(0);
  272. }
  273. _wcslwr(pTemp);
  274. pString = pTemp;
  275. }
  276. break;
  277. }
  278. case ( GEO_LCID ) :
  279. {
  280. //
  281. // Check if the we have a valid LANGID. If not, retrieve
  282. // the default one.
  283. //
  284. if (LangId == 0)
  285. {
  286. LangId = GetUserDefaultLangID();
  287. }
  288. //
  289. // Try to get a valid LCID from the GEOID and the LANGID.
  290. //
  291. if ((Locale = GetGeoLCID(GeoId, LangId)) == 0)
  292. {
  293. //
  294. // Try the Primary Language Identifier.
  295. //
  296. DefaultLangId = MAKELANGID(PRIMARYLANGID(LangId), SUBLANG_DEFAULT);
  297. if (DefaultLangId != LangId)
  298. {
  299. Locale = GetGeoLCID(GeoId, DefaultLangId);
  300. }
  301. //
  302. // Check if the Locale returned is valid.
  303. //
  304. if (Locale == 0)
  305. {
  306. //
  307. // Nothing found, make something with the LangId.
  308. // If Language ID already contains a sub-language,
  309. // we'll use it directly.
  310. //
  311. if (SUBLANGID(LangId) != 0)
  312. {
  313. Locale = MAKELCID(LangId, SORT_DEFAULT);
  314. }
  315. else
  316. {
  317. Locale = MAKELCID(MAKELANGID(LangId, SUBLANG_DEFAULT), SORT_DEFAULT);
  318. }
  319. }
  320. }
  321. //
  322. // Convert the value found into a string.
  323. //
  324. if (Locale != 0)
  325. {
  326. NlsConvertIntegerToString( Locale,
  327. 16,
  328. 8,
  329. pTemp,
  330. MAX_REG_VAL_SIZE );
  331. pString = pTemp;
  332. }
  333. break;
  334. }
  335. case ( GEO_FRIENDLYNAME ) :
  336. {
  337. Length = GetStringTableEntry( GeoId,
  338. LangId,
  339. pTemp,
  340. MAX_REG_VAL_SIZE,
  341. RC_GEO_FRIENDLY_NAME );
  342. if (Length == 0)
  343. {
  344. SetLastError(ERROR_INVALID_PARAMETER);
  345. return (0);
  346. }
  347. pString = pTemp;
  348. break;
  349. }
  350. case ( GEO_OFFICIALNAME ) :
  351. {
  352. Length = GetStringTableEntry( GeoId,
  353. LangId,
  354. pTemp,
  355. MAX_REG_VAL_SIZE,
  356. RC_GEO_OFFICIAL_NAME );
  357. if (Length == 0)
  358. {
  359. //
  360. // If the official name is not there, fall back on
  361. // the friendly name.
  362. //
  363. Length = GetStringTableEntry( GeoId,
  364. LangId,
  365. pTemp,
  366. MAX_REG_VAL_SIZE,
  367. RC_GEO_FRIENDLY_NAME );
  368. if (Length == 0)
  369. {
  370. SetLastError(ERROR_INVALID_PARAMETER);
  371. return (0);
  372. }
  373. }
  374. pString = pTemp;
  375. break;
  376. }
  377. case ( GEO_TIMEZONES ) :
  378. {
  379. // Not implemented
  380. break;
  381. }
  382. case ( GEO_OFFICIALLANGUAGES ) :
  383. {
  384. // Not implemented
  385. break;
  386. }
  387. default :
  388. {
  389. SetLastError(ERROR_INVALID_FLAGS);
  390. break;
  391. }
  392. }
  393. //
  394. // Make sure the pointer is valid. If not, return failure.
  395. //
  396. if (pString == NULL)
  397. {
  398. return (0);
  399. }
  400. //
  401. // Get the length (in characters) of the string to copy.
  402. //
  403. if (Length == 0)
  404. {
  405. Length = NlsStrLenW(pString);
  406. }
  407. //
  408. // Add one for null termination. All strings should be null
  409. // terminated.
  410. //
  411. Length++;
  412. //
  413. // Check cchData for size of given buffer.
  414. //
  415. if (cchData == 0)
  416. {
  417. //
  418. // If cchData is 0, then we can't use lpGeoData. In this
  419. // case, we simply want to return the length (in characters) of
  420. // the string to be copied.
  421. //
  422. return (Length);
  423. }
  424. else if (cchData < Length)
  425. {
  426. //
  427. // The buffer is too small for the string, so return an error
  428. // and zero bytes written.
  429. //
  430. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  431. return (0);
  432. }
  433. //
  434. // Copy the string to lpGeoData and null terminate it.
  435. // Return the number of characters copied.
  436. //
  437. wcsncpy(lpGeoData, pString, Length - 1);
  438. lpGeoData[Length - 1] = 0;
  439. return (Length);
  440. }
  441. ////////////////////////////////////////////////////////////////////////////
  442. //
  443. // EnumSystemGeoID
  444. //
  445. // Enumerates the GEOIDs that are available on the system. This function
  446. // returns TRUE if it succeeds, FALSE if it fails.
  447. //
  448. ////////////////////////////////////////////////////////////////////////////
  449. BOOL WINAPI EnumSystemGeoID(
  450. GEOCLASS GeoClass,
  451. GEOID ParentGeoId,
  452. GEO_ENUMPROC lpGeoEnumProc)
  453. {
  454. int ctr1;
  455. if ((lpGeoEnumProc == NULL) ||
  456. (0 != ParentGeoId) )
  457. {
  458. SetLastError(ERROR_INVALID_PARAMETER);
  459. return (FALSE);
  460. }
  461. if (GeoClass != GEOCLASS_NATION)
  462. {
  463. SetLastError(ERROR_INVALID_FLAGS);
  464. return (FALSE);
  465. }
  466. if (pTblPtrs->pGeoInfo == NULL)
  467. {
  468. if (GetGeoFileInfo())
  469. {
  470. return (FALSE);
  471. }
  472. }
  473. for (ctr1 = 0; ctr1 < pTblPtrs->nGeoInfo; ctr1++)
  474. {
  475. if (pTblPtrs->pGeoInfo[ctr1].GeoClass == GeoClass)
  476. {
  477. if (!lpGeoEnumProc(pTblPtrs->pGeoInfo[ctr1].GeoId))
  478. {
  479. return (TRUE);
  480. }
  481. }
  482. }
  483. return (TRUE);
  484. }
  485. ////////////////////////////////////////////////////////////////////////////
  486. //
  487. // GetUserGeoID
  488. //
  489. // Retrieves information about the geographical location of the user.
  490. // This function returns a valid GEOID or the value GEOID_NOT_AVAILABLE.
  491. //
  492. ////////////////////////////////////////////////////////////////////////////
  493. GEOID WINAPI GetUserGeoID(
  494. GEOCLASS GeoClass)
  495. {
  496. PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
  497. BYTE buffer[MAX_KEY_VALUE_FULLINFO]; // buffer
  498. HANDLE hKey = NULL; // handle to geo key
  499. WCHAR wszGeoRegStr[48]; // ptr to class key
  500. GEOID GeoId = GEOID_NOT_AVAILABLE; // GEOID to default
  501. UNICODE_STRING ObUnicodeStr; // registry data value string
  502. switch (GeoClass)
  503. {
  504. case ( GEOCLASS_NATION ) :
  505. {
  506. if(FAILED(StringCchCopyW(wszGeoRegStr, ARRAYSIZE(wszGeoRegStr), GEO_REG_NATION)))
  507. {
  508. //
  509. // Failure should in theory be impossible, but if we ignore the
  510. // return value, PREfast will complain.
  511. //
  512. return(GEOID_NOT_AVAILABLE);
  513. }
  514. break;
  515. }
  516. case ( GEOCLASS_REGION ) :
  517. {
  518. if(FAILED(StringCchCopyW(wszGeoRegStr, ARRAYSIZE(wszGeoRegStr), GEO_REG_REGION)))
  519. {
  520. //
  521. // Failure should in theory be impossible, but if we ignore the
  522. // return value, PREfast will complain.
  523. //
  524. return(GEOID_NOT_AVAILABLE);
  525. }
  526. break;
  527. }
  528. default :
  529. {
  530. return (GeoId);
  531. }
  532. }
  533. //
  534. // Open the Control Panel International registry key.
  535. //
  536. OPEN_GEO_KEY(hKey, GEOID_NOT_AVAILABLE, KEY_READ);
  537. //
  538. // Query the registry value.
  539. //
  540. pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)buffer;
  541. if (QueryRegValue( hKey,
  542. wszGeoRegStr,
  543. &pKeyValueFull,
  544. MAX_KEY_VALUE_FULLINFO,
  545. NULL ) == NO_ERROR)
  546. {
  547. //
  548. // Convert the string to a value.
  549. //
  550. GeoId = _wtol(GET_VALUE_DATA_PTR(pKeyValueFull));
  551. }
  552. //
  553. // Close the registry key.
  554. //
  555. CLOSE_REG_KEY(hKey);
  556. //
  557. // Return the Geo Id.
  558. //
  559. return (GeoId);
  560. }
  561. ////////////////////////////////////////////////////////////////////////////
  562. //
  563. // SetUserGeoID
  564. //
  565. // Sets information about the geographical location of the user. This
  566. // function returns TRUE if it succeeds, FALSE if it fails.
  567. //
  568. ////////////////////////////////////////////////////////////////////////////
  569. BOOL WINAPI SetUserGeoID(
  570. GEOID GeoId)
  571. {
  572. int ctr1, ctr2, ctr3;
  573. WCHAR wszRegStr[MAX_REG_VAL_SIZE];
  574. HANDLE hKey = NULL;
  575. BOOL bRet = FALSE;
  576. WCHAR wszBuffer[MAX_REG_VAL_SIZE] = {0};
  577. if (pTblPtrs->pGeoInfo == NULL)
  578. {
  579. if (GetGeoFileInfo())
  580. {
  581. return (FALSE);
  582. }
  583. }
  584. ctr1 = 0;
  585. ctr2 = pTblPtrs->nGeoInfo - 1;
  586. ctr3 = ctr2 >> 1;
  587. //
  588. // Binary searching the GEOID's GEOCLASS type.
  589. //
  590. while (ctr1 <= ctr2)
  591. {
  592. if (GeoId == pTblPtrs->pGeoInfo[ctr3].GeoId)
  593. {
  594. switch (pTblPtrs->pGeoInfo[ctr3].GeoClass)
  595. {
  596. case ( GEOCLASS_NATION ) :
  597. {
  598. if(FAILED(StringCchCopyW(wszRegStr, ARRAYSIZE(wszRegStr), GEO_REG_NATION)))
  599. {
  600. //
  601. // Failure should in theory be impossible, but if we ignore the
  602. // return value, PREfast will complain.
  603. //
  604. return(FALSE);
  605. }
  606. break;
  607. }
  608. case ( GEOCLASS_REGION ) :
  609. {
  610. if(FAILED(StringCchCopyW(wszRegStr, ARRAYSIZE(wszRegStr), GEO_REG_REGION)))
  611. {
  612. //
  613. // Failure should in theory be impossible, but if we ignore the
  614. // return value, PREfast will complain.
  615. //
  616. return(FALSE);
  617. }
  618. break;
  619. }
  620. default :
  621. {
  622. return (FALSE);
  623. }
  624. }
  625. break;
  626. }
  627. else
  628. {
  629. if (GeoId < pTblPtrs->pGeoInfo[ctr3].GeoId)
  630. {
  631. ctr2 = ctr3 - 1;
  632. }
  633. else
  634. {
  635. ctr1 = ctr3 + 1;
  636. }
  637. ctr3 = (ctr1 + ctr2) >> 1;
  638. }
  639. }
  640. //
  641. // Not a valid GEOID or available GEOID if we can't find it in our
  642. // GEO table.
  643. //
  644. if (ctr1 > ctr2)
  645. {
  646. return (FALSE);
  647. }
  648. //
  649. // If the registry key does not exist, create a new one.
  650. //
  651. if (CreateRegKey( &hKey,
  652. NULL,
  653. GEO_REG_KEY,
  654. KEY_READ | KEY_WRITE ) != NO_ERROR)
  655. {
  656. return (FALSE);
  657. }
  658. //
  659. // Convert to decimal string.
  660. //
  661. NlsConvertIntegerToString((UINT)GeoId, 10, 0, wszBuffer, MAX_REG_VAL_SIZE);
  662. //
  663. // Set the new GEOID value.
  664. //
  665. if (SetRegValue( hKey,
  666. wszRegStr,
  667. wszBuffer,
  668. (NlsStrLenW(wszBuffer) + 1) * sizeof(WCHAR) ) == NO_ERROR)
  669. {
  670. bRet = TRUE;
  671. }
  672. //
  673. // Close the registry key.
  674. //
  675. CLOSE_REG_KEY(hKey);
  676. //
  677. // Return the result.
  678. //
  679. return (bRet);
  680. }