PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT STRING * encoding_to_encoding(PARROT_INTERP, ARGIN(const STRING *src), ARGIN(const STR_VTABLE *encoding), double avg_bytes) { ASSERT_ARGS(encoding_to_encoding) STRING *result; String_iter src_iter, dest_iter; UINTVAL src_len, alloc_bytes; UINTVAL max_bytes = encoding->max_bytes_per_codepoint; if (src->encoding == encoding) return Parrot_str_clone(interp, src); src_len = src->strlen; result = Parrot_gc_new_string_header(interp, 0); result->encoding = encoding; result->strlen = src_len; if (!src_len) return result; alloc_bytes = (UINTVAL)(src_len * avg_bytes); if (alloc_bytes < max_bytes) alloc_bytes = max_bytes; Parrot_gc_allocate_string_storage(interp, result, alloc_bytes); result->bufused = alloc_bytes; STRING_ITER_INIT(interp, &src_iter); STRING_ITER_INIT(interp, &dest_iter); while (src_iter.charpos < src_len) { const UINTVAL c = STRING_iter_get_and_advance(interp, src, &src_iter); const UINTVAL needed = dest_iter.bytepos + max_bytes; if (needed > result->bufused) { alloc_bytes = src_len - src_iter.charpos; alloc_bytes = (UINTVAL)(alloc_bytes * avg_bytes); alloc_bytes += needed; Parrot_gc_reallocate_string_storage(interp, result, alloc_bytes); result->bufused = alloc_bytes; } STRING_iter_set_and_advance(interp, result, &dest_iter, c); } result->bufused = dest_iter.bytepos; return result; }
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static STRING * utf16_to_encoding(PARROT_INTERP, ARGIN(const STRING *src)) { ASSERT_ARGS(utf16_to_encoding) STRING *result; UINTVAL src_len; src_len = STRING_length(src); if (STRING_max_bytes_per_codepoint(src) == 1) { result = Parrot_gc_new_string_header(interp, 0); result->encoding = Parrot_ucs2_encoding_ptr; result->bufused = 2 * src_len; result->strlen = src_len; if (src_len) { UINTVAL i; Parrot_UInt2 *p; Parrot_gc_allocate_string_storage(interp, result, 2 * src_len); p = (Parrot_UInt2 *)result->strstart; for (i = 0; i < src_len; ++i) { p[i] = (unsigned char)src->strstart[i]; } } } else if (src->encoding == Parrot_utf16_encoding_ptr || src->encoding == Parrot_ucs2_encoding_ptr) { /* we have to use clone instead of copy because the Unicode upcase * and downcase functions assume to get an unshared buffer */ result = Parrot_str_clone(interp, src); } else { result = encoding_to_encoding(interp, src, Parrot_utf16_encoding_ptr, 2.2); /* downgrade if possible */ if (result->bufused == result->strlen << 1) result->encoding = Parrot_ucs2_encoding_ptr; } return result; }