/*
 * call-seq:
 *   IDN::Punycode.decode(string) => string
 *
 * Converts Punycode to a string in UTF-8 format.
 *
 * Raises IDN::Punycode::PunycodeError on failure.
 */

static VALUE decode(VALUE self, VALUE str)
{
  int rc;
  punycode_uint *ustr;
  size_t len;
  char *buf = NULL;
  VALUE retv;

  str = rb_check_convert_type(str, T_STRING, "String", "to_s");

  len = RSTRING(str)->len;
  ustr = malloc(len * sizeof(punycode_uint));

  if (ustr == NULL) {
    rb_raise(rb_eNoMemError, "cannot allocate memory (%d bytes)", len);
    return Qnil;
  }

  rc = punycode_decode(RSTRING(str)->len, RSTRING(str)->ptr,
                       &len, ustr, NULL);

  if (rc != PUNYCODE_SUCCESS) {
    xfree(ustr);
    rb_raise(ePunycodeError, "%s (%d)", punycode_strerror(rc), rc);
    return Qnil;
  }

  buf = stringprep_ucs4_to_utf8(ustr, len, NULL, &len);
  retv = rb_str_new(buf, len);
  xfree(ustr);
  xfree(buf);
  return retv;
}