/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.c

http://github.com/zpao/v8monkey · C · 654 lines · 441 code · 98 blank · 115 comment · 56 complexity · b3f88f0cfafb433516e1ea1ec78d799c MD5 · raw file

  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is the PKIX-C library.
  15. *
  16. * The Initial Developer of the Original Code is
  17. * Sun Microsystems, Inc.
  18. * Portions created by the Initial Developer are
  19. * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
  20. *
  21. * Contributor(s):
  22. * Sun Microsystems, Inc.
  23. *
  24. * Alternatively, the contents of this file may be used under the terms of
  25. * either the GNU General Public License Version 2 or later (the "GPL"), or
  26. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27. * in which case the provisions of the GPL or the LGPL are applicable instead
  28. * of those above. If you wish to allow use of your version of this file only
  29. * under the terms of either the GPL or the LGPL, and not to allow others to
  30. * use your version of this file under the terms of the MPL, indicate your
  31. * decision by deleting the provisions above and replace them with the notice
  32. * and other provisions required by the GPL or the LGPL. If you do not delete
  33. * the provisions above, a recipient may use your version of this file under
  34. * the terms of any one of the MPL, the GPL or the LGPL.
  35. *
  36. * ***** END LICENSE BLOCK ***** */
  37. /*
  38. * pkix_pl_string.c
  39. *
  40. * String Object Functions
  41. *
  42. */
  43. #include "pkix_pl_string.h"
  44. /* --Private-String-Functions------------------------------------- */
  45. /*
  46. * FUNCTION: pkix_pl_String_Comparator
  47. * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
  48. *
  49. * NOTE:
  50. * This function is a utility function called by pkix_pl_String_Equals().
  51. * It is not officially registered as a comparator.
  52. */
  53. static PKIX_Error *
  54. pkix_pl_String_Comparator(
  55. PKIX_PL_String *firstString,
  56. PKIX_PL_String *secondString,
  57. PKIX_Int32 *pResult,
  58. void *plContext)
  59. {
  60. PKIX_UInt32 i;
  61. PKIX_Int32 result;
  62. unsigned char *p1 = NULL;
  63. unsigned char *p2 = NULL;
  64. PKIX_ENTER(STRING, "pkix_pl_String_Comparator");
  65. PKIX_NULLCHECK_THREE(firstString, secondString, pResult);
  66. result = 0;
  67. p1 = (unsigned char*) firstString->utf16String;
  68. p2 = (unsigned char*) secondString->utf16String;
  69. /* Compare characters until you find a difference */
  70. for (i = 0; ((i < firstString->utf16Length) &&
  71. (i < secondString->utf16Length) &&
  72. result == 0); i++, p1++, p2++) {
  73. if (*p1 < *p2){
  74. result = -1;
  75. } else if (*p1 > *p2){
  76. result = 1;
  77. }
  78. }
  79. /* If two arrays are identical so far, the longer one is greater */
  80. if (result == 0) {
  81. if (firstString->utf16Length < secondString->utf16Length) {
  82. result = -1;
  83. } else if (firstString->utf16Length >
  84. secondString->utf16Length) {
  85. result = 1;
  86. }
  87. }
  88. *pResult = result;
  89. PKIX_RETURN(STRING);
  90. }
  91. /*
  92. * FUNCTION: pkix_pl_String_Destroy
  93. * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
  94. */
  95. static PKIX_Error *
  96. pkix_pl_String_Destroy(
  97. PKIX_PL_Object *object,
  98. void *plContext)
  99. {
  100. PKIX_PL_String *string = NULL;
  101. PKIX_ENTER(STRING, "pkix_pl_String_Destroy");
  102. PKIX_NULLCHECK_ONE(object);
  103. PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
  104. PKIX_ARGUMENTNOTSTRING);
  105. string = (PKIX_PL_String*)object;
  106. /* XXX For debugging Destroy EscASCII String */
  107. if (string->escAsciiString != NULL) {
  108. PKIX_FREE(string->escAsciiString);
  109. string->escAsciiString = NULL;
  110. string->escAsciiLength = 0;
  111. }
  112. /* Destroy UTF16 String */
  113. if (string->utf16String != NULL) {
  114. PKIX_FREE(string->utf16String);
  115. string->utf16String = NULL;
  116. string->utf16Length = 0;
  117. }
  118. cleanup:
  119. PKIX_RETURN(STRING);
  120. }
  121. /*
  122. * FUNCTION: pkix_pl_String_ToString
  123. * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
  124. */
  125. static PKIX_Error *
  126. pkix_pl_String_ToString(
  127. PKIX_PL_Object *object,
  128. PKIX_PL_String **pString,
  129. void *plContext)
  130. {
  131. PKIX_PL_String *string = NULL;
  132. char *ascii = NULL;
  133. PKIX_UInt32 length;
  134. PKIX_ENTER(STRING, "pkix_pl_String_ToString");
  135. PKIX_NULLCHECK_TWO(object, pString);
  136. PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
  137. PKIX_ARGUMENTNOTSTRING);
  138. string = (PKIX_PL_String*)object;
  139. PKIX_CHECK(PKIX_PL_String_GetEncoded
  140. (string, PKIX_ESCASCII, (void **)&ascii, &length, plContext),
  141. PKIX_STRINGGETENCODEDFAILED);
  142. PKIX_CHECK(PKIX_PL_String_Create
  143. (PKIX_ESCASCII, ascii, 0, pString, plContext),
  144. PKIX_STRINGCREATEFAILED);
  145. goto cleanup;
  146. cleanup:
  147. PKIX_FREE(ascii);
  148. PKIX_RETURN(STRING);
  149. }
  150. /*
  151. * FUNCTION: pkix_pl_String_Equals
  152. * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
  153. */
  154. static PKIX_Error *
  155. pkix_pl_String_Equals(
  156. PKIX_PL_Object *firstObject,
  157. PKIX_PL_Object *secondObject,
  158. PKIX_Boolean *pResult,
  159. void *plContext)
  160. {
  161. PKIX_UInt32 secondType;
  162. PKIX_Int32 cmpResult = 0;
  163. PKIX_ENTER(STRING, "pkix_pl_String_Equals");
  164. PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
  165. /* Sanity check: Test that "firstObject" is a Strings */
  166. PKIX_CHECK(pkix_CheckType(firstObject, PKIX_STRING_TYPE, plContext),
  167. PKIX_FIRSTOBJECTNOTSTRING);
  168. /* "SecondObject" doesn't have to be a string */
  169. PKIX_CHECK(PKIX_PL_Object_GetType
  170. (secondObject, &secondType, plContext),
  171. PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
  172. /* If types differ, then we will return false */
  173. *pResult = PKIX_FALSE;
  174. if (secondType != PKIX_STRING_TYPE) goto cleanup;
  175. /* It's safe to cast here */
  176. PKIX_CHECK(pkix_pl_String_Comparator
  177. ((PKIX_PL_String*)firstObject,
  178. (PKIX_PL_String*)secondObject,
  179. &cmpResult,
  180. plContext),
  181. PKIX_STRINGCOMPARATORFAILED);
  182. /* Strings are equal iff Comparator Result is 0 */
  183. *pResult = (cmpResult == 0);
  184. cleanup:
  185. PKIX_RETURN(STRING);
  186. }
  187. /*
  188. * FUNCTION: pkix_pl_String_Hashcode
  189. * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
  190. */
  191. static PKIX_Error *
  192. pkix_pl_String_Hashcode(
  193. PKIX_PL_Object *object,
  194. PKIX_UInt32 *pHashcode,
  195. void *plContext)
  196. {
  197. PKIX_PL_String *string = NULL;
  198. PKIX_ENTER(STRING, "pkix_pl_String_Hashcode");
  199. PKIX_NULLCHECK_TWO(object, pHashcode);
  200. PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
  201. PKIX_OBJECTNOTSTRING);
  202. string = (PKIX_PL_String*)object;
  203. PKIX_CHECK(pkix_hash
  204. ((const unsigned char *)string->utf16String,
  205. string->utf16Length,
  206. pHashcode,
  207. plContext),
  208. PKIX_HASHFAILED);
  209. cleanup:
  210. PKIX_RETURN(STRING);
  211. }
  212. /*
  213. * FUNCTION: pkix_pl_String_RegisterSelf
  214. * DESCRIPTION:
  215. * Registers PKIX_STRING_TYPE and its related functions with systemClasses[]
  216. * THREAD SAFETY:
  217. * Not Thread Safe - for performance and complexity reasons
  218. *
  219. * Since this function is only called by PKIX_PL_Initialize, which should
  220. * only be called once, it is acceptable that this function is not
  221. * thread-safe.
  222. */
  223. PKIX_Error *
  224. pkix_pl_String_RegisterSelf(
  225. void *plContext)
  226. {
  227. extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
  228. pkix_ClassTable_Entry entry;
  229. PKIX_ENTER(STRING, "pkix_pl_String_RegisterSelf");
  230. entry.description = "String";
  231. entry.objCounter = 0;
  232. entry.typeObjectSize = sizeof(PKIX_PL_String);
  233. entry.destructor = pkix_pl_String_Destroy;
  234. entry.equalsFunction = pkix_pl_String_Equals;
  235. entry.hashcodeFunction = pkix_pl_String_Hashcode;
  236. entry.toStringFunction = pkix_pl_String_ToString;
  237. entry.comparator = NULL;
  238. entry.duplicateFunction = pkix_duplicateImmutable;
  239. systemClasses[PKIX_STRING_TYPE] = entry;
  240. PKIX_RETURN(STRING);
  241. }
  242. /* --Public-String-Functions----------------------------------------- */
  243. /*
  244. * FUNCTION: PKIX_PL_String_Create (see comments in pkix_pl_system.h)
  245. */
  246. PKIX_Error *
  247. PKIX_PL_String_Create(
  248. PKIX_UInt32 fmtIndicator,
  249. const void *stringRep,
  250. PKIX_UInt32 stringLen,
  251. PKIX_PL_String **pString,
  252. void *plContext)
  253. {
  254. PKIX_PL_String *string = NULL;
  255. unsigned char *utf16Char = NULL;
  256. PKIX_UInt32 i;
  257. PKIX_ENTER(STRING, "PKIX_PL_String_Create");
  258. PKIX_NULLCHECK_TWO(pString, stringRep);
  259. PKIX_CHECK(PKIX_PL_Object_Alloc
  260. (PKIX_STRING_TYPE,
  261. sizeof (PKIX_PL_String),
  262. (PKIX_PL_Object **)&string,
  263. plContext),
  264. PKIX_COULDNOTALLOCATENEWSTRINGOBJECT);
  265. string->utf16String = NULL;
  266. string->utf16Length = 0;
  267. /* XXX For Debugging */
  268. string->escAsciiString = NULL;
  269. string->escAsciiLength = 0;
  270. switch (fmtIndicator) {
  271. case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG:
  272. PKIX_STRING_DEBUG("\tCalling PL_strlen).\n");
  273. string->escAsciiLength = PL_strlen(stringRep);
  274. /* XXX Cache for Debugging */
  275. PKIX_CHECK(PKIX_PL_Malloc
  276. ((string->escAsciiLength)+1,
  277. (void **)&string->escAsciiString,
  278. plContext),
  279. PKIX_MALLOCFAILED);
  280. (void) PORT_Memcpy
  281. (string->escAsciiString,
  282. (void *)((char *)stringRep),
  283. (string->escAsciiLength)+1);
  284. /* Convert the EscASCII string to UTF16 */
  285. PKIX_CHECK(pkix_EscASCII_to_UTF16
  286. (string->escAsciiString,
  287. string->escAsciiLength,
  288. (fmtIndicator == PKIX_ESCASCII_DEBUG),
  289. &string->utf16String,
  290. &string->utf16Length,
  291. plContext),
  292. PKIX_ESCASCIITOUTF16FAILED);
  293. break;
  294. case PKIX_UTF8:
  295. /* Convert the UTF8 string to UTF16 */
  296. PKIX_CHECK(pkix_UTF8_to_UTF16
  297. (stringRep,
  298. stringLen,
  299. &string->utf16String,
  300. &string->utf16Length,
  301. plContext),
  302. PKIX_UTF8TOUTF16FAILED);
  303. break;
  304. case PKIX_UTF16:
  305. /* UTF16 Strings must be even in length */
  306. if (stringLen%2 == 1) {
  307. PKIX_DECREF(string);
  308. PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR);
  309. }
  310. utf16Char = (unsigned char *)stringRep;
  311. /* Make sure this is a valid UTF-16 String */
  312. for (i = 0; \
  313. (i < stringLen) && (pkixErrorResult == NULL); \
  314. i += 2) {
  315. /* Check that surrogate pairs are valid */
  316. if ((utf16Char[i] >= 0xD8)&&
  317. (utf16Char[i] <= 0xDB)) {
  318. if ((i+2) >= stringLen) {
  319. PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR);
  320. /* Second pair should be DC00-DFFF */
  321. } else if (!((utf16Char[i+2] >= 0xDC)&&
  322. (utf16Char[i+2] <= 0xDF))) {
  323. PKIX_ERROR(PKIX_UTF16LOWZONEERROR);
  324. } else {
  325. /* Surrogate quartet is valid. */
  326. i += 2;
  327. }
  328. }
  329. }
  330. /* Create UTF16 String */
  331. string->utf16Length = stringLen;
  332. /* Alloc space for string */
  333. PKIX_CHECK(PKIX_PL_Malloc
  334. (stringLen, &string->utf16String, plContext),
  335. PKIX_MALLOCFAILED);
  336. PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n");
  337. (void) PORT_Memcpy
  338. (string->utf16String, stringRep, stringLen);
  339. break;
  340. default:
  341. PKIX_ERROR(PKIX_UNKNOWNFORMAT);
  342. }
  343. *pString = string;
  344. cleanup:
  345. if (PKIX_ERROR_RECEIVED){
  346. PKIX_DECREF(string);
  347. }
  348. PKIX_RETURN(STRING);
  349. }
  350. /*
  351. * FUNCTION: PKIX_PL_Sprintf (see comments in pkix_pl_system.h)
  352. */
  353. PKIX_Error *
  354. PKIX_PL_Sprintf(
  355. PKIX_PL_String **pOut,
  356. void *plContext,
  357. const PKIX_PL_String *fmt,
  358. ...)
  359. {
  360. PKIX_PL_String *tempString = NULL;
  361. PKIX_UInt32 tempUInt = 0;
  362. void *pArg = NULL;
  363. char *asciiText = NULL;
  364. char *asciiFormat = NULL;
  365. char *convertedAsciiFormat = NULL;
  366. char *convertedAsciiFormatBase = NULL;
  367. va_list args;
  368. PKIX_UInt32 length, i, j, dummyLen;
  369. PKIX_ENTER(STRING, "PKIX_PL_Sprintf");
  370. PKIX_NULLCHECK_TWO(pOut, fmt);
  371. PKIX_CHECK(PKIX_PL_String_GetEncoded
  372. ((PKIX_PL_String *)fmt,
  373. PKIX_ESCASCII,
  374. (void **)&asciiFormat,
  375. &length,
  376. plContext),
  377. PKIX_STRINGGETENCODEDFAILED);
  378. PKIX_STRING_DEBUG("\tCalling PR_Malloc).\n");
  379. convertedAsciiFormat = PR_Malloc(length + 1);
  380. if (convertedAsciiFormat == NULL)
  381. PKIX_ERROR_ALLOC_ERROR();
  382. convertedAsciiFormatBase = convertedAsciiFormat;
  383. PKIX_STRING_DEBUG("\tCalling va_start).\n");
  384. va_start(args, fmt);
  385. i = 0;
  386. j = 0;
  387. while (i < length) {
  388. if ((asciiFormat[i] == '%')&&((i+1) < length)) {
  389. switch (asciiFormat[i+1]) {
  390. case 's':
  391. convertedAsciiFormat[j++] = asciiFormat[i++];
  392. convertedAsciiFormat[j++] = asciiFormat[i++];
  393. convertedAsciiFormat[j] = '\0';
  394. tempString = va_arg(args, PKIX_PL_String *);
  395. if (tempString != NULL) {
  396. PKIX_CHECK(PKIX_PL_String_GetEncoded
  397. ((PKIX_PL_String*)
  398. tempString,
  399. PKIX_ESCASCII,
  400. &pArg,
  401. &dummyLen,
  402. plContext),
  403. PKIX_STRINGGETENCODEDFAILED);
  404. } else {
  405. /* there may be a NULL in var_args */
  406. pArg = NULL;
  407. }
  408. if (asciiText != NULL) {
  409. asciiText = PR_sprintf_append(asciiText,
  410. (const char *)convertedAsciiFormat,
  411. pArg);
  412. } else {
  413. asciiText = PR_smprintf
  414. ((const char *)convertedAsciiFormat,
  415. pArg);
  416. }
  417. if (pArg != NULL) {
  418. PKIX_PL_Free(pArg, plContext);
  419. pArg = NULL;
  420. }
  421. convertedAsciiFormat += j;
  422. j = 0;
  423. break;
  424. case 'd':
  425. case 'i':
  426. case 'o':
  427. case 'u':
  428. case 'x':
  429. case 'X':
  430. convertedAsciiFormat[j++] = asciiFormat[i++];
  431. convertedAsciiFormat[j++] = asciiFormat[i++];
  432. convertedAsciiFormat[j] = '\0';
  433. tempUInt = va_arg(args, PKIX_UInt32);
  434. if (asciiText != NULL) {
  435. asciiText = PR_sprintf_append(asciiText,
  436. (const char *)convertedAsciiFormat,
  437. tempUInt);
  438. } else {
  439. asciiText = PR_smprintf
  440. ((const char *)convertedAsciiFormat,
  441. tempUInt);
  442. }
  443. convertedAsciiFormat += j;
  444. j = 0;
  445. break;
  446. default:
  447. convertedAsciiFormat[j++] = asciiFormat[i++];
  448. convertedAsciiFormat[j++] = asciiFormat[i++];
  449. break;
  450. }
  451. } else {
  452. convertedAsciiFormat[j++] = asciiFormat[i++];
  453. }
  454. }
  455. /* for constant string value at end of fmt */
  456. if (j > 0) {
  457. convertedAsciiFormat[j] = '\0';
  458. if (asciiText != NULL) {
  459. asciiText = PR_sprintf_append(asciiText,
  460. (const char *)convertedAsciiFormat);
  461. } else {
  462. asciiText = PR_smprintf((const char *)convertedAsciiFormat);
  463. }
  464. }
  465. va_end(args);
  466. /* Copy temporary char * into a string object */
  467. PKIX_CHECK(PKIX_PL_String_Create
  468. (PKIX_ESCASCII, (void *)asciiText, 0, pOut, plContext),
  469. PKIX_STRINGCREATEFAILED);
  470. cleanup:
  471. PKIX_FREE(asciiFormat);
  472. if (convertedAsciiFormatBase){
  473. PR_Free(convertedAsciiFormatBase);
  474. }
  475. if (asciiText){
  476. PKIX_STRING_DEBUG("\tCalling PR_smprintf_free).\n");
  477. PR_smprintf_free(asciiText);
  478. }
  479. PKIX_RETURN(STRING);
  480. }
  481. /*
  482. * FUNCTION: PKIX_PL_GetString (see comments in pkix_pl_system.h)
  483. */
  484. PKIX_Error *
  485. PKIX_PL_GetString(
  486. /* ARGSUSED */ PKIX_UInt32 stringID,
  487. char *defaultString,
  488. PKIX_PL_String **pString,
  489. void *plContext)
  490. {
  491. PKIX_ENTER(STRING, "PKIX_PL_GetString");
  492. PKIX_NULLCHECK_TWO(pString, defaultString);
  493. /* XXX Optimization - use stringID for caching */
  494. PKIX_CHECK(PKIX_PL_String_Create
  495. (PKIX_ESCASCII, defaultString, 0, pString, plContext),
  496. PKIX_STRINGCREATEFAILED);
  497. cleanup:
  498. PKIX_RETURN(STRING);
  499. }
  500. /*
  501. * FUNCTION: PKIX_PL_String_GetEncoded (see comments in pkix_pl_system.h)
  502. */
  503. PKIX_Error *
  504. PKIX_PL_String_GetEncoded(
  505. PKIX_PL_String *string,
  506. PKIX_UInt32 fmtIndicator,
  507. void **pStringRep,
  508. PKIX_UInt32 *pLength,
  509. void *plContext)
  510. {
  511. PKIX_ENTER(STRING, "PKIX_PL_String_GetEncoded");
  512. PKIX_NULLCHECK_THREE(string, pStringRep, pLength);
  513. switch (fmtIndicator) {
  514. case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG:
  515. PKIX_CHECK(pkix_UTF16_to_EscASCII
  516. (string->utf16String,
  517. string->utf16Length,
  518. (fmtIndicator == PKIX_ESCASCII_DEBUG),
  519. (char **)pStringRep,
  520. pLength,
  521. plContext),
  522. PKIX_UTF16TOESCASCIIFAILED);
  523. break;
  524. case PKIX_UTF8:
  525. PKIX_CHECK(pkix_UTF16_to_UTF8
  526. (string->utf16String,
  527. string->utf16Length,
  528. PKIX_FALSE,
  529. pStringRep,
  530. pLength,
  531. plContext),
  532. PKIX_UTF16TOUTF8FAILED);
  533. break;
  534. case PKIX_UTF8_NULL_TERM:
  535. PKIX_CHECK(pkix_UTF16_to_UTF8
  536. (string->utf16String,
  537. string->utf16Length,
  538. PKIX_TRUE,
  539. pStringRep,
  540. pLength,
  541. plContext),
  542. PKIX_UTF16TOUTF8FAILED);
  543. break;
  544. case PKIX_UTF16:
  545. *pLength = string->utf16Length;
  546. PKIX_CHECK(PKIX_PL_Malloc(*pLength, pStringRep, plContext),
  547. PKIX_MALLOCFAILED);
  548. PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n");
  549. (void) PORT_Memcpy(*pStringRep, string->utf16String, *pLength);
  550. break;
  551. default:
  552. PKIX_ERROR(PKIX_UNKNOWNFORMAT);
  553. }
  554. cleanup:
  555. PKIX_RETURN(STRING);
  556. }