Back to GNU Libidn 1.33 Homepage
GNU Libidn 1.33 Cyclomatic Complexity Report

Report generated at: Wed Jul 20 19:26:33 CEST 2016

Summary

Total number of functions | 72
Number of low risk functions | 61
Number of moderate risk functions | 6
Number of high risk functions | 5
Number of untestable functions | 0

Details for all functions

| Cyclomatic Complexity | Risk Evaluation
| 0 - 10 | Simple module, without much risk
| 11 - 20 | More complex module, moderate risk
| 21 - 50 | Complex module, high risk
| greater than 50 | Untestable module, very high risk

| Function Name | Modified Cyclo | Number of Statements | Number of Lines | Source File
↓ | idna_to_ascii_4i | 37 | 96 | 199 | idna.c
    int
    idna_to_ascii_4i (const uint32_t * in, size_t inlen, char *out, int flags)
    {
      size_t len, outlen;
      uint32_t *src;		/* XXX don't need to copy data? */
      int rc;

      /*
       * ToASCII consists of the following steps:
       *
       * 1. If all code points in the sequence are in the ASCII range (0..7F)
       * then skip to step 3.
       */

      {
        size_t i;
        int inasciirange;

        inasciirange = 1;
        for (i = 0; i < inlen; i++)
          if (in[i] > 0x7F)
    	inasciirange = 0;
        if (inasciirange)
          {
    	src = malloc (sizeof (in[0]) * (inlen + 1));
    	if (src == NULL)
    	  return IDNA_MALLOC_ERROR;

    	memcpy (src, in, sizeof (in[0]) * inlen);
    	src[inlen] = 0;

    	goto step3;
          }
      }

      /*
       * 2. Perform the steps specified in [NAMEPREP] and fail if there is
       * an error. The AllowUnassigned flag is used in [NAMEPREP].
       */

      {
        char *p;

        p = stringprep_ucs4_to_utf8 (in, (ssize_t) inlen, NULL, NULL);
        if (p == NULL)
          return IDNA_MALLOC_ERROR;

        len = strlen (p);
        do
          {
    	char *newp;

    	len = 2 * len + 10;	/* XXX better guess? */
    	newp = realloc (p, len);
    	if (newp == NULL)
    	  {
    	    free (p);
    	    return IDNA_MALLOC_ERROR;
    	  }
    	p = newp;

    	if (flags & IDNA_ALLOW_UNASSIGNED)
    	  rc = stringprep_nameprep (p, len);
    	else
    	  rc = stringprep_nameprep_no_unassigned (p, len);
          }
        while (rc == STRINGPREP_TOO_SMALL_BUFFER);

        if (rc != STRINGPREP_OK)
          {
    	free (p);
    	return IDNA_STRINGPREP_ERROR;
          }

        src = stringprep_utf8_to_ucs4 (p, -1, NULL);

        free (p);

        if (!src)
          return IDNA_MALLOC_ERROR;
      }

    step3:
      /*
       * 3. If the UseSTD3ASCIIRules flag is set, then perform these checks:
       *
       * (a) Verify the absence of non-LDH ASCII code points; that is,
       * the absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
       *
       * (b) Verify the absence of leading and trailing hyphen-minus;
       * that is, the absence of U+002D at the beginning and end of
       * the sequence.
       */

      if (flags & IDNA_USE_STD3_ASCII_RULES)
        {
          size_t i;

          for (i = 0; src[i]; i++)
    	if (src[i] <= 0x2C || src[i] == 0x2E || src[i] == 0x2F ||
    	    (src[i] >= 0x3A && src[i] <= 0x40) ||
    	    (src[i] >= 0x5B && src[i] <= 0x60) ||
    	    (src[i] >= 0x7B && src[i] <= 0x7F))
    	  {
    	    free (src);
    	    return IDNA_CONTAINS_NON_LDH;
    	  }

          if (src[0] == 0x002D || (i > 0 && src[i - 1] == 0x002D))
    	{
    	  free (src);
    	  return IDNA_CONTAINS_MINUS;
    	}
        }

      /*
       * 4. If all code points in the sequence are in the ASCII range
       * (0..7F), then skip to step 8.
       */

      {
        size_t i;
        int inasciirange;

        inasciirange = 1;
        for (i = 0; src[i]; i++)
          {
    	if (src[i] > 0x7F)
    	  inasciirange = 0;
    	/* copy string to output buffer if we are about to skip to step8 */
    	if (i < 64)
    	  out[i] = src[i];
          }
        if (i < 64)
          out[i] = '\0';
        else
          {
    	free (src);
    	return IDNA_INVALID_LENGTH;
          }
        if (inasciirange)
          goto step8;
      }

      /*
       * 5. Verify that the sequence does NOT begin with the ACE prefix.
       *
       */

      {
        size_t i;
        int match;

        match = 1;
        for (i = 0; match && i < strlen (IDNA_ACE_PREFIX); i++)
          if (((uint32_t) IDNA_ACE_PREFIX[i] & 0xFF) != src[i])
    	match = 0;
        if (match)
          {
    	free (src);
    	return IDNA_CONTAINS_ACE_PREFIX;
          }
      }

      /*
       * 6. Encode the sequence using the encoding algorithm in [PUNYCODE]
       * and fail if there is an error.
       */
      for (len = 0; src[len]; len++)
        ;
      src[len] = '\0';
      outlen = 63 - strlen (IDNA_ACE_PREFIX);
      rc = punycode_encode (len, src, NULL,
    			&outlen, &out[strlen (IDNA_ACE_PREFIX)]);
      if (rc != PUNYCODE_SUCCESS)
        {
          free (src);
          return IDNA_PUNYCODE_ERROR;
        }
      out[strlen (IDNA_ACE_PREFIX) + outlen] = '\0';

      /*
       * 7. Prepend the ACE prefix.
       */

      memcpy (out, IDNA_ACE_PREFIX, strlen (IDNA_ACE_PREFIX));

      /*
       * 8. Verify that the number of code points is in the range 1 to 63
       * inclusive (0 is excluded).
       */

    step8:
      free (src);
      if (strlen (out) < 1)
        return IDNA_INVALID_LENGTH;

      return IDNA_SUCCESS;
    }
