001: package com.quadcap.util;
002:
003: /* Copyright 1997 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.util.Comparator;
042:
043: /**
044: * This class implements a comparator for octet strings.
045: *
046: * @author Stan Bailes
047: */
048: public class OctetComparator implements Comparator {
049: boolean reverse = false;
050: boolean casemap = false;
051:
052: static OctetComparator cmp = new OctetComparator();
053: static OctetComparator casecmp = new OctetComparator(true, false);
054:
055: /**
056: * Construct a new octet comparator.
057: */
058: public OctetComparator() {
059: }
060:
061: public OctetComparator(boolean casemap, boolean reverse) {
062: this .casemap = casemap;
063: this .reverse = reverse;
064: }
065:
066: /**
067: * Ordering: is object 'a' <i>less, equal, or greater</i> than object 'b'?
068: *
069: * <p>(From the ACAP draft: draft-ietf-acap-spec-06.txt)
070: *
071: * <p>Ordering comparators can determine the ordinal precedence of any
072: * two values. When used for ordering, a comparator's name can be
073: * prefixed with "+" or "-" to indicate that the ordering should be
074: * normal order or reversed order respectively. If no prefix is
075: * included, "+" is assumed.
076: *
077: * <p>A comparator may designate certain values as having
078: * an undefined ordinal precedence. Such values collate with equal
079: * value after all other values regardless of whether normal or reverse
080: * ordering is used.
081: *
082: * @param a the first object to compare
083: * @param b the second object
084: * @return if a < b return -1 else if a > b return 1 else return 0
085: */
086: public int compare(Object a, Object b) {
087: OctetString oa = (OctetString) a;
088: OctetString ob = (OctetString) b;
089:
090: int before = reverse ? 1 : -1;
091: int after = 0 - before;
092:
093: byte[] va = getBytes(oa);
094: byte[] vb = getBytes(ob);
095: int i = 0;
096: while (i < va.length && i < vb.length) {
097: if (va[i] < vb[i])
098: return before;
099: if (va[i] > vb[i])
100: return after;
101: i++;
102: }
103: if (i < vb.length)
104: return before;
105: if (i < va.length)
106: return after;
107: return 0;
108: }
109:
110: /**
111: * Determine if the search value is a prefix of the object being
112: * searched. In the case of a prefix search on a multi-value,
113: * the match is successful if the value is a prefix of any one of
114: * the muliple values.
115: *
116: * @param obj the "first" object to compare, normally the candidate
117: * object in a SEARCH operation.
118: * @param val the "second" object, normally the constant value
119: * specified in the SEARCH operation.
120: * @return true if <b>val</b> is a prefix of <b>obj</b>.
121: */
122: public boolean prefixMatch(OctetString obj, OctetString val) {
123: byte[] va = getBytes(val);
124: byte[] vb = getBytes(obj);
125: if (va.length > vb.length)
126: return false;
127: for (int i = 0; i < va.length; i++) {
128: if (va[i] != vb[i])
129: return false;
130: }
131: return true;
132: }
133:
134: /**
135: * Determine if the search value is a substring of the object being
136: * searched. In the case of a substring search on a multi-value,
137: * the match is successful if the value is a substring of any one of
138: * the muliple values.
139: *
140: * @param obj the "first" object to compare, normally the candidate
141: * object in a SEARCH operation.
142: * @param val the "second" object, normally the constant value
143: * specified in the SEARCH operation.
144: * @return true if <b>val</b> is a substring of <b>obj</b>.
145: */
146: public boolean substringMatch(OctetString obj, OctetString val) {
147: byte[] va = getBytes(obj);
148: byte[] vb = getBytes(val);
149: int left = va.length - vb.length;
150: for (int i = 0; i <= left; i++) {
151: boolean match = true;
152: for (int j = 0; match && j < vb.length; j++) {
153: match = va[i + j] == vb[j];
154: }
155: if (match)
156: return true;
157: }
158: return false;
159: }
160:
161: /**
162: * Determine if the search value matches a glob-style pattern.
163: *
164: * @param obj the object to compare.
165: * @param pattern the pattern
166: * @return true if <b>obj</b> matches the pattern specified by
167: * <b>pattern</b>.
168: */
169: public boolean patternMatch(OctetString obj, OctetString pattern) {
170: byte[] va = getBytes(obj);
171: byte[] vb = getBytes(pattern);
172: return pMatch(va, 0, vb, 0);
173: }
174:
175: boolean pMatch(byte[] va, int a, byte[] vb, int b) {
176: while (b < vb.length) {
177: byte p = vb[b++];
178: switch (p) {
179: case (byte) '*':
180: if (a >= va.length || b >= vb.length)
181: return true;
182: while (a < va.length) {
183: if (pMatch(va, a++, vb, b))
184: return true;
185: }
186: return false;
187: case (byte) '?':
188: if (a++ >= va.length)
189: return false;
190: break;
191: case (byte) '\\':
192: if (b >= vb.length)
193: return false;
194: p = vb[b++];
195: // fall through...
196: default:
197: if (a >= va.length)
198: return false;
199: if (va[a++] != p)
200: return false;
201: }
202: }
203: return a >= va.length;
204: }
205:
206: int pMatchOrder(byte[] va, int a, byte[] vb, int b) {
207: int ret = 0;
208: while (b < vb.length) {
209: byte p = vb[b++];
210: switch (p) {
211: case (byte) '*':
212: while (a < va.length) {
213: ret = pMatchOrder(va, a++, vb, b);
214: if (ret == 0)
215: return ret;
216: }
217: return ret;
218: case (byte) '?':
219: if (a++ >= va.length)
220: return -1;
221: break;
222: case (byte) '\\':
223: if (b >= vb.length)
224: return 1;
225: p = vb[b++];
226: // fall through...
227: default:
228: if (a >= va.length)
229: return -1;
230: byte q = va[a++];
231: if (q < p)
232: return -1;
233: if (q > p)
234: return 1;
235: }
236: }
237: return a >= va.length ? 0 : 1;
238: }
239:
240: /**
241: * The layer above which "i;octet" and "i;ascii-casemap" are the
242: * same comparator.
243: *
244: * @param obj the object whose bytes we want.
245: */
246: byte[] getBytes(OctetString obj) {
247: byte[] b = obj.getBytes();
248: if (casemap) {
249: byte[] cb = new byte[b.length];
250: for (int i = 0; i < b.length; i++) {
251: byte c = b[i];
252: if (c >= 'a' && c <= 'z')
253: cb[i] = (byte) (c - 32);
254: else
255: cb[i] = c;
256: }
257: b = cb;
258: }
259: return b;
260: }
261: }
|