/* * Copyright 2009-2012 Michael Dalton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jtaint; import java.util.BitSet; public final class Taint implements Cloneable { private int len; private BitSet b; public Object clone() { Taint t; try { t = (Taint) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException("JDK Clone Error"); } t.b = (BitSet) b.clone(); t.verifyTaint(); return t; } private void verifyTaint() { if (b.nextSetBit(len) != -1) throw new IndexOutOfBoundsException("Invalid Taint: bit " + b.nextSetBit(len) + " set but length is " + len); } public Taint() { b = new BitSet(); } public Taint(BitSet b, int len) { this.b = (BitSet) b.clone(); this.len = len; verifyTaint(); } public Taint(boolean fill, int len) { b = new BitSet(fill ? len : 0); if (len > 0 && fill) { b.set(0,len); } this.len = len; verifyTaint(); } public Taint(char[] t, int len) { b = new BitSet(len); for (int i = 0; i < t.length; i++) for (int j = 0; j < 16; j++) if ((t[i] & (1 << j)) != 0) b.set(i * 16 + j); if (t.length != (len + 15)/16) throw new IllegalArgumentException("invalid taint"); this.len = len; verifyTaint(); } public Taint setLength(int newLength) throws IllegalArgumentException { if (newLength < 0) throw new IllegalArgumentException("negative len"); if (newLength < len) b.clear(newLength, len); len = newLength; verifyTaint(); return this; } public void set(int index) throws IllegalArgumentException { if (index >= len || index < 0) throw new IllegalArgumentException("invalid index"); b.set(index); } public void set(int fromIndex, int toIndex) throws IllegalArgumentException { if (fromIndex > toIndex || toIndex >= len || (fromIndex|toIndex) < 0) throw new IllegalArgumentException("invalid index"); b.set(fromIndex, toIndex); } public void clear(int index) throws IllegalArgumentException { if (index >= len || index < 0) throw new IllegalArgumentException("invalid index"); b.clear(index); } public void clear(int fromIndex, int toIndex) throws IllegalArgumentException { if (fromIndex > toIndex || toIndex >= len || (fromIndex|toIndex) < 0) throw new IllegalArgumentException("invalid index"); b.clear(fromIndex, toIndex); } public boolean get(int index) throws IllegalArgumentException { if (index >= len || index < 0) throw new IllegalArgumentException("invalid index"); return b.get(index); } public Taint subset(int beginIndex, int endIndex) throws IllegalArgumentException { int newLen = endIndex - beginIndex; if (beginIndex > endIndex || endIndex > len || (beginIndex|endIndex) < 0) throw new IllegalArgumentException("invalid index"); b.clear(0, beginIndex); for (int i = b.nextSetBit(beginIndex); i >= 0 && i < endIndex; i = b.nextSetBit(i+1)) { b.clear(i); b.set(i - beginIndex); } b.clear(endIndex, len); len = newLen; verifyTaint(); return this; } public Taint delete(int beginIndex, int endIndex) throws IllegalArgumentException { int remlen; if (beginIndex < 0 || beginIndex > endIndex || beginIndex > len) throw new IllegalArgumentException("invalid index"); if (endIndex > len) endIndex = len; remlen = endIndex - beginIndex; b.clear(beginIndex, endIndex); for (int i = b.nextSetBit(endIndex); i >= 0; i = b.nextSetBit(i+1)) { b.clear(i); b.set(i-remlen); } len -= remlen; verifyTaint(); return this; } public Taint append(Taint t) { BitSet tb = t.asBitSet(); for (int i = tb.nextSetBit(0); i >= 0; i = tb.nextSetBit(i+1)) b.set(len + i); len += t.len; verifyTaint(); return this; } public Taint insert(int offset, Taint t) throws IllegalArgumentException { /* Explicitly allow offset == len, which makes this an append */ if (offset > len || offset < 0) throw new IllegalArgumentException("invalid offset"); int olen = t.len; for (int i = len - 1; i >= offset; i--) { if (b.get(i)) { b.clear(i); b.set(i + olen); } } BitSet tb = t.asBitSet(); for (int i = tb.nextSetBit(0); i >= 0; i = tb.nextSetBit(i+1)) b.set(offset + i); len += olen; verifyTaint(); return this; } public Taint insertUntainted(int offset, int olen) throws IllegalArgumentException { if (offset > len || offset < 0) throw new IllegalArgumentException("invalid offset"); for (int i = len - 1; i >= offset; i--) { if (b.get(i)) { b.clear(i); b.set(i + olen); } } len += olen; verifyTaint(); return this; } public Taint reverse() { for (int i =0, j = len-1; i < j; i++, j--) { boolean t = b.get(i); b.set(i,b.get(j)); b.set(j,t); } verifyTaint(); return this; } public void getTaintAsChars(char[] dst, int dstBegin) { for (int i = b.nextSetBit(0); i >= 0; i = b.nextSetBit(i+1)) dst[dstBegin + i/16] |= (char) (1 << (i & 15)); } public boolean isTainted() { return b.cardinality() != 0; } public int cardinality() { return b.cardinality(); } public int length() { return len; } public BitSet asBitSet() { return b; } public String toString() { return "[tainted: " + isTainted() + "]" + "[length: " + len + "] " + b.toString(); } }