↓ | stringprep_4i | 30 | 76 | 137 | stringprep.c
    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;
    	    size_t contains_ral = SIZE_MAX;
    	    size_t contains_l = SIZE_MAX;

    	    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 != SIZE_MAX && contains_l != SIZE_MAX)
    	      return STRINGPREP_BIDI_BOTH_L_AND_RAL;

    	    if (contains_ral != SIZE_MAX)
    	      {
    		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;
    }
↓ | _g_utf8_normalize_wc | 30 | 76 | 135 | nfkc.c
    static gunichar *
    _g_utf8_normalize_wc (const gchar * str, gssize max_len, GNormalizeMode mode)
    {
      gsize n_wc;
      gunichar *wc_buffer;
      const char *p;
      gsize last_start;
      gboolean do_compat = (mode == G_NORMALIZE_NFKC || mode == G_NORMALIZE_NFKD);
      gboolean do_compose = (mode == G_NORMALIZE_NFC || mode == G_NORMALIZE_NFKC);

      n_wc = 0;
      p = str;
      while ((max_len < 0 || p < str + max_len) && *p)
        {
          const gchar *decomp;
          gunichar wc = g_utf8_get_char (p);

          if (wc >= SBase && wc < SBase + SCount)
    	{
    	  gsize result_len;
    	  decompose_hangul (wc, NULL, &result_len);
    	  n_wc += result_len;
    	}
          else
    	{
    	  decomp = find_decomposition (wc, do_compat);

    	  if (decomp)
    	    n_wc += g_utf8_strlen (decomp, -1);
    	  else
    	    n_wc++;
    	}

          p = g_utf8_next_char (p);
        }

      wc_buffer = g_malloc (sizeof (gunichar) * (n_wc + 1));
      if (!wc_buffer)
        return NULL;

      last_start = 0;
      n_wc = 0;
      p = str;
      while ((max_len < 0 || p < str + max_len) && *p)
        {
          gunichar wc = g_utf8_get_char (p);
          const gchar *decomp;
          int cc;
          gsize old_n_wc = n_wc;

          if (wc >= SBase && wc < SBase + SCount)
    	{
    	  gsize result_len;
    	  decompose_hangul (wc, wc_buffer + n_wc, &result_len);
    	  n_wc += result_len;
    	}
          else
    	{
    	  decomp = find_decomposition (wc, do_compat);

    	  if (decomp)
    	    {
    	      const char *pd;
    	      for (pd = decomp; *pd != '\0'; pd = g_utf8_next_char (pd))
    		wc_buffer[n_wc++] = g_utf8_get_char (pd);
    	    }
    	  else
    	    wc_buffer[n_wc++] = wc;
    	}

          if (n_wc > 0)
    	{
    	  cc = COMBINING_CLASS (wc_buffer[old_n_wc]);

    	  if (cc == 0)
    	    {
    	      g_unicode_canonical_ordering (wc_buffer + last_start,
    					    n_wc - last_start);
    	      last_start = old_n_wc;
    	    }
    	}

          p = g_utf8_next_char (p);
        }

      if (n_wc > 0)
        {
          g_unicode_canonical_ordering (wc_buffer + last_start,
    				    n_wc - last_start);
          // dead assignment: last_start = n_wc;
        }

      wc_buffer[n_wc] = 0;

      /* All decomposed and reordered */

      if (do_compose && n_wc > 0)
        {
          gsize i, j;
          int last_cc = 0;
          last_start = 0;

          for (i = 0; i < n_wc; i++)
    	{
    	  int cc = COMBINING_CLASS (wc_buffer[i]);

    	  if (i > 0 &&
    	      (last_cc == 0 || last_cc != cc) &&
    	      combine (wc_buffer[last_start], wc_buffer[i],
    		       &wc_buffer[last_start]))
    	    {
    	      for (j = i + 1; j < n_wc; j++)
    		wc_buffer[j - 1] = wc_buffer[j];
    	      n_wc--;
    	      i--;

    	      if (i == last_start)
    		last_cc = 0;
    	      else
    		last_cc = COMBINING_CLASS (wc_buffer[i - 1]);

    	      continue;
    	    }

    	  if (cc == 0)
    	    last_start = i;

    	  last_cc = cc;
    	}
        }

      wc_buffer[n_wc] = 0;

      return wc_buffer;
    }
