1   /* $RCSfile: PaddingDoubleBuffer.java,v $
2    * $Revision: 1.10 $
3    * $Date: 2002/11/23 11:09:57 $
4    * $Author: uwe_guenther $
5    * $State: Exp $
6    *
7    * Created on August 20, 2001 1:58 PM
8    *
9    * Copyright (C) 2001 Uwe Guenther <uwe@cscc.de>
10   *
11   * This file is part of the jhbci JCE-ServiceProvider. The jhbci JCE-
12   * ServiceProvider is a library, written in JavaTM, that should be 
13   * used in HBCI banking applications (clients and may be servers),
14   * to do cryptographic operations.
15   *
16   * The jhbci library is free software; you can redistribute it and/or
17   * modify it under the terms of the GNU Lesser General Public
18   * License as published by the Free Software Foundation; either
19   * version 2.1 of the License, or (at your option) any later version.
20   *
21   * The jhbci library is distributed in the hope that it will be useful,
22   * but WITHOUT ANY WARRANTY; without even the implied warranty of
23   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   * Lesser General Public License for more details.
25   *
26   * You should have received a copy of the GNU Lesser General Public
27   * License along with this library; if not, write to the Free Software
28   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29   *
30   */
31  
32  package de.cscc.crypto.provider;
33  
34  import javax.crypto.IllegalBlockSizeException;
35  
36  /** 
37   * PaddingDoubleBuffer Class.
38   *
39   * @author  <a href=mailto:uwe@cscc.de>Uwe G&uuml;nther</a>
40   * @version $Revision: 1.10 $
41   */
42  class PaddingDoubleBuffer implements Cloneable {
43      
44      /** The internal buffer. */    
45      private PaddingSingleBuffer buffer1;
46      
47      /** The internal buffer. */    
48      private PaddingSingleBuffer buffer2;    
49          
50      /** Don't create PaddingDoubleBuffer with default constructor. */
51      private PaddingDoubleBuffer() {}
52      
53      /** 
54       * Create a new buffer with size bytes.
55       * @param size the buffer length in bytes.
56       */    
57      public PaddingDoubleBuffer(int size) {
58          
59          this.buffer1 = new PaddingSingleBuffer(size);
60          this.buffer2 = new PaddingSingleBuffer(size);
61      }    
62  
63      /**
64       * Creates and returns a deep copy of this object.
65       *
66       * @return a clone of this instance.
67       * @see java.lang.Cloneable
68       * @exception CloneNotSupportedException if the object's class does not
69       *             support the <code>Cloneable</code> interface. Subclasses
70       *             that override the <code>clone</code> method can also
71       *             throw this exception to indicate that an instance cannot
72       *             be cloned. */
73      public Object clone() throws CloneNotSupportedException {
74  
75          //Create the new object "result".
76          PaddingDoubleBuffer result = (PaddingDoubleBuffer) super.clone();
77          
78          //Fix the shallow copies to deep copies
79          result.buffer1 = (PaddingSingleBuffer) this.buffer1.clone();
80          result.buffer2 = (PaddingSingleBuffer) this.buffer2.clone();
81          
82          //Return the new fixed object "result".
83          return result;
84      }
85      
86      /** 
87       * Indicates whether some other object is "equal to" this one.
88       *
89       * @param   obj   the reference object with which to compare.
90       * @return  <code>true</code> if this object is the same as the obj
91       *         argument; <code>false</code> otherwise.
92       * @see     #hashCode()
93       * @see     java.util.Hashtable
94       */
95      public boolean equals(Object obj) {
96          
97          //Only for performance.
98          if (this == obj) {
99              return true;
100         }
101         
102         //If obj == null then instanceof returns false, see JLS 15.20.2                   
103         if (!(obj instanceof PaddingDoubleBuffer)) {            
104             return false;
105         }
106         
107         PaddingDoubleBuffer other = (PaddingDoubleBuffer) obj;
108         return this.buffer1.equals(other.buffer1) &&
109                this.buffer2.equals(other.buffer2)  ;
110     }
111     
112     /**
113      * Returns a hash code value for the object. 
114      *
115      * @return  a hash code value for this object.
116      * @see     #equals(java.lang.Object)
117      * @see     java.util.Hashtable
118      */
119     public int hashCode() {
120        
121         int result = 17;
122         
123         result = 37*result + this.buffer1.hashCode();
124         result = 37*result + this.buffer2.hashCode();
125         
126         return result;
127     }
128     
129     /** 
130      * Returns a string representation of the object. 
131      *
132      * @return  a string representation of the object.
133      */
134     public String toString() {
135         
136         return "buffer1: [" + this.buffer1 + "] " +
137                "buffer2: [" + this.buffer2 + "]";
138     }
139     
140     /**
141      * Add a byte to the buffer.
142      * @param b the byte to add.
143      * @throws IllegalArgumentException if the internal buffer is full.
144      */    
145     public void add(byte b) throws IllegalArgumentException {
146         
147         if (this.buffer1.isFull() == false) {
148             this.buffer1.add(b);
149             return;
150         } 
151         
152         if (this.buffer2.isFull() == false) {
153             this.buffer2.add(b);
154             return;
155         }
156         
157         throw new IllegalArgumentException("Buffer is full.");
158     }
159     
160     /** Swaps the 2 internal buffers. */    
161     private void swapBuffer() {
162 
163         PaddingSingleBuffer swap = this.buffer1;
164         this.buffer1 = this.buffer2;
165         this.buffer2 = swap;
166     }
167     
168     /** 
169      * Indicates if the buffer is full.
170      * @return true if the buffer is full, false otherwise.
171      */    
172     public boolean hasEnoughBytes() {
173         
174          return this.buffer1.isFull() && (this.buffer2.hasBytes() > 0);
175     }    
176 
177 
178     /** 
179      * Returns a copy of the internal main buffer.
180      * @return the number off bytes that stored in output.
181      * @param output the output buffer.
182      * @param outputOffset the offset in output where output starts.
183      * @throws IllegalStateException if buffer2 is still empty.
184      * @throws IllegalBlockSizeException if the usable range is lesser than the
185      * initial size  with this buffer was constructed.
186      */    
187     public int fetch(byte[] output, int outputOffset) 
188             throws IllegalStateException, IllegalBlockSizeException {    
189         
190         if (hasEnoughBytes() == false) {
191             //Throw IllegalStateException if buffer2 is still empty.            
192             throw new IllegalStateException("Buffer has not enough bytes.");
193         }
194 
195         //If buffer1 is full and buffer2 contains 1 byte or more,
196         //return buffer1.
197         int returnValue = this.buffer1.fetch(output, outputOffset);
198         swapBuffer();
199         return returnValue;            
200     }        
201     
202     /** 
203      * Returns a copy of the internal backhand buffer .
204      * @return the number off bytes that stored in output.
205      * @param output a copy of the internal bachkhand buffer (fetch all bytes).
206      * @param outputOffset the offset in output where output starts.
207      * @throws IllegalStateException IllegalStateException if buffer2 
208      * is not empty.
209      * @throws IllegalBlockSizeException if the usable range is lesser than the
210      * initial size  with this buffer was constructed.
211      */    
212     public int finalFetch(byte[] output, int outputOffset) 
213             throws IllegalStateException, IllegalBlockSizeException {
214                 
215         if (hasEnoughBytes()) {
216             //Throw IllegalStateException if buffer2 is not empty.            
217             throw new IllegalStateException(
218                     "There are bytes to fetch with fetch(), " +
219                     " so invoke fetch() first.");
220         }        
221         
222         return this.buffer1.fetch(output, outputOffset);
223     }    
224     
225     /** 
226      * Returns the number of bytes that the buffer contains.
227      * @return the number of bytes that the buffer contains.
228      */    
229     public int hasBytes() {
230         
231         return this.buffer1.hasBytes() + this.buffer2.hasBytes();
232     }    
233 }
234