/* * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.joni; import org.jcodings.Encoding; import org.joni.exception.ErrorMessages; import org.joni.exception.ValueException; public final class CodeRangeBuffer { private static final int INIT_MULTI_BYTE_RANGE_SIZE = 5; private static final int ALL_MULTI_BYTE_RANGE = 0x7fffffff; int[]p; int used; public CodeRangeBuffer(int[]ranges) { p = ranges; used = ranges[0] + 1; } public CodeRangeBuffer() { p = new int[INIT_MULTI_BYTE_RANGE_SIZE]; writeCodePoint(0, 0); } public int[]getCodeRange() { return p; } private CodeRangeBuffer(CodeRangeBuffer orig) { p = new int[orig.p.length]; System.arraycopy(orig.p, 0, p, 0, p.length); used = orig.used; } public String toString() { StringBuilder buf = new StringBuilder(); buf.append("CodeRange"); buf.append("\n used: " + used); buf.append("\n code point: " + p[0]); buf.append("\n ranges: "); for (int i=0; i 0 && i % 6 == 0) buf.append("\n "); } return buf.toString(); } private static String rangeNumToString(int num){ return "0x" + Integer.toString(num, 16); } public void expand(int low) { int length = p.length; do { length <<= 1; } while (length < low); int[]tmp = new int[length]; System.arraycopy(p, 0, tmp, 0, used); p = tmp; } public void ensureSize(int size) { int length = p.length; while (length < size ) { length <<= 1; } if (p.length != length) { int[]tmp = new int[length]; System.arraycopy(p, 0, tmp, 0, used); p = tmp; } } private void moveRight(int from, int to, int n) { if (to + n > p.length) expand(to + n); System.arraycopy(p, from, p, to, n); if (to + n > used) used = to + n; } protected void moveLeft(int from, int to, int n) { System.arraycopy(p, from, p, to, n); } private void moveLeftAndReduce(int from, int to) { System.arraycopy(p, from, p, to, used - from); used -= from - to; } public void writeCodePoint(int pos, int b) { int u = pos + 1; if (p.length < u) expand(u); p[pos] = b; if (used < u) used = u; } public CodeRangeBuffer clone() { return new CodeRangeBuffer(this); } // ugly part: these methods should be made OO // add_code_range_to_buf public static CodeRangeBuffer addCodeRangeToBuff(CodeRangeBuffer pbuf, int from, int to) { if (from > to) { int n = from; from = to; to = n; } if (pbuf == null) pbuf = new CodeRangeBuffer(); // move to CClassNode int[]p = pbuf.p; int n = p[0]; int low = 0; int bound = n; while (low < bound) { int x = (low + bound) >>> 1; if (from > p[x * 2 + 2]) { low = x + 1; } else { bound = x; } } int high = low; bound = n; while (high < bound) { int x = (high + bound) >>> 1; if (to >= p[x * 2 + 1] - 1) { high = x + 1; } else { bound = x; } } int incN = low + 1 - high; if (n + incN > Config.MAX_MULTI_BYTE_RANGES_NUM) throw new ValueException(ErrorMessages.ERR_TOO_MANY_MULTI_BYTE_RANGES); if (incN != 1) { if (from > p[low * 2 + 1]) from = p[low * 2 + 1]; if (to < p[(high - 1) * 2 + 2]) to = p[(high - 1) * 2 + 2]; } if (incN != 0 && high < n) { int fromPos = 1 + high * 2; int toPos = 1 + (low + 1) * 2; int size = (n - high) * 2; if (incN > 0) { pbuf.moveRight(fromPos, toPos, size); } else { pbuf.moveLeftAndReduce(fromPos, toPos); } } int pos = 1 + low * 2; // pbuf.ensureSize(pos + 2); pbuf.writeCodePoint(pos, from); pbuf.writeCodePoint(pos + 1, to); n += incN; pbuf.writeCodePoint(0, n); return pbuf; } // add_code_range, be aware of it returning null! public static CodeRangeBuffer addCodeRange(CodeRangeBuffer pbuf, ScanEnvironment env, int from, int to) { if (from >to) { if (env.syntax.allowEmptyRangeInCC()) { return pbuf; } else { throw new ValueException(ErrorMessages.ERR_EMPTY_RANGE_IN_CHAR_CLASS); } } return addCodeRangeToBuff(pbuf, from, to); } // SET_ALL_MULTI_BYTE_RANGE protected static CodeRangeBuffer setAllMultiByteRange(Encoding enc, CodeRangeBuffer pbuf) { return addCodeRangeToBuff(pbuf, enc.mbcodeStartPosition(), ALL_MULTI_BYTE_RANGE); } // ADD_ALL_MULTI_BYTE_RANGE public static CodeRangeBuffer addAllMultiByteRange(Encoding enc, CodeRangeBuffer pbuf) { if (!enc.isSingleByte()) return setAllMultiByteRange(enc, pbuf); return pbuf; } // not_code_range_buf public static CodeRangeBuffer notCodeRangeBuff(Encoding enc, CodeRangeBuffer bbuf) { CodeRangeBuffer pbuf = null; if (bbuf == null) return setAllMultiByteRange(enc, pbuf); int[]p = bbuf.p; int n = p[0]; if (n <= 0) return setAllMultiByteRange(enc, pbuf); int pre = enc.mbcodeStartPosition(); int from; int to = 0; for (int i=0; i to1) break; } if (from1 <= to1) { pbuf = addCodeRangeToBuff(pbuf, from1, to1); } return pbuf; } // and_code_range_buf public static CodeRangeBuffer andCodeRangeBuff(CodeRangeBuffer bbuf1, boolean not1, CodeRangeBuffer bbuf2, boolean not2) { CodeRangeBuffer pbuf = null; if (bbuf1 == null) { if (not1 && bbuf2 != null) return bbuf2.clone(); /* not1 != 0 -> not2 == 0 */ return null; } else if (bbuf2 == null) { if (not2) return bbuf1.clone(); return null; } if (not1) { CodeRangeBuffer tbuf; boolean tnot; // swap tnot = not1; not1 = not2; not2 = tnot; tbuf = bbuf1; bbuf1 = bbuf2; bbuf2 = tbuf; } int[]p1 = bbuf1.p; int n1 = p1[0]; int[]p2 = bbuf2.p; int n2 = p2[0]; if (!not2 && !not1) { /* 1 AND 2 */ for (int i=0; i to1) break; if (to2 < from1) continue; int from = from1 > from2 ? from1 : from2; int to = to1 < to2 ? to1 : to2; pbuf = addCodeRangeToBuff(pbuf, from, to); } } } else if (!not1) { /* 1 AND (not 2) */ for (int i=0; i