↓ | punycode_encode | 22 | 57 | 111 | punycode.c
    int
    punycode_encode (size_t input_length,
    		 const punycode_uint input[],
    		 const unsigned char case_flags[],
    		 size_t * output_length, char output[])
    {
      punycode_uint input_len, n, delta, h, b, bias, j, m, q, k, t;
      size_t out, max_out;

      /* The Punycode spec assumes that the input length is the same type */
      /* of integer as a code point, so we need to convert the size_t to  */
      /* a punycode_uint, which could overflow.                           */

      if (input_length > maxint)
        return punycode_overflow;
      input_len = (punycode_uint) input_length;

      /* Initialize the state: */

      n = initial_n;
      delta = 0;
      out = 0;
      max_out = *output_length;
      bias = initial_bias;

      /* Handle the basic code points: */

      for (j = 0; j < input_len; ++j)
        {
          if (basic (input[j]))
    	{
    	  if (max_out - out < 2)
    	    return punycode_big_output;
    	  output[out++] = case_flags ?
    	    encode_basic (input[j], case_flags[j]) : (char) input[j];
    	}
          /* else if (input[j] < n) return punycode_bad_input; */
          /* (not needed for Punycode with unsigned code points) */
        }

      h = b = (punycode_uint) out;
      /* cannot overflow because out <= input_len <= maxint */

      /* h is the number of code points that have been handled, b is the  */
      /* number of basic code points, and out is the number of ASCII code */
      /* points that have been output.                                    */

      if (b > 0)
        output[out++] = delimiter;

      /* Main encoding loop: */

      while (h < input_len)
        {
          /* All non-basic code points < n have been     */
          /* handled already.  Find the next larger one: */

          for (m = maxint, j = 0; j < input_len; ++j)
    	{
    	  /* if (basic(input[j])) continue; */
    	  /* (not needed for Punycode) */
    	  if (input[j] >= n && input[j] < m)
    	    m = input[j];
    	}

          /* Increase delta enough to advance the decoder's    */
          /* <n,i> state to <m,0>, but guard against overflow: */

          if (m - n > (maxint - delta) / (h + 1))
    	return punycode_overflow;
          delta += (m - n) * (h + 1);
          n = m;

          for (j = 0; j < input_len; ++j)
    	{
    	  /* Punycode does not need to check whether input[j] is basic: */
    	  if (input[j] < n /* || basic(input[j]) */ )
    	    {
    	      if (++delta == 0)
    		return punycode_overflow;
    	    }

    	  if (input[j] == n)
    	    {
    	      /* Represent delta as a generalized variable-length integer: */

    	      for (q = delta, k = base;; k += base)
    		{
    		  if (out >= max_out)
    		    return punycode_big_output;
    		  t = k <= bias /* + tmin */ ? tmin :	/* +tmin not needed */
    		    k >= bias + tmax ? tmax : k - bias;
    		  if (q < t)
    		    break;
    		  output[out++] = encode_digit (t + (q - t) % (base - t), 0);
    		  q = (q - t) / (base - t);
    		}

    	      output[out++] = encode_digit (q, case_flags && case_flags[j]);
    	      bias = adapt (delta, h + 1, h == b);
    	      delta = 0;
    	      ++h;
    	    }
    	}

          ++delta, ++n;
        }

      *output_length = out;
      return punycode_success;
    }
