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.

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