/** * stringprep_4i: * @ucs4: input/output array with string to prepare. * @len: on input, length of input array with Unicode code points, * on exit, length of output array with Unicode code points. * @maxucs4len: maximum length of input/output array. * @flags: stringprep profile flags, or 0. * @profile: pointer to stringprep profile to use. * * Prepare the input UCS-4 string according to the stringprep profile, * and write back the result to the input string. * * The input is not required to be zero terminated (@ucs4[@len] = 0). * The output will not be zero terminated unless @ucs4[@len] = 0. * Instead, see stringprep_4zi() if your input is zero terminated or * if you want the output to be. * * Since the stringprep operation can expand the string, @maxucs4len * indicate how large the buffer holding the string is. This function * will not read or write to code points outside that size. * * The @flags are one of Stringprep_profile_flags, or 0. * * The @profile contain the instructions to perform. Your application * can define new profiles, possibly re-using the generic stringprep * tables that always will be part of the library, or use one of the * currently supported profiles. * * Return value: Returns %STRINGPREP_OK iff successful, or an error code. **/ int stringprep_4i (uint32_t * ucs4, size_t * len, size_t maxucs4len, Stringprep_profile_flags flags, const Stringprep_profile * profile) { size_t i, j; ssize_t k; size_t ucs4len = *len; int rc; for (i = 0; profile[i].operation; i++) { switch (profile[i].operation) { case STRINGPREP_NFKC: { uint32_t *q = 0; if (UNAPPLICAPLEFLAGS (flags, profile[i].flags)) break; if (flags & STRINGPREP_NO_NFKC && !profile[i].flags) /* Profile requires NFKC, but callee asked for no NFKC. */ return STRINGPREP_FLAG_ERROR; q = stringprep_ucs4_nfkc_normalize (ucs4, ucs4len); if (!q) return STRINGPREP_NFKC_FAILED; for (ucs4len = 0; q[ucs4len]; ucs4len++) ; if (ucs4len >= maxucs4len) { free (q); return STRINGPREP_TOO_SMALL_BUFFER; } memcpy (ucs4, q, ucs4len * sizeof (ucs4[0])); free (q); } break; case STRINGPREP_PROHIBIT_TABLE: k = stringprep_find_string_in_table (ucs4, ucs4len, NULL, profile[i].table); if (k != -1) return STRINGPREP_CONTAINS_PROHIBITED; break; case STRINGPREP_UNASSIGNED_TABLE: if (UNAPPLICAPLEFLAGS (flags, profile[i].flags)) break; if (flags & STRINGPREP_NO_UNASSIGNED) { k = stringprep_find_string_in_table (ucs4, ucs4len, NULL, profile[i].table); if (k != -1) return STRINGPREP_CONTAINS_UNASSIGNED; } break; case STRINGPREP_MAP_TABLE: if (UNAPPLICAPLEFLAGS (flags, profile[i].flags)) break; rc = stringprep_apply_table_to_string (ucs4, &ucs4len, maxucs4len, profile[i].table); if (rc != STRINGPREP_OK) return rc; break; case STRINGPREP_BIDI_PROHIBIT_TABLE: case STRINGPREP_BIDI_RAL_TABLE: case STRINGPREP_BIDI_L_TABLE: break; case STRINGPREP_BIDI: { int done_prohibited = 0; int done_ral = 0; int done_l = 0; int contains_ral = -1; int contains_l = -1; for (j = 0; profile[j].operation; j++) if (profile[j].operation == STRINGPREP_BIDI_PROHIBIT_TABLE) { done_prohibited = 1; k = stringprep_find_string_in_table (ucs4, ucs4len, NULL, profile[j].table); if (k != -1) return STRINGPREP_BIDI_CONTAINS_PROHIBITED; } else if (profile[j].operation == STRINGPREP_BIDI_RAL_TABLE) { done_ral = 1; if (stringprep_find_string_in_table (ucs4, ucs4len, NULL, profile[j].table) != -1) contains_ral = j; } else if (profile[j].operation == STRINGPREP_BIDI_L_TABLE) { done_l = 1; if (stringprep_find_string_in_table (ucs4, ucs4len, NULL, profile[j].table) != -1) contains_l = j; } if (!done_prohibited || !done_ral || !done_l) return STRINGPREP_PROFILE_ERROR; if (contains_ral != -1 && contains_l != -1) return STRINGPREP_BIDI_BOTH_L_AND_RAL; if (contains_ral != -1) { if (!(stringprep_find_character_in_table (ucs4[0], profile[contains_ral].table) != -1 && stringprep_find_character_in_table (ucs4[ucs4len - 1], profile[contains_ral].table) != -1)) return STRINGPREP_BIDI_LEADTRAIL_NOT_RAL; } } break; default: return STRINGPREP_PROFILE_ERROR; break; } } *len = ucs4len; return STRINGPREP_OK; }
void doit (void) { size_t i; int rc; for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) { if (debug) { uint32_t *p, *q; printf ("PR29 entry %ld: %s\n", i, tv[i].name); printf ("in:\n"); ucs4print (tv[i].in, tv[i].inlen); printf ("nfkc:\n"); p = stringprep_ucs4_nfkc_normalize (tv[i].in, tv[i].inlen); ucs4print (p, -1); printf ("second nfkc:\n"); q = stringprep_ucs4_nfkc_normalize (p, -1); ucs4print (q, -1); free (p); free (q); } rc = pr29_4 (tv[i].in, tv[i].inlen); if (rc != tv[i].rc) { fail ("PR29 entry %ld failed (expected %d): %d\n", i, tv[i].rc, rc); if (debug) printf ("FATAL\n"); continue; } rc = pr29_4z (tv[i].in); if (rc != tv[i].rc) { fail ("PR29 entry %ld failed (expected %d): %d\n", i, tv[i].rc, rc); if (debug) printf ("FATAL\n"); continue; } { char *p; size_t items_read, items_written; p = stringprep_ucs4_to_utf8 (tv[i].in, (ssize_t) tv[i].inlen, &items_read, &items_written); if (p == NULL) fail ("FAIL: stringprep_ucs4_to_utf8(tv[%ld]) == NULL\n", i); if (debug) hexprint (p, strlen (p)); rc = pr29_8z (p); free (p); if (rc != tv[i].rc) { fail ("PR29 entry %ld failed (expected %d): %d\n", i, tv[i].rc, rc); if (debug) printf ("FATAL\n"); continue; } } if (debug) { if (tv[i].rc != PR29_SUCCESS) printf ("EXPECTED FAIL\n"); else printf ("OK\n"); } } }