↓ | punycode_decode | 21 | 59 | 101 | punycode.c
    int
    punycode_decode (size_t input_length,
    		 const char input[],
    		 size_t * output_length,
    		 punycode_uint output[], unsigned char case_flags[])
    {
      punycode_uint n, out, i, max_out, bias, oldi, w, k, digit, t;
      size_t b, j, in;

      /* Initialize the state: */

      n = initial_n;
      out = i = 0;
      max_out = *output_length > maxint ? maxint
        : (punycode_uint) * output_length;
      bias = initial_bias;

      /* Handle the basic code points:  Let b be the number of input code */
      /* points before the last delimiter, or 0 if there is none, then    */
      /* copy the first b code points to the output.                      */

      for (b = j = 0; j < input_length; ++j)
        if (delim (input[j]))
          b = j;
      if (b > max_out)
        return punycode_big_output;

      for (j = 0; j < b; ++j)
        {
          if (case_flags)
    	case_flags[out] = flagged (input[j]);
          if (!basic (input[j]))
    	return punycode_bad_input;
          output[out++] = input[j];
        }

      /* Main decoding loop:  Start just after the last delimiter if any  */
      /* basic code points were copied; start at the beginning otherwise. */

      for (in = b > 0 ? b + 1 : 0; in < input_length; ++out)
        {

          /* in is the index of the next ASCII code point to be consumed, */
          /* and out is the number of code points in the output array.    */

          /* Decode a generalized variable-length integer into delta,  */
          /* which gets added to i.  The overflow checking is easier   */
          /* if we increase i as we go, then subtract off its starting */
          /* value at the end to obtain delta.                         */

          for (oldi = i, w = 1, k = base;; k += base)
    	{
    	  if (in >= input_length)
    	    return punycode_bad_input;
    	  digit = decode_digit (input[in++]);
    	  if (digit >= base)
    	    return punycode_bad_input;
    	  if (digit > (maxint - i) / w)
    	    return punycode_overflow;
    	  i += digit * w;
    	  t = k <= bias /* + tmin */ ? tmin :	/* +tmin not needed */
    	    k >= bias + tmax ? tmax : k - bias;
    	  if (digit < t)
    	    break;
    	  if (w > maxint / (base - t))
    	    return punycode_overflow;
    	  w *= (base - t);
    	}

          bias = adapt (i - oldi, out + 1, oldi == 0);

          /* i was supposed to wrap around from out+1 to 0,   */
          /* incrementing n each time, so we'll fix that now: */

          if (i / (out + 1) > maxint - n)
    	return punycode_overflow;
          n += i / (out + 1);
          i %= (out + 1);

          /* Insert n at position i of the output: */

          /* not needed for Punycode: */
          /* if (basic(n)) return punycode_bad_input; */
          if (out >= max_out)
    	return punycode_big_output;

          if (case_flags)
    	{
    	  memmove (case_flags + i + 1, case_flags + i, out - i);
    	  /* Case of last ASCII code point determines case flag: */
    	  case_flags[i] = flagged (input[in - 1]);
    	}

          memmove (output + i + 1, output + i, (out - i) * sizeof *output);
          output[i++] = n;
        }

      *output_length = (size_t) out;
      /* cannot overflow because out <= old value of *output_length */
      return punycode_success;
    }
