001    /*
002     * Copyright 2008-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2016 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.ldap.matchingrules;
022    
023    
024    
025    import com.unboundid.asn1.ASN1OctetString;
026    import com.unboundid.ldap.sdk.LDAPException;
027    
028    
029    
030    /**
031     * This class provides a common matching rule framework that may be extended by
032     * matching rule implementations in which equality, ordering, and substring
033     * matching can all be made based on byte-for-byte comparisons of the normalized
034     * value, for values that are considered acceptable by the
035     * {@code MatchingRule#normalize} and {@code MatchingRule#normalizeSubstring}
036     * methods.
037     */
038    public abstract class SimpleMatchingRule
039           extends MatchingRule
040    {
041      /**
042       * The serial version UID for this serializable class.
043       */
044      private static final long serialVersionUID = -7221506185552250694L;
045    
046    
047    
048      /**
049       * {@inheritDoc}
050       */
051      @Override()
052      public boolean valuesMatch(final ASN1OctetString value1,
053                                 final ASN1OctetString value2)
054             throws LDAPException
055      {
056        return normalize(value1).equals(normalize(value2));
057      }
058    
059    
060    
061      /**
062       * {@inheritDoc}
063       */
064      @Override()
065      public boolean matchesSubstring(final ASN1OctetString value,
066                                      final ASN1OctetString subInitial,
067                                      final ASN1OctetString[] subAny,
068                                      final ASN1OctetString subFinal)
069             throws LDAPException
070      {
071        final byte[] normValue = normalize(value).getValue();
072    
073        int pos = 0;
074        if (subInitial != null)
075        {
076          final byte[] normSubInitial =
077               normalizeSubstring(subInitial, SUBSTRING_TYPE_SUBINITIAL).getValue();
078          if (normValue.length < normSubInitial.length)
079          {
080            return false;
081          }
082    
083          for (int i=0; i < normSubInitial.length; i++)
084          {
085            if (normValue[i] != normSubInitial[i])
086            {
087              return false;
088            }
089          }
090    
091          pos = normSubInitial.length;
092        }
093    
094        if (subAny != null)
095        {
096          final byte[][] normSubAny = new byte[subAny.length][];
097          for (int i=0; i < subAny.length; i++)
098          {
099            normSubAny[i] =
100                 normalizeSubstring(subAny[i],SUBSTRING_TYPE_SUBANY).getValue();
101          }
102    
103          for (final byte[] b : normSubAny)
104          {
105            if (b.length == 0)
106            {
107              continue;
108            }
109    
110            boolean match = false;
111            final int subEndLength = normValue.length - b.length;
112            while (pos <= subEndLength)
113            {
114              match = true;
115              for (int i=0; i < b.length; i++)
116              {
117                if (normValue[pos+i] != b[i])
118                {
119                  match = false;
120                  break;
121                }
122              }
123    
124              if (match)
125              {
126                pos += b.length;
127                break;
128              }
129              else
130              {
131                pos++;
132              }
133            }
134    
135            if (! match)
136            {
137              return false;
138            }
139          }
140        }
141    
142        if (subFinal != null)
143        {
144          final byte[] normSubFinal =
145               normalizeSubstring(subFinal, SUBSTRING_TYPE_SUBFINAL).getValue();
146          int finalStartPos = normValue.length - normSubFinal.length;
147          if (finalStartPos < pos)
148          {
149            return false;
150          }
151    
152          for (int i=0; i < normSubFinal.length; i++,finalStartPos++)
153          {
154            if (normValue[finalStartPos] != normSubFinal[i])
155            {
156              return false;
157            }
158          }
159        }
160    
161        return true;
162      }
163    
164    
165    
166      /**
167       * {@inheritDoc}
168       */
169      @Override()
170      public int compareValues(final ASN1OctetString value1,
171                               final ASN1OctetString value2)
172             throws LDAPException
173      {
174        final byte[] normValue1 = normalize(value1).getValue();
175        final byte[] normValue2 = normalize(value2).getValue();
176    
177        final int minLength = Math.min(normValue1.length, normValue2.length);
178        for (int i=0; i < minLength; i++)
179        {
180          final int b1 = normValue1[i] & 0xFF;
181          final int b2 = normValue2[i] & 0xFF;
182    
183          if (b1 < b2)
184          {
185            return -1;
186          }
187          else if (b1 > b2)
188          {
189            return 1;
190          }
191        }
192    
193        // If we've gotten here, then it means that all of the bytes they had in
194        // common are the same.  At this point, the shorter of the two should be
195        // ordered first, or return zero if they're the same length.
196        return normValue1.length - normValue2.length;
197      }
198    }