151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/* 251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. 351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it 651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as 751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation. Oracle designates this 851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided 951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code. 1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT 1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that 1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code). 1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version 1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation, 1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any 2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions. 2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage java.security; 2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.nio.ByteBuffer; 2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.security.jca.JCAUtil; 3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/** 3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) 3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * for the <code>MessageDigest</code> class, which provides the functionality 3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * of a message digest algorithm, such as MD5 or SHA. Message digests are 3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * secure one-way hash functions that take arbitrary-sized data and output a 3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * fixed-length hash value. 3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p> All the abstract methods in this class must be implemented by a 4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * cryptographic service provider who wishes to supply the implementation 4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * of a particular message digest algorithm. 4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p> Implementations are free to implement the Cloneable interface. 4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author Benjamin Renaud 4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see MessageDigest 4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic abstract class MessageDigestSpi { 5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // for re-use in engineUpdate(ByteBuffer input) 5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private byte[] tempArray; 5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns the digest length in bytes. 5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>This concrete method has been added to this previously-defined 6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * abstract class. (For backwards compatibility, it cannot be abstract.) 6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>The default behavior is to return 0. 6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>This method may be overridden by a provider to return the digest 6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * length. 6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return the digest length in bytes. 6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @since 1.2 7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected int engineGetDigestLength() { 7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return 0; 7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Updates the digest using the specified byte. 7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param input the byte to use for the update. 7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected abstract void engineUpdate(byte input); 8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Updates the digest using the specified array of bytes, 8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * starting at the specified offset. 8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param input the array of bytes to use for the update. 8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param offset the offset to start from in the array of bytes. 8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param len the number of bytes to use, starting at 9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>offset</code>. 9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected abstract void engineUpdate(byte[] input, int offset, int len); 9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Update the digest using the specified ByteBuffer. The digest is 9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * updated using the <code>input.remaining()</code> bytes starting 9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * at <code>input.position()</code>. 9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Upon return, the buffer's position will be equal to its limit; 10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * its limit will not have changed. 10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param input the ByteBuffer 10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @since 1.5 10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected void engineUpdate(ByteBuffer input) { 10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (input.hasRemaining() == false) { 10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return; 10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (input.hasArray()) { 11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski byte[] b = input.array(); 11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int ofs = input.arrayOffset(); 11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int pos = input.position(); 11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int lim = input.limit(); 11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski engineUpdate(b, ofs + pos, lim - pos); 11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski input.position(lim); 11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int len = input.remaining(); 11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int n = JCAUtil.getTempArraySize(len); 11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if ((tempArray == null) || (n > tempArray.length)) { 12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski tempArray = new byte[n]; 12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (len > 0) { 12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int chunk = Math.min(len, tempArray.length); 12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski input.get(tempArray, 0, chunk); 12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski engineUpdate(tempArray, 0, chunk); 12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski len -= chunk; 12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Completes the hash computation by performing final 13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * operations such as padding. Once <code>engineDigest</code> has 13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * been called, the engine should be reset (see 13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * {@link #engineReset() engineReset}). 13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Resetting is the responsibility of the 13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * engine implementor. 13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return the array of bytes for the resulting hash value. 14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected abstract byte[] engineDigest(); 14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Completes the hash computation by performing final 14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * operations such as padding. Once <code>engineDigest</code> has 14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * been called, the engine should be reset (see 14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * {@link #engineReset() engineReset}). 14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Resetting is the responsibility of the 14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * engine implementor. 15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This method should be abstract, but we leave it concrete for 15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * binary compatibility. Knowledgeable providers should override this 15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * method. 15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param buf the output buffer in which to store the digest 15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param offset offset to start from in the output buffer 15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @param len number of bytes within buf allotted for the digest. 16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Both this default implementation and the SUN provider do not 16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * return partial digests. The presence of this parameter is solely 16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * for consistency in our API's. If the value of this parameter is less 16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * than the actual digest length, the method will throw a DigestException. 16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This parameter is ignored if its value is greater than or equal to 16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the actual digest length. 16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return the length of the digest stored in the output buffer. 16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception DigestException if an error occurs. 17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @since 1.2 17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected int engineDigest(byte[] buf, int offset, int len) 17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throws DigestException { 17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski byte[] digest = engineDigest(); 17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (len < digest.length) 17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new DigestException("partial digests not returned"); 17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (buf.length - offset < digest.length) 18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new DigestException("insufficient space in the output " 18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski + "buffer to store the digest"); 18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski System.arraycopy(digest, 0, buf, offset, digest.length); 18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return digest.length; 18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Resets the digest for further use. 18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected abstract void engineReset(); 19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Returns a clone if the implementation is cloneable. 19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @return a clone if the implementation is cloneable. 19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @exception CloneNotSupportedException if this is called on an 19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * implementation that does not support <code>Cloneable</code>. 19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public Object clone() throws CloneNotSupportedException { 20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (this instanceof Cloneable) { 20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return super.clone(); 20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski throw new CloneNotSupportedException(); 20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski} 207