↓ | idna_to_ascii_4z | 15 | 46 | 85 | idna.c
    int
    idna_to_ascii_4z (const uint32_t * input, char **output, int flags)
    {
      const uint32_t *start = input;
      const uint32_t *end;
      char buf[64];
      char *out = NULL;
      int rc;

      /* 1) Whenever dots are used as label separators, the following
         characters MUST be recognized as dots: U+002E (full stop),
         U+3002 (ideographic full stop), U+FF0E (fullwidth full stop),
         U+FF61 (halfwidth ideographic full stop). */

      if (input[0] == 0)
        {
          /* Handle implicit zero-length root label. */
          *output = malloc (1);
          if (!*output)
    	return IDNA_MALLOC_ERROR;
          strcpy (*output, "");
          return IDNA_SUCCESS;
        }

      if (DOTP (input[0]) && input[1] == 0)
        {
          /* Handle explicit zero-length root label. */
          *output = malloc (2);
          if (!*output)
    	return IDNA_MALLOC_ERROR;
          strcpy (*output, ".");
          return IDNA_SUCCESS;
        }

      *output = NULL;
      do
        {
          end = start;

          for (; *end && !DOTP (*end); end++)
    	;

          if (*end == '\0' && start == end)
    	{
    	  /* Handle explicit zero-length root label. */
    	  buf[0] = '\0';
    	}
          else
    	{
    	  rc = idna_to_ascii_4i (start, (size_t) (end - start), buf, flags);
    	  if (rc != IDNA_SUCCESS)
    	    {
    	      free (out);
    	      return rc;
    	    }
    	}

          if (out)
    	{
    	  size_t l = strlen (out) + 1 + strlen (buf) + 1;
    	  char *newp = realloc (out, l);
    	  if (!newp)
    	    {
    	      free (out);
    	      return IDNA_MALLOC_ERROR;
    	    }
    	  out = newp;
    	  strcat (out, ".");
    	  strcat (out, buf);
    	}
          else
    	{
    	  out = strdup (buf);
    	  if (!out)
    	    return IDNA_MALLOC_ERROR;
    	}

          start = end + 1;
        }
      while (*end);

      *output = out;

      return IDNA_SUCCESS;
    }
↓ | tld_get_4 | 14 | 24 | 37 | tld.c
    int
    tld_get_4 (const uint32_t * in, size_t inlen, char **out)
    {
      const uint32_t *ipos;
      size_t olen;

      *out = NULL;
      if (!in || inlen == 0)
        return TLD_NODATA;

      ipos = &in[inlen - 1];
      olen = 0;
      /* Scan backwards for non(latin)letters. */
      while (ipos >= in && ((*ipos >= 0x41 && *ipos <= 0x5A) ||
    			(*ipos >= 0x61 && *ipos <= 0x7A)))
        ipos--, olen++;

      if (olen > 0 && ipos >= in && DOTP (*ipos))
        {
          /* Found something that appears a TLD. */
          char *out_s = malloc (sizeof (char) * (olen + 1));
          char *opos = out_s;

          if (!opos)
    	return TLD_MALLOC_ERROR;

          ipos++;
          /* Transcribe to lowercase ascii string. */
          for (; ipos < &in[inlen]; ipos++, opos++)
    	*opos = *ipos > 0x5A ? *ipos : *ipos + 0x20;
          *opos = 0;
          *out = out_s;
          return TLD_SUCCESS;
        }

      return TLD_NO_TLD;
    }
