};
// transcode_loop
public static void transcodeLoop(ThreadContext context, byte[] inBytes, Ptr inPos, byte[] outBytes, Ptr outPos, int inStop, int _outStop, ByteList destination, ResizeFunction resizeFunction, byte[] sname, byte[] dname, int ecflags, IRubyObject ecopts) {
Ruby runtime = context.runtime;
EConv ec;
Ptr outStop = new Ptr(_outStop);
IRubyObject fallback = context.nil;
TranscodeFallback fallbackFunc = null;
ec = econvOpenOpts(context, sname, dname, ecflags, ecopts);
if (ec == null) {
throw econvOpenExc(context, sname, dname, ecflags);
}
if (!ecopts.isNil() && ecopts instanceof RubyHash) {
fallback = ((RubyHash)ecopts).op_aref(context, runtime.newSymbol("fallback"));
if (fallback instanceof RubyHash) {
fallbackFunc = HASH_FALLBACK;
} else if (fallback instanceof RubyProc) { // not quite same check as MRI
fallbackFunc = PROC_FALLBACK;
} else if (fallback instanceof RubyMethod) { // not quite same check as MRI
fallbackFunc = METHOD_FALLBACK;
} else {
fallbackFunc = AREF_FALLBACK;
}
}
Transcoding lastTC = ec.lastTranscoding;
int maxOutput = lastTC != null ? lastTC.transcoder.maxOutput : 1;
Ptr outStart = new Ptr(outPos.p);
// resume:
while (true) {
EConvResult ret = ec.convert(inBytes, inPos, inStop, outBytes, outPos, outStop.p, 0);
if (!fallback.isNil() && ret == EConvResult.UndefinedConversion) {
IRubyObject rep = RubyString.newStringNoCopy(
runtime,
new ByteList(
ec.lastError.getErrorBytes(),
ec.lastError.getErrorBytesP(),
ec.lastError.getErrorBytesLength(),
runtime.getEncodingService().findEncodingOrAliasEntry(ec.lastError.getSource()).getEncoding(),
false)
);
rep = fallbackFunc.call(context, fallback, rep);
if (!rep.isNil()) {
rep = rep.convertToString();
Encoding repEnc = ((RubyString)rep).getEncoding();
ByteList repByteList = ((RubyString)rep).getByteList();
ec.insertOutput(repByteList.getUnsafeBytes(), repByteList.begin(), repByteList.getRealSize(), repEnc.getName());
// TODO: check for too-large replacement
continue;
}
}
if (ret == EConvResult.InvalidByteSequence ||
ret == EConvResult.IncompleteInput ||
ret == EConvResult.UndefinedConversion) {
RaiseException re = makeEconvException(runtime, ec);
ec.close();
throw re;
}
if (ret == EConvResult.DestinationBufferFull) {
moreOutputBuffer(destination, resizeFunction, maxOutput, outStart, outPos, outStop);
outBytes = destination.getUnsafeBytes();
continue;
}
ec.close();
return;
}
}