Symbol* Converter::primitive_convert(STATE, Object* source, String* target, Fixnum* offset, Fixnum* size, Fixnum* options) { String* src = 0; if(!source->nil_p()) { if(!(src = try_as<String>(source))) { return force_as<Symbol>(Primitives::failure()); } } OnStack<3> os(state, source, src, target); const unsigned char* source_ptr = 0; const unsigned char* source_end = 0; native_int byte_offset = offset->to_native(); native_int byte_size = size->to_native(); retry: if(!converter_) { size_t num_converters = converters()->size(); converter_ = rb_econv_alloc(num_converters); for(size_t i = 0; i < num_converters; i++) { Transcoding* transcoding = as<Transcoding>(converters()->get(state, i)); rb_transcoder* tr = transcoding->get_transcoder(); if(rb_econv_add_transcoder_at(converter_, tr, i) == -1) { rb_econv_free(converter_); converter_ = NULL; return force_as<Symbol>(Primitives::failure()); } } } /* It would be nice to have a heuristic that avoids having to reconvert * after growing the destination buffer. This is complicated, however, as * a converter may contain more than one transcoder. So, the heuristic * would need to be transitive. This requires getting the encoding objects * for every stage of the converter to check the min/max byte values. */ if(byte_size == -1) { byte_size = src ? src->byte_size() : 4096; } int flags = converter_->flags = options->to_native(); if(!replacement()->nil_p()) { native_int byte_size = replacement()->byte_size(); char* buf = (char*)XMALLOC(byte_size + 1); strncpy(buf, replacement()->c_str(state), byte_size + 1); converter_->replacement_str = (const unsigned char*)buf; converter_->replacement_len = replacement()->byte_size(); String* name = replacement()->encoding()->name(); byte_size = name->byte_size(); buf = (char*)XMALLOC(byte_size + 1); strncpy(buf, name->c_str(state), byte_size + 1); converter_->replacement_enc = (const char*)buf; converter_->replacement_allocated = 1; size_t num_converters = replacement_converters()->size(); rb_econv_alloc_replacement_converters(converter_, num_converters / 2); for(size_t i = 0, k = 0; i < num_converters; k++, i += 2) { rb_econv_replacement_converters* repl_converter; repl_converter = converter_->replacement_converters + k; name = as<String>(replacement_converters()->get(state, i)); byte_size = name->byte_size(); buf = (char*)XMALLOC(byte_size + 1); strncpy(buf, name->c_str(state), byte_size + 1); repl_converter->destination_encoding_name = (const char*)buf; Array* trs = as<Array>(replacement_converters()->get(state, i + 1)); size_t num_transcoders = trs->size(); repl_converter->num_transcoders = num_transcoders; repl_converter->transcoders = ALLOC_N(rb_transcoder*, num_transcoders); for(size_t j = 0; j < num_transcoders; j++) { Transcoding* transcoding = as<Transcoding>(trs->get(state, j)); rb_transcoder* tr = transcoding->get_transcoder(); repl_converter->transcoders[j] = tr; } } }
Symbol* Converter::primitive_convert(STATE, Object* source, String* target, Fixnum* offset, Fixnum* size, Fixnum* options) { String* src = 0; if(!source->nil_p()) { if(!(src = try_as<String>(source))) { return force_as<Symbol>(Primitives::failure()); } } Converter* self = this; OnStack<4> os(state, self, source, src, target); const unsigned char* source_ptr = 0; const unsigned char* source_end = 0; native_int byte_offset = offset->to_native(); native_int byte_size = size->to_native(); retry: if(!self->converter_) { size_t num_converters = self->converters()->size(); self->set_converter(rb_econv_alloc(num_converters)); for(size_t i = 0; i < num_converters; i++) { Transcoding* transcoding = as<Transcoding>(self->converters()->get(state, i)); rb_transcoder* tr = transcoding->get_transcoder(); if(rb_econv_add_transcoder_at(self->converter_, tr, i) == -1) { rb_econv_free(self->get_converter()); self->set_converter(NULL); return force_as<Symbol>(Primitives::failure()); } } } /* It would be nice to have a heuristic that avoids having to reconvert * after growing the destination buffer. This is complicated, however, as * a converter may contain more than one transcoder. So, the heuristic * would need to be transitive. This requires getting the encoding objects * for every stage of the converter to check the min/max byte values. */ if(byte_size == -1) { byte_size = src ? src->byte_size() : 4096; } int flags = self->converter_->flags = options->to_native(); if(!self->replacement()->nil_p() && !self->converter_->replacement_str) { // First check the array's whether they exist so we don't // leak memory or create badly initialized C structures size_t num_converters = self->replacement_converters()->size(); for(size_t i = 0, k = 0; i < num_converters; k++, i += 2) { as<String>(self->replacement_converters()->get(state, i)); as<Array>(self->replacement_converters()->get(state, i + 1)); } native_int byte_size = self->replacement()->byte_size(); char* buf = (char*)XMALLOC(byte_size + 1); strncpy(buf, self->replacement()->c_str(state), byte_size + 1); self->converter_->replacement_str = (const unsigned char*)buf; self->converter_->replacement_len = self->replacement()->byte_size(); String* name = self->replacement()->encoding()->name(); byte_size = name->byte_size(); buf = (char*)XMALLOC(byte_size + 1); strncpy(buf, name->c_str(state), byte_size + 1); self->converter_->replacement_enc = (const char*)buf; self->converter_->replacement_allocated = 1; rb_econv_alloc_replacement_converters(self->converter_, num_converters / 2); for(size_t i = 0, k = 0; i < num_converters; k++, i += 2) { rb_econv_replacement_converters* repl_converter; repl_converter = self->converter_->replacement_converters + k; // We can use force_as here since we know type has been checked above name = force_as<String>(self->replacement_converters()->get(state, i)); byte_size = name->byte_size(); buf = (char*)XMALLOC(byte_size + 1); strncpy(buf, name->c_str(state), byte_size + 1); repl_converter->destination_encoding_name = (const char*)buf; Array* trs = force_as<Array>(replacement_converters()->get(state, i + 1)); size_t num_transcoders = trs->size(); repl_converter->num_transcoders = num_transcoders; repl_converter->transcoders = ALLOC_N(rb_transcoder*, num_transcoders); for(size_t j = 0; j < num_transcoders; j++) { Transcoding* transcoding = as<Transcoding>(trs->get(state, j)); rb_transcoder* tr = transcoding->get_transcoder(); repl_converter->transcoders[j] = tr; } } }
Symbol* Converter::primitive_convert(STATE, Object* source, String* target, Fixnum* offset, Fixnum* size, Fixnum* options) { String* src = 0; if(!source->nil_p()) { if(!(src = try_as<String>(source))) { return force_as<Symbol>(Primitives::failure()); } } if(!converter_) { size_t num_converters = converters()->size(); converter_ = rb_econv_alloc(num_converters); for(size_t i = 0; i < num_converters; i++) { Transcoding* transcoding = as<Transcoding>(converters()->get(state, i)); rb_transcoder* tr = transcoding->get_transcoder(); if(rb_econv_add_transcoder_at(converter_, tr, i) == -1) { rb_econv_free(converter_); converter_ = NULL; return force_as<Symbol>(Primitives::failure()); } } } if(!replacement()->nil_p()) { native_int byte_size = replacement()->byte_size(); char* buf = (char*)XMALLOC(byte_size + 1); strncpy(buf, replacement()->c_str(state), byte_size + 1); converter_->replacement_str = (const unsigned char*)buf; converter_->replacement_len = replacement()->byte_size(); String* name = replacement()->encoding()->name(); byte_size = name->byte_size(); buf = (char*)XMALLOC(byte_size + 1); strncpy(buf, name->c_str(state), byte_size + 1); converter_->replacement_enc = (const char*)buf; converter_->replacement_allocated = 1; size_t num_converters = replacement_converters()->size(); rb_econv_alloc_replacement_converters(converter_, num_converters / 2); for(size_t i = 0, k = 0; i < num_converters; k++, i += 2) { rb_econv_replacement_converters* repl_converter; repl_converter = converter_->replacement_converters + k; name = as<String>(replacement_converters()->get(state, i)); byte_size = name->byte_size(); buf = (char*)XMALLOC(byte_size + 1); strncpy(buf, name->c_str(state), byte_size + 1); repl_converter->destination_encoding_name = (const char*)buf; Array* trs = as<Array>(replacement_converters()->get(state, i + 1)); size_t num_transcoders = trs->size(); repl_converter->num_transcoders = num_transcoders; repl_converter->transcoders = ALLOC_N(rb_transcoder*, num_transcoders); for(size_t j = 0; j < num_transcoders; j++) { Transcoding* transcoding = as<Transcoding>(trs->get(state, j)); rb_transcoder* tr = transcoding->get_transcoder(); repl_converter->transcoders[j] = tr; } } }