↓ | idna_to_unicode_internal | 12 | 47 | 118 | idna.c
    static int
    idna_to_unicode_internal (char *utf8in,
    			  uint32_t * out, size_t * outlen, int flags)
    {
      int rc;
      char tmpout[64];
      size_t utf8len = strlen (utf8in) + 1;
      size_t addlen = 0;

      /*
       * ToUnicode consists of the following steps:
       *
       * 1. If the sequence contains any code points outside the ASCII range
       * (0..7F) then proceed to step 2, otherwise skip to step 3.
       */

      {
        size_t i;
        int inasciirange;

        inasciirange = 1;
        for (i = 0; utf8in[i]; i++)
          if (utf8in[i] & ~0x7F)
    	inasciirange = 0;
        if (inasciirange)
          goto step3;
      }

      /*
       * 2. Perform the steps specified in [NAMEPREP] and fail if there is an
       * error. (If step 3 of ToASCII is also performed here, it will not
       * affect the overall behavior of ToUnicode, but it is not
       * necessary.) The AllowUnassigned flag is used in [NAMEPREP].
       */
      do
        {
          char *newp = realloc (utf8in, utf8len + addlen);
          if (newp == NULL)
    	{
    	  free (utf8in);
    	  return IDNA_MALLOC_ERROR;
    	}
          utf8in = newp;
          if (flags & IDNA_ALLOW_UNASSIGNED)
    	rc = stringprep_nameprep (utf8in, utf8len + addlen);
          else
    	rc = stringprep_nameprep_no_unassigned (utf8in, utf8len + addlen);
          addlen += 1;
        }
      while (rc == STRINGPREP_TOO_SMALL_BUFFER);

      if (rc != STRINGPREP_OK)
        {
          free (utf8in);
          return IDNA_STRINGPREP_ERROR;
        }

      /* 3. Verify that the sequence begins with the ACE prefix, and save a
       * copy of the sequence.
       * ... The ToASCII and ToUnicode operations MUST recognize the ACE
       prefix in a case-insensitive manner.
       */

    step3:
      if (c_strncasecmp (utf8in, IDNA_ACE_PREFIX, strlen (IDNA_ACE_PREFIX)) != 0)
        {
          free (utf8in);
          return IDNA_NO_ACE_PREFIX;
        }

      /* 4. Remove the ACE prefix.
       */

      memmove (utf8in, &utf8in[strlen (IDNA_ACE_PREFIX)],
    	   strlen (utf8in) - strlen (IDNA_ACE_PREFIX) + 1);

      /* 5. Decode the sequence using the decoding algorithm in [PUNYCODE]
       * and fail if there is an error. Save a copy of the result of
       * this step.
       */

      (*outlen)--;			/* reserve one for the zero */

      rc = punycode_decode (strlen (utf8in), utf8in, outlen, out, NULL);
      if (rc != PUNYCODE_SUCCESS)
        {
          free (utf8in);
          return IDNA_PUNYCODE_ERROR;
        }

      out[*outlen] = 0;		/* add zero */

      /* 6. Apply ToASCII.
       */

      rc = idna_to_ascii_4i (out, *outlen, tmpout, flags);
      if (rc != IDNA_SUCCESS)
        {
          free (utf8in);
          return rc;
        }

      /* 7. Verify that the result of step 6 matches the saved copy from
       * step 3, using a case-insensitive ASCII comparison.
       */

      if (c_strcasecmp (utf8in, tmpout + strlen (IDNA_ACE_PREFIX)) != 0)
        {
          free (utf8in);
          return IDNA_ROUNDTRIP_VERIFY_ERROR;
        }

      /* 8. Return the saved copy from step 5.
       */

      free (utf8in);
      return IDNA_SUCCESS;
    }
