ByteList replList = replStr.value;
if (replList.getRealSize() == 0) return delete_bang19(context, src);
RubyString srcStr = src.convertToString();
ByteList srcList = srcStr.value;
Encoding e1 = checkEncoding(srcStr);
Encoding e2 = checkEncoding(replStr);
Encoding enc = e1 == e2 ? e1 : srcStr.checkEncoding(replStr);
int cr = getCodeRange();
final TR trSrc = new TR(srcList);
boolean cflag = false;
if (value.getRealSize() > 1) {
if (enc.isAsciiCompatible()) {
if (trSrc.buf.length > 0 && (trSrc.buf[trSrc.p] & 0xff) == '^' && trSrc.p + 1 < trSrc.pend) {
cflag = true;
trSrc.p++;
}
} else {
int cl = StringSupport.preciseLength(enc, trSrc.buf, trSrc.p, trSrc.pend);
if (enc.mbcToCode(trSrc.buf, trSrc.p, trSrc.pend) == '^' && trSrc.p + cl < trSrc.pend) {
cflag = true;
trSrc.p += cl;
}
}
}
boolean singlebyte = true;
int c;
final int[]trans = new int[TRANS_SIZE];
IntHash<Integer> hash = null;
final TR trRepl = new TR(replList);
if (cflag) {
for (int i=0; i<TRANS_SIZE; i++) trans[i] = 1;
while ((c = trNext(trSrc, runtime, enc)) >= 0) {
if (c < TRANS_SIZE) {
trans[c & 0xff] = -1;
} else {
if (hash == null) hash = new IntHash<Integer>();
hash.put(c, 1); // QTRUE
}
}
while ((c = trNext(trRepl, runtime, enc)) >= 0) {} /* retrieve last replacer */
int last = trRepl.now;
for (int i=0; i<TRANS_SIZE; i++) {
if (trans[i] >= 0) trans[i] = last;
}
} else {
for (int i=0; i<TRANS_SIZE; i++) trans[i] = -1;
while ((c = trNext(trSrc, runtime, enc)) >= 0) {
int r = trNext(trRepl, runtime, enc);
if (r == -1) r = trRepl.now;
if (c < TRANS_SIZE) {
trans[c & 0xff] = r;
if (r > TRANS_SIZE - 1) singlebyte = false;
} else {
if (hash == null) hash = new IntHash<Integer>();
hash.put(c, r);
}
}
}
if (cr == CR_VALID) cr = CR_7BIT;
modifyAndKeepCodeRange();
int s = value.getBegin();
int send = s + value.getRealSize();
byte sbytes[] = value.getUnsafeBytes();
int max = value.getRealSize();
boolean modify = false;
int last = -1;
int clen, tlen, c0;
if (sflag) {
int save = -1;
byte[]buf = new byte[max];
int t = 0;
while (s < send) {
boolean mayModify = false;
c0 = c = codePoint(runtime, e1, sbytes, s, send);
clen = codeLength(runtime, e1, c);
tlen = enc == e1 ? clen : codeLength(runtime, enc, c);
s += clen;
c = trCode(c, trans, hash, cflag, last);
if (c != -1) {
if (save == c) {
if (cr == CR_7BIT && !Encoding.isAscii(c)) cr = CR_VALID;
continue;
}
save = c;
tlen = codeLength(runtime, enc, c);
modify = true;
} else {
save = -1;
c = c0;
if (enc != e1) mayModify = true;
}
while (t + tlen >= max) {
max <<= 1;
byte[]tbuf = new byte[max];
System.arraycopy(buf, 0, tbuf, 0, buf.length);
buf = tbuf;
}
enc.codeToMbc(c, buf, t);
if (mayModify && (tlen == 1 ? sbytes[s] != buf[t] : ByteList.memcmp(sbytes, s, buf, t, tlen) != 0)) modify = true;
if (cr == CR_7BIT && !Encoding.isAscii(c)) cr = CR_VALID;
t += tlen;
}
value.setUnsafeBytes(buf);
value.setRealSize(t);
} else if (enc.isSingleByte() || (singlebyte && hash == null)) {
while (s < send) {
c = sbytes[s] & 0xff;
if (trans[c] != -1) {
if (!cflag) {
c = trans[c];
sbytes[s] = (byte)c;
} else {
sbytes[s] = (byte)last;
}
modify = true;
}
if (cr == CR_7BIT && !Encoding.isAscii(c)) cr = CR_VALID;
s++;
}
} else {
max += max >> 1;
byte[]buf = new byte[max];
int t = 0;
while (s < send) {
boolean mayModify = false;
c0 = c = codePoint(runtime, e1, sbytes, s, send);
clen = codeLength(runtime, e1, c);
tlen = enc == e1 ? clen : codeLength(runtime, enc, c);
c = trCode(c, trans, hash, cflag, last);
if (c != -1) {
tlen = codeLength(runtime, enc, c);
modify = true;
} else {
c = c0;
if (enc != e1) mayModify = true;
}
while (t + tlen >= max) {
max <<= 1;
byte[]tbuf = new byte[max];
System.arraycopy(buf, 0, tbuf, 0, buf.length);
buf = tbuf;
}
enc.codeToMbc(c, buf, t);
if (mayModify && (tlen == 1 ? sbytes[s] != buf[t] : ByteList.memcmp(sbytes, s, buf, t, tlen) != 0)) modify = true;
if (cr == CR_7BIT && !Encoding.isAscii(c)) cr = CR_VALID;
s += clen;
t += tlen;