↓ | combine | 12 | 21 | 54 | nfkc.c
    static gboolean
    combine (gunichar a, gunichar b, gunichar * result)
    {
      gushort index_a, index_b;

      if (combine_hangul (a, b, result))
        return TRUE;

      index_a = COMPOSE_INDEX (a);

      if (index_a >= COMPOSE_FIRST_SINGLE_START && index_a < COMPOSE_SECOND_START)
        {
          if (b == compose_first_single[index_a - COMPOSE_FIRST_SINGLE_START][0])
    	{
    	  *result =
    	    compose_first_single[index_a - COMPOSE_FIRST_SINGLE_START][1];
    	  return TRUE;
    	}
          else
    	return FALSE;
        }

      index_b = COMPOSE_INDEX (b);

      if (index_b >= COMPOSE_SECOND_SINGLE_START)
        {
          if (a ==
    	  compose_second_single[index_b - COMPOSE_SECOND_SINGLE_START][0])
    	{
    	  *result =
    	    compose_second_single[index_b - COMPOSE_SECOND_SINGLE_START][1];
    	  return TRUE;
    	}
          else
    	return FALSE;
        }

      if (index_a >= COMPOSE_FIRST_START && index_a < COMPOSE_FIRST_SINGLE_START
          && index_b >= COMPOSE_SECOND_START
          && index_b < COMPOSE_SECOND_SINGLE_START)
        {
          gunichar res =
    	compose_array[index_a - COMPOSE_FIRST_START][index_b -
    						     COMPOSE_SECOND_START];

          if (res)
    	{
    	  *result = res;
    	  return TRUE;
    	}
        }

      return FALSE;
    }
↓ | g_utf8_to_ucs4_fast | 11 | 38 | 75 | nfkc.c
    static gunichar *
    g_utf8_to_ucs4_fast (const gchar * str, glong len, glong * items_written)
    {
      gunichar *result;
      gsize n_chars, i;
      const gchar *p;

      g_return_val_if_fail (str != NULL, NULL);

      p = str;
      n_chars = 0;
      if (len < 0)
        {
          while (*p)
    	{
    	  p = g_utf8_next_char (p);
    	  ++n_chars;
    	}
        }
      else
        {
          while (p < str + len && *p)
    	{
    	  p = g_utf8_next_char (p);
    	  ++n_chars;
    	}
        }

      result = g_malloc (sizeof (gunichar) * (n_chars + 1));
      if (!result)
        return NULL;

      p = str;
      for (i = 0; i < n_chars; i++)
        {
          gunichar wc = (guchar) * p++;

          if (wc < 0x80)
    	{
    	  result[i] = wc;
    	}
          else
    	{
    	  gunichar mask = 0x40;

    	  if (G_UNLIKELY ((wc & mask) == 0))
    	    {
    	      /* It's an out-of-sequence 10xxxxxxx byte.
    	       * Rather than making an ugly hash of this and the next byte
    	       * and overrunning the buffer, it's more useful to treat it
    	       * with a replacement character */
    	      result[i] = 0xfffd;
    	      continue;
    	    }

    	  do
    	    {
    	      wc <<= 6;
    	      wc |= (guchar) (*p++) & 0x3f;
    	      mask <<= 5;
    	    }
    	  while ((wc & mask) != 0);

    	  wc &= mask - 1;

    	  result[i] = wc;
    	}
        }
      result[i] = 0;

      if (items_written)
        *items_written = i;

      return result;
    }
↓ | _tld_checkchar | 11 | 15 | 28 | tld.c
    static int
    _tld_checkchar (uint32_t ch, const Tld_table * tld)
    {
      const Tld_table_element *s, *e, *m;

      if (!tld)
        return TLD_SUCCESS;

      /* Check for [-a-z0-9.]. */
      if ((ch >= 0x61 && ch <= 0x7A) ||
          (ch >= 0x30 && ch <= 0x39) || ch == 0x2D || DOTP (ch))
        return TLD_SUCCESS;

      s = tld->valid;
      e = s + tld->nvalid;
      while (s < e)
        {
          m = s + ((e - s) >> 1);
          if (ch < m->start)
    	e = m;
          else if (ch > m->end)
    	s = m + 1;
          else
    	return TLD_SUCCESS;
        }

      return TLD_INVALID;
    }
| find_decomposition | 10 | 21 | 41 | nfkc.c
| combine_hangul | 10 | 11 | 23 | nfkc.c
| g_ucs4_to_utf8 | 9 | 26 | 42 | nfkc.c
| stringprep_profile | 9 | 24 | 38 | stringprep.c
| g_utf8_strlen | 9 | 16 | 37 | nfkc.c
| g_unichar_to_utf8 | 8 | 28 | 51 | nfkc.c
| idna_to_unicode_4z4z | 7 | 37 | 61 | idna.c
| stringprep | 7 | 32 | 55 | stringprep.c
| g_unicode_canonical_ordering | 7 | 24 | 36 | nfkc.c
| pr29_4 | 7 | 15 | 27 | pr29.c
| stringprep_find_character_in_table | 6 | 8 | 21 | stringprep.c
| tld_get_table | 5 | 9 | 14 | tld.c
| stringprep_locale_charset | 5 | 7 | 17 | toutf8.c
| stringprep_apply_table_to_string | 5 | 13 | 27 | stringprep.c
| tld_check_4t | 5 | 13 | 24 | tld.c
| tld_default_table | 4 | 8 | 16 | tld.c
| decode_digit | 4 | 4 | 6 | punycode.c
| tld_check_4 | 4 | 13 | 28 | tld.c
| idna_to_unicode_44i | 4 | 12 | 24 | idna.c
| decompose_hangul | 4 | 10 | 21 | nfkc.c
| stringprep_find_string_in_table | 4 | 10 | 19 | stringprep.c
| first_column | 4 | 10 | 12 | pr29.c
| adapt | 3 | 9 | 16 | punycode.c
| stringprep_4zi_1 | 3 | 8 | 18 | stringprep.c
| combinationclass | 3 | 7 | 11 | pr29.c
| in_last_column_row | 3 | 7 | 11 | pr29.c
| stringprep_utf8_nfkc_normalize | 3 | 7 | 15 | nfkc.c
| stringprep_utf8_to_ucs4 | 3 | 7 | 15 | nfkc.c
| tld_check_4z | 3 | 6 | 14 | tld.c
| stringprep_4zi | 3 | 6 | 12 | stringprep.c
| tld_check_4tz | 3 | 6 | 13 | tld.c
| tld_get_4z | 3 | 6 | 13 | tld.c
| stringprep_check_version | 3 | 3 | 8 | version.c
| tld_get_z | 3 | 14 | 22 | tld.c
| tld_check_8z | 3 | 11 | 21 | tld.c
| idna_to_unicode_8zlz | 3 | 10 | 18 | idna.c
| idna_to_unicode_8z8z | 3 | 10 | 18 | idna.c
| tld_check_lz | 3 | 10 | 20 | tld.c
| tld_strerror | 2 | 17 | 40 | strerror-tld.c
| punycode_strerror | 2 | 13 | 32 | strerror-punycode.c
| pr29_strerror | 2 | 11 | 28 | strerror-pr29.c
| idna_to_unicode_8z4z | 2 | 9 | 16 | idna.c
| idna_to_ascii_8z | 2 | 9 | 18 | idna.c
| idna_to_unicode_lzlz | 2 | 8 | 15 | idna.c
| idna_to_ascii_lz | 2 | 8 | 16 | idna.c
| g_utf8_get_char | 2 | 8 | 14 | nfkc.c
| pr29_8z | 2 | 8 | 16 | pr29.c
| stringprep_convert | 2 | 7 | 16 | toutf8.c
| pr29_4z | 2 | 6 | 10 | pr29.c
| encode_basic | 2 | 2 | 6 | punycode.c
| stringprep_strerror | 2 | 31 | 67 | strerror-stringprep.c
| idna_strerror | 2 | 29 | 64 | strerror-idna.c
| stringprep_ucs4_nfkc_normalize | 1 | 6 | 12 | nfkc.c
| g_utf8_normalize | 1 | 5 | 11 | nfkc.c
| stringprep_unichar_to_utf8 | 1 | 1 | 5 | nfkc.c
| stringprep_utf8_to_unichar | 1 | 1 | 5 | nfkc.c
| idn_free | 1 | 1 | 5 | idn-free.c
| stringprep_utf8_to_locale | 1 | 1 | 5 | toutf8.c
| stringprep_locale_to_utf8 | 1 | 1 | 5 | toutf8.c
| stringprep_ucs4_to_utf8 | 1 | 1 | 7 | nfkc.c
| encode_digit | 1 | 1 | 7 | punycode.c

Copyright (c) 2007, 2008 Free Software Foundation, Inc.