From 9feea8b823c069addfda8b43e0c14c7f46d5be19 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Thu, 2 Mar 2006 09:33:42 +0000 Subject: 2006-03-02 Andrew John Hughes * Merge of HEAD-->generics-branch for the period between the 0.20 release and the tag generics-merge-20050225. --- .classpath | 4 +- .settings/org.eclipse.jdt.core.prefs | 14 +- AUTHORS | 1 + ChangeLog | 5647 +++++++ LICENSE | 46 + Makefile.am | 4 +- NEWS | 32 + configure.ac | 4 +- doc/README.jaxp | 27 + doc/api/Makefile.am | 1 + doc/unicode/SpecialCasing-4.0.0.txt | 256 + doc/unicode/UnicodeData-4.0.0.txt | 15100 +++++++++++++++++++ doc/vmintegration.texinfo | 89 +- doc/www.gnu.org/announce/20060113.wml | 289 + doc/www.gnu.org/downloads/downloads.wml | 14 +- doc/www.gnu.org/newsitems.txt | 5 + examples/Makefile.am | 5 +- .../examples/CORBA/swing/x5/PlayingDesk.java | 4 +- .../CORBA/swing/x5/_GameManagerImpl_Tie.java | 9 +- .../examples/CORBA/swing/x5/_PlayerImpl_Tie.java | 7 +- .../gnu/classpath/examples/swing/ButtonDemo.java | 35 +- .../gnu/classpath/examples/swing/ComboBoxDemo.java | 38 +- examples/gnu/classpath/examples/swing/Demo.java | 138 +- .../classpath/examples/swing/FileChooserDemo.java | 112 +- .../gnu/classpath/examples/swing/MiniDemo.java | 233 + .../classpath/examples/swing/ScrollBarDemo.java | 27 +- .../gnu/classpath/examples/swing/SliderDemo.java | 53 +- .../gnu/classpath/examples/swing/SpinnerDemo.java | 230 + .../gnu/classpath/examples/swing/TableDemo.java | 236 + .../classpath/examples/swing/TextFieldDemo.java | 41 +- external/Makefile.am | 2 +- external/relaxngDatatype/.cvsignore | 2 + external/relaxngDatatype/Makefile.am | 14 + external/relaxngDatatype/README.txt | 54 + external/relaxngDatatype/copying.txt | 30 + .../org/relaxng/datatype/Datatype.java | 237 + .../org/relaxng/datatype/DatatypeBuilder.java | 45 + .../org/relaxng/datatype/DatatypeException.java | 39 + .../org/relaxng/datatype/DatatypeLibrary.java | 37 + .../relaxng/datatype/DatatypeLibraryFactory.java | 26 + .../datatype/DatatypeStreamingValidator.java | 46 + .../org/relaxng/datatype/ValidationContext.java | 66 + .../datatype/helpers/DatatypeLibraryLoader.java | 262 + .../helpers/ParameterlessDatatypeBuilder.java | 42 + .../datatype/helpers/StreamingValidatorImpl.java | 55 + gnu/CORBA/IOR.java | 54 + gnu/CORBA/NamingService/NamingMap.java | 13 +- .../NamingService/NamingServiceTransient.java | 2 +- gnu/CORBA/NamingService/TransientContext.java | 35 +- gnu/classpath/ServiceFactory.java | 7 +- gnu/classpath/ServiceProviderLoadingAction.java | 6 +- gnu/classpath/debug/Component.java | 4 +- gnu/classpath/jdwp/Jdwp.java | 6 +- gnu/classpath/jdwp/event/EventRequest.java | 15 +- gnu/classpath/jdwp/id/JdwpId.java | 12 +- gnu/classpath/jdwp/id/ObjectId.java | 10 +- gnu/classpath/jdwp/id/ReferenceTypeId.java | 10 +- .../jdwp/processor/VirtualMachineCommandSet.java | 14 +- gnu/java/awt/peer/GLightweightPeer.java | 7 +- gnu/java/awt/peer/gtk/GtkButtonPeer.java | 7 +- gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java | 9 +- gnu/java/awt/peer/gtk/GtkCheckboxPeer.java | 57 +- gnu/java/awt/peer/gtk/GtkComponentPeer.java | 134 +- gnu/java/awt/peer/gtk/GtkContainerPeer.java | 13 +- gnu/java/awt/peer/gtk/GtkFramePeer.java | 13 +- gnu/java/awt/peer/gtk/GtkGenericPeer.java | 39 +- gnu/java/awt/peer/gtk/GtkImage.java | 20 +- gnu/java/awt/peer/gtk/GtkLabelPeer.java | 9 +- gnu/java/awt/peer/gtk/GtkListPeer.java | 9 +- gnu/java/awt/peer/gtk/GtkMenuBarPeer.java | 79 +- gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java | 59 +- gnu/java/awt/peer/gtk/GtkMenuItemPeer.java | 99 +- gnu/java/awt/peer/gtk/GtkMenuPeer.java | 32 +- gnu/java/awt/peer/gtk/GtkPanelPeer.java | 33 +- gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java | 7 +- gnu/java/awt/peer/gtk/GtkScrollbarPeer.java | 22 +- gnu/java/awt/peer/gtk/GtkTextAreaPeer.java | 6 +- gnu/java/awt/peer/gtk/GtkTextFieldPeer.java | 2 - gnu/java/awt/peer/gtk/GtkToolkit.java | 170 +- gnu/java/awt/peer/gtk/GtkWindowPeer.java | 54 +- gnu/java/awt/peer/swing/SwingButtonPeer.java | 224 + gnu/java/awt/peer/swing/SwingCanvasPeer.java | 64 + gnu/java/awt/peer/swing/SwingComponent.java | 89 + gnu/java/awt/peer/swing/SwingComponentPeer.java | 994 ++ gnu/java/awt/peer/swing/SwingContainerPeer.java | 241 + gnu/java/awt/peer/swing/SwingFramePeer.java | 196 + gnu/java/awt/peer/swing/SwingLabelPeer.java | 196 + gnu/java/awt/peer/swing/SwingMenuBarPeer.java | 295 + gnu/java/awt/peer/swing/SwingMenuItemPeer.java | 157 + gnu/java/awt/peer/swing/SwingMenuPeer.java | 284 + gnu/java/awt/peer/swing/SwingPanelPeer.java | 67 + gnu/java/awt/peer/swing/SwingTextFieldPeer.java | 367 + gnu/java/awt/peer/swing/SwingToolkit.java | 165 + gnu/java/awt/peer/swing/SwingWindowPeer.java | 72 + gnu/java/awt/peer/swing/package.html | 71 + gnu/java/beans/DefaultExceptionListener.java | 66 + .../beans/decoder/DefaultExceptionListener.java | 57 - gnu/java/lang/CharData.java | 2228 ++- gnu/java/net/CRLFInputStream.java | 19 +- gnu/java/net/LineInputStream.java | 31 +- gnu/java/net/protocol/file/Connection.java | 18 +- gnu/java/net/protocol/ftp/ActiveModeDTP.java | 1 + gnu/java/net/protocol/ftp/FTPURLConnection.java | 43 +- gnu/java/net/protocol/http/ChunkedInputStream.java | 31 +- gnu/java/net/protocol/http/HTTPConnection.java | 269 +- gnu/java/net/protocol/http/HTTPURLConnection.java | 71 +- gnu/java/net/protocol/http/Request.java | 30 +- gnu/java/net/protocol/http/Response.java | 24 +- gnu/java/nio/charset/Provider.java | 3 +- gnu/java/rmi/registry/RegistryImpl.java | 2 +- gnu/java/rmi/server/CombinedClassLoader.java | 149 + gnu/java/rmi/server/RMIObjectInputStream.java | 64 +- gnu/java/rmi/server/UnicastServerRef.java | 650 +- gnu/java/security/Properties.java | 374 + gnu/java/security/Registry.java | 455 + gnu/java/security/der/DERValue.java | 29 +- gnu/java/security/der/DERWriter.java | 10 +- gnu/java/security/hash/BaseHash.java | 206 + gnu/java/security/hash/HashFactory.java | 178 + gnu/java/security/hash/Haval.java | 759 + gnu/java/security/hash/IMessageDigest.java | 135 + gnu/java/security/hash/MD2.java | 301 + gnu/java/security/hash/MD4.java | 328 + gnu/java/security/hash/MD5.java | 365 + gnu/java/security/hash/RipeMD128.java | 291 + gnu/java/security/hash/RipeMD160.java | 328 + gnu/java/security/hash/Sha160.java | 308 + gnu/java/security/hash/Sha256.java | 278 + gnu/java/security/hash/Sha384.java | 322 + gnu/java/security/hash/Sha512.java | 322 + gnu/java/security/hash/Tiger.java | 943 ++ gnu/java/security/hash/Whirlpool.java | 626 + gnu/java/security/jce/hash/HavalSpi.java | 68 + gnu/java/security/jce/hash/MD2Spi.java | 69 + gnu/java/security/jce/hash/MD4Spi.java | 69 + gnu/java/security/jce/hash/MD5Spi.java | 68 + .../security/jce/hash/MessageDigestAdapter.java | 147 + gnu/java/security/jce/hash/RipeMD128Spi.java | 68 + gnu/java/security/jce/hash/RipeMD160Spi.java | 68 + gnu/java/security/jce/hash/Sha160Spi.java | 68 + gnu/java/security/jce/hash/Sha256Spi.java | 68 + gnu/java/security/jce/hash/Sha384Spi.java | 68 + gnu/java/security/jce/hash/Sha512Spi.java | 68 + gnu/java/security/jce/hash/TigerSpi.java | 69 + gnu/java/security/jce/hash/WhirlpoolSpi.java | 68 + gnu/java/security/jce/prng/HavalRandomSpi.java | 66 + gnu/java/security/jce/prng/MD2RandomSpi.java | 66 + gnu/java/security/jce/prng/MD4RandomSpi.java | 66 + gnu/java/security/jce/prng/MD5RandomSpi.java | 66 + gnu/java/security/jce/prng/RipeMD128RandomSpi.java | 66 + gnu/java/security/jce/prng/RipeMD160RandomSpi.java | 66 + .../security/jce/prng/SecureRandomAdapter.java | 126 + gnu/java/security/jce/prng/Sha160RandomSpi.java | 66 + gnu/java/security/jce/prng/Sha256RandomSpi.java | 66 + gnu/java/security/jce/prng/Sha384RandomSpi.java | 66 + gnu/java/security/jce/prng/Sha512RandomSpi.java | 66 + gnu/java/security/jce/prng/TigerRandomSpi.java | 66 + gnu/java/security/jce/prng/WhirlpoolRandomSpi.java | 66 + gnu/java/security/jce/sig/DSSKeyFactory.java | 238 + .../security/jce/sig/DSSKeyPairGeneratorSpi.java | 169 + gnu/java/security/jce/sig/DSSParameters.java | 220 + .../security/jce/sig/DSSParametersGenerator.java | 125 + gnu/java/security/jce/sig/DSSRawSignatureSpi.java | 70 + gnu/java/security/jce/sig/EncodedKeyFactory.java | 423 + .../security/jce/sig/KeyPairGeneratorAdapter.java | 109 + gnu/java/security/jce/sig/MD2withRSA.java | 56 + gnu/java/security/jce/sig/MD5withRSA.java | 56 + gnu/java/security/jce/sig/RSAKeyFactory.java | 265 + .../security/jce/sig/RSAKeyPairGeneratorSpi.java | 115 + .../security/jce/sig/RSAPSSRawSignatureSpi.java | 69 + gnu/java/security/jce/sig/SHA160withDSS.java | 54 + gnu/java/security/jce/sig/SHA160withRSA.java | 56 + gnu/java/security/jce/sig/SHA256withRSA.java | 56 + gnu/java/security/jce/sig/SHA384withRSA.java | 56 + gnu/java/security/jce/sig/SHA512withRSA.java | 56 + gnu/java/security/jce/sig/SignatureAdapter.java | 258 + gnu/java/security/key/IKeyPairCodec.java | 132 + gnu/java/security/key/IKeyPairGenerator.java | 82 + gnu/java/security/key/KeyPairCodecFactory.java | 362 + gnu/java/security/key/KeyPairGeneratorFactory.java | 148 + gnu/java/security/key/dss/DSSKey.java | 182 + gnu/java/security/key/dss/DSSKeyPairGenerator.java | 445 + .../security/key/dss/DSSKeyPairPKCS8Codec.java | 235 + gnu/java/security/key/dss/DSSKeyPairRawCodec.java | 383 + gnu/java/security/key/dss/DSSKeyPairX509Codec.java | 248 + gnu/java/security/key/dss/DSSPrivateKey.java | 201 + gnu/java/security/key/dss/DSSPublicKey.java | 201 + gnu/java/security/key/dss/FIPS186.java | 296 + gnu/java/security/key/rsa/GnuRSAKey.java | 181 + gnu/java/security/key/rsa/GnuRSAPrivateKey.java | 299 + gnu/java/security/key/rsa/GnuRSAPublicKey.java | 185 + gnu/java/security/key/rsa/RSAKeyPairGenerator.java | 264 + .../security/key/rsa/RSAKeyPairPKCS8Codec.java | 284 + gnu/java/security/key/rsa/RSAKeyPairRawCodec.java | 332 + gnu/java/security/key/rsa/RSAKeyPairX509Codec.java | 232 + gnu/java/security/prng/BasePRNG.java | 199 + gnu/java/security/prng/EntropySource.java | 62 + gnu/java/security/prng/IRandom.java | 180 + gnu/java/security/prng/LimitReachedException.java | 69 + gnu/java/security/prng/MDGenerator.java | 135 + gnu/java/security/prng/PRNGFactory.java | 109 + gnu/java/security/prng/RandomEvent.java | 82 + gnu/java/security/prng/RandomEventListener.java | 50 + gnu/java/security/provider/EncodedKeyFactory.java | 7 +- gnu/java/security/provider/Gnu.java | 111 +- gnu/java/security/provider/GnuDSAPrivateKey.java | 3 +- gnu/java/security/provider/GnuDSAPublicKey.java | 3 +- gnu/java/security/provider/GnuRSAPrivateKey.java | 3 +- gnu/java/security/provider/GnuRSAPublicKey.java | 3 +- gnu/java/security/sig/BaseSignature.java | 261 + gnu/java/security/sig/ISignature.java | 169 + gnu/java/security/sig/ISignatureCodec.java | 68 + gnu/java/security/sig/SignatureCodecFactory.java | 226 + gnu/java/security/sig/SignatureFactory.java | 113 + gnu/java/security/sig/dss/DSSSignature.java | 347 + .../security/sig/dss/DSSSignatureRawCodec.java | 191 + .../security/sig/dss/DSSSignatureX509Codec.java | 192 + gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java | 306 + gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java | 299 + gnu/java/security/sig/rsa/EMSA_PSS.java | 432 + gnu/java/security/sig/rsa/RSA.java | 356 + .../security/sig/rsa/RSAPKCS1V1_5Signature.java | 247 + .../sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java | 153 + .../sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java | 157 + gnu/java/security/sig/rsa/RSAPSSSignature.java | 348 + .../security/sig/rsa/RSAPSSSignatureRawCodec.java | 159 + gnu/java/security/sig/rsa/RSASignatureFactory.java | 176 + gnu/java/security/util/Base64.java | 396 + gnu/java/security/util/DerUtil.java | 64 + gnu/java/security/util/ExpirableObject.java | 172 + gnu/java/security/util/FormatUtil.java | 140 + gnu/java/security/util/PRNG.java | 156 + gnu/java/security/util/Prime2.java | 417 + gnu/java/security/util/Sequence.java | 149 + gnu/java/security/util/SimpleList.java | 171 + gnu/java/security/util/Util.java | 692 + gnu/java/security/x509/X509Certificate.java | 8 +- gnu/java/security/x509/ext/GeneralNames.java | 21 +- gnu/javax/crypto/DiffieHellmanImpl.java | 159 - gnu/javax/crypto/assembly/Assembly.java | 298 + gnu/javax/crypto/assembly/Cascade.java | 405 + gnu/javax/crypto/assembly/CascadeStage.java | 109 + gnu/javax/crypto/assembly/CascadeTransformer.java | 139 + gnu/javax/crypto/assembly/DeflateTransformer.java | 233 + gnu/javax/crypto/assembly/Direction.java | 92 + gnu/javax/crypto/assembly/LoopbackTransformer.java | 116 + gnu/javax/crypto/assembly/ModeStage.java | 129 + gnu/javax/crypto/assembly/Operation.java | 89 + gnu/javax/crypto/assembly/PaddingTransformer.java | 178 + gnu/javax/crypto/assembly/Stage.java | 218 + gnu/javax/crypto/assembly/Transformer.java | 460 + .../crypto/assembly/TransformerException.java | 158 + gnu/javax/crypto/cipher/Anubis.java | 583 + gnu/javax/crypto/cipher/BaseCipher.java | 304 + gnu/javax/crypto/cipher/Blowfish.java | 749 + gnu/javax/crypto/cipher/Cast5.java | 1391 ++ gnu/javax/crypto/cipher/CipherFactory.java | 169 + gnu/javax/crypto/cipher/DES.java | 894 ++ gnu/javax/crypto/cipher/IBlockCipher.java | 205 + gnu/javax/crypto/cipher/IBlockCipherSpi.java | 128 + gnu/javax/crypto/cipher/Khazad.java | 521 + gnu/javax/crypto/cipher/NullCipher.java | 129 + gnu/javax/crypto/cipher/Rijndael.java | 859 ++ gnu/javax/crypto/cipher/Serpent.java | 1830 +++ gnu/javax/crypto/cipher/Square.java | 520 + gnu/javax/crypto/cipher/TripleDES.java | 196 + gnu/javax/crypto/cipher/Twofish.java | 909 ++ gnu/javax/crypto/cipher/WeakKeyException.java | 71 + gnu/javax/crypto/jce/DiffieHellmanImpl.java | 155 + gnu/javax/crypto/jce/GnuCrypto.java | 620 + gnu/javax/crypto/jce/GnuSasl.java | 114 + gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java | 229 + gnu/javax/crypto/jce/cipher/AESSpi.java | 104 + gnu/javax/crypto/jce/cipher/ARCFourSpi.java | 208 + gnu/javax/crypto/jce/cipher/AnubisSpi.java | 59 + gnu/javax/crypto/jce/cipher/BlowfishSpi.java | 59 + gnu/javax/crypto/jce/cipher/Cast5Spi.java | 68 + gnu/javax/crypto/jce/cipher/CipherAdapter.java | 507 + gnu/javax/crypto/jce/cipher/DESSpi.java | 59 + gnu/javax/crypto/jce/cipher/KhazadSpi.java | 59 + gnu/javax/crypto/jce/cipher/NullCipherSpi.java | 59 + gnu/javax/crypto/jce/cipher/PBES2.java | 1352 ++ gnu/javax/crypto/jce/cipher/RijndaelSpi.java | 59 + gnu/javax/crypto/jce/cipher/SerpentSpi.java | 59 + gnu/javax/crypto/jce/cipher/SquareSpi.java | 59 + gnu/javax/crypto/jce/cipher/TripleDESSpi.java | 59 + gnu/javax/crypto/jce/cipher/TwofishSpi.java | 59 + .../crypto/jce/key/AnubisKeyGeneratorImpl.java | 53 + .../crypto/jce/key/AnubisSecretKeyFactoryImpl.java | 53 + .../crypto/jce/key/BlowfishKeyGeneratorImpl.java | 53 + .../jce/key/BlowfishSecretKeyFactoryImpl.java | 53 + .../crypto/jce/key/Cast5KeyGeneratorImpl.java | 53 + .../crypto/jce/key/Cast5SecretKeyFactoryImpl.java | 53 + gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java | 73 + .../crypto/jce/key/DESSecretKeyFactoryImpl.java | 80 + .../crypto/jce/key/DESedeSecretKeyFactoryImpl.java | 80 + .../crypto/jce/key/KhazadKeyGeneratorImpl.java | 52 + .../crypto/jce/key/KhazadSecretKeyFactoryImpl.java | 52 + .../crypto/jce/key/RijndaelKeyGeneratorImpl.java | 52 + .../jce/key/RijndaelSecretKeyFactoryImpl.java | 52 + gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java | 87 + .../crypto/jce/key/SecretKeyGeneratorImpl.java | 120 + .../crypto/jce/key/SerpentKeyGeneratorImpl.java | 52 + .../jce/key/SerpentSecretKeyFactoryImpl.java | 52 + .../crypto/jce/key/SquareKeyGeneratorImpl.java | 52 + .../crypto/jce/key/SquareSecretKeyFactoryImpl.java | 52 + .../crypto/jce/key/TripleDESKeyGeneratorImpl.java | 52 + .../crypto/jce/key/TwofishKeyGeneratorImpl.java | 52 + .../jce/key/TwofishSecretKeyFactoryImpl.java | 52 + gnu/javax/crypto/jce/keyring/GnuKeyring.java | 413 + gnu/javax/crypto/jce/mac/HMacHavalSpi.java | 67 + gnu/javax/crypto/jce/mac/HMacMD2Spi.java | 59 + gnu/javax/crypto/jce/mac/HMacMD4Spi.java | 59 + gnu/javax/crypto/jce/mac/HMacMD5Spi.java | 59 + gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java | 59 + gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java | 59 + gnu/javax/crypto/jce/mac/HMacSHA160Spi.java | 59 + gnu/javax/crypto/jce/mac/HMacSHA256Spi.java | 67 + gnu/javax/crypto/jce/mac/HMacSHA384Spi.java | 67 + gnu/javax/crypto/jce/mac/HMacSHA512Spi.java | 67 + gnu/javax/crypto/jce/mac/HMacTigerSpi.java | 59 + gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java | 59 + gnu/javax/crypto/jce/mac/MacAdapter.java | 156 + gnu/javax/crypto/jce/mac/OMacAnubisImpl.java | 53 + gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java | 53 + gnu/javax/crypto/jce/mac/OMacCast5Impl.java | 53 + gnu/javax/crypto/jce/mac/OMacDESImpl.java | 53 + gnu/javax/crypto/jce/mac/OMacImpl.java | 137 + gnu/javax/crypto/jce/mac/OMacKhazadImpl.java | 53 + gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java | 53 + gnu/javax/crypto/jce/mac/OMacSerpentImpl.java | 53 + gnu/javax/crypto/jce/mac/OMacSquareImpl.java | 53 + gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java | 53 + gnu/javax/crypto/jce/mac/OMacTwofishImpl.java | 53 + gnu/javax/crypto/jce/mac/TMMH16Spi.java | 91 + gnu/javax/crypto/jce/mac/UHash32Spi.java | 59 + gnu/javax/crypto/jce/mac/UMac32Spi.java | 91 + .../crypto/jce/params/BlockCipherParameters.java | 209 + .../crypto/jce/params/DEREncodingException.java | 53 + gnu/javax/crypto/jce/params/DERReader.java | 160 + gnu/javax/crypto/jce/params/DERWriter.java | 154 + gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java | 120 + gnu/javax/crypto/jce/prng/CSPRNGSpi.java | 114 + gnu/javax/crypto/jce/prng/FortunaImpl.java | 85 + gnu/javax/crypto/jce/prng/ICMRandomSpi.java | 260 + gnu/javax/crypto/jce/prng/UMacRandomSpi.java | 207 + gnu/javax/crypto/jce/sig/DHKeyFactory.java | 232 + .../crypto/jce/sig/DHKeyPairGeneratorSpi.java | 91 + gnu/javax/crypto/jce/sig/DHParameters.java | 220 + .../crypto/jce/sig/DHParametersGenerator.java | 152 + .../crypto/jce/spec/BlockCipherParameterSpec.java | 139 + gnu/javax/crypto/jce/spec/TMMHParameterSpec.java | 129 + gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java | 82 + gnu/javax/crypto/key/BaseKeyAgreementParty.java | 208 + gnu/javax/crypto/key/GnuSecretKey.java | 149 + gnu/javax/crypto/key/IKeyAgreementParty.java | 105 + gnu/javax/crypto/key/IncomingMessage.java | 356 + gnu/javax/crypto/key/KeyAgreementException.java | 187 + gnu/javax/crypto/key/KeyAgreementFactory.java | 181 + gnu/javax/crypto/key/OutgoingMessage.java | 255 + gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java | 229 + gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java | 370 + gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java | 244 + .../crypto/key/dh/DiffieHellmanKeyAgreement.java | 134 + gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java | 147 + gnu/javax/crypto/key/dh/DiffieHellmanSender.java | 156 + gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java | 130 + gnu/javax/crypto/key/dh/ElGamalReceiver.java | 121 + gnu/javax/crypto/key/dh/ElGamalSender.java | 134 + gnu/javax/crypto/key/dh/GnuDHKey.java | 184 + gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java | 290 + gnu/javax/crypto/key/dh/GnuDHPrivateKey.java | 196 + gnu/javax/crypto/key/dh/GnuDHPublicKey.java | 194 + gnu/javax/crypto/key/dh/RFC2631.java | 255 + gnu/javax/crypto/key/srp6/SRP6Host.java | 213 + gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java | 172 + gnu/javax/crypto/key/srp6/SRP6SaslClient.java | 101 + gnu/javax/crypto/key/srp6/SRP6SaslServer.java | 101 + gnu/javax/crypto/key/srp6/SRP6TLSClient.java | 191 + gnu/javax/crypto/key/srp6/SRP6TLSServer.java | 220 + gnu/javax/crypto/key/srp6/SRP6User.java | 203 + gnu/javax/crypto/key/srp6/SRPAlgorithm.java | 175 + gnu/javax/crypto/key/srp6/SRPKey.java | 170 + gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java | 351 + gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java | 380 + gnu/javax/crypto/key/srp6/SRPPrivateKey.java | 250 + gnu/javax/crypto/key/srp6/SRPPublicKey.java | 194 + gnu/javax/crypto/keyring/AuthenticatedEntry.java | 222 + gnu/javax/crypto/keyring/BaseKeyring.java | 198 + gnu/javax/crypto/keyring/BinaryDataEntry.java | 128 + gnu/javax/crypto/keyring/CertPathEntry.java | 133 + gnu/javax/crypto/keyring/CertificateEntry.java | 150 + gnu/javax/crypto/keyring/CompressedEntry.java | 113 + gnu/javax/crypto/keyring/EncryptedEntry.java | 235 + gnu/javax/crypto/keyring/Entry.java | 178 + gnu/javax/crypto/keyring/EnvelopeEntry.java | 398 + gnu/javax/crypto/keyring/GnuPrivateKeyring.java | 328 + gnu/javax/crypto/keyring/GnuPublicKeyring.java | 146 + gnu/javax/crypto/keyring/IKeyring.java | 164 + gnu/javax/crypto/keyring/IPrivateKeyring.java | 142 + gnu/javax/crypto/keyring/IPublicKeyring.java | 81 + .../crypto/keyring/MalformedKeyringException.java | 58 + .../crypto/keyring/MaskableEnvelopeEntry.java | 148 + gnu/javax/crypto/keyring/MeteredInputStream.java | 137 + .../crypto/keyring/PasswordAuthenticatedEntry.java | 285 + .../crypto/keyring/PasswordEncryptedEntry.java | 301 + .../crypto/keyring/PasswordProtectedEntry.java | 66 + gnu/javax/crypto/keyring/PrimitiveEntry.java | 129 + gnu/javax/crypto/keyring/PrivateKeyEntry.java | 221 + gnu/javax/crypto/keyring/Properties.java | 227 + gnu/javax/crypto/keyring/PublicKeyEntry.java | 192 + gnu/javax/crypto/mac/BaseMac.java | 148 + gnu/javax/crypto/mac/HMac.java | 328 + gnu/javax/crypto/mac/HMacFactory.java | 128 + gnu/javax/crypto/mac/IMac.java | 197 + gnu/javax/crypto/mac/MacFactory.java | 164 + gnu/javax/crypto/mac/MacInputStream.java | 138 + gnu/javax/crypto/mac/MacOutputStream.java | 140 + gnu/javax/crypto/mac/OMAC.java | 402 + gnu/javax/crypto/mac/TMMH16.java | 402 + gnu/javax/crypto/mac/UHash32.java | 957 ++ gnu/javax/crypto/mac/UMac32.java | 491 + gnu/javax/crypto/mode/BaseMode.java | 352 + gnu/javax/crypto/mode/CBC.java | 143 + gnu/javax/crypto/mode/CFB.java | 175 + gnu/javax/crypto/mode/CTR.java | 221 + gnu/javax/crypto/mode/EAX.java | 352 + gnu/javax/crypto/mode/ECB.java | 137 + gnu/javax/crypto/mode/IAuthenticatedMode.java | 60 + gnu/javax/crypto/mode/ICM.java | 228 + gnu/javax/crypto/mode/IMode.java | 145 + gnu/javax/crypto/mode/ModeFactory.java | 192 + gnu/javax/crypto/mode/OFB.java | 194 + gnu/javax/crypto/pad/BasePad.java | 153 + gnu/javax/crypto/pad/IPad.java | 110 + gnu/javax/crypto/pad/PKCS1_V1_5.java | 184 + gnu/javax/crypto/pad/PKCS7.java | 149 + gnu/javax/crypto/pad/PadFactory.java | 136 + gnu/javax/crypto/pad/SSL3.java | 98 + gnu/javax/crypto/pad/TBC.java | 156 + gnu/javax/crypto/pad/TLS1.java | 105 + gnu/javax/crypto/pad/WrongPaddingException.java | 63 + gnu/javax/crypto/prng/ARCFour.java | 161 + gnu/javax/crypto/prng/CSPRNG.java | 1268 ++ gnu/javax/crypto/prng/Fortuna.java | 366 + gnu/javax/crypto/prng/ICMGenerator.java | 379 + gnu/javax/crypto/prng/IPBE.java | 69 + gnu/javax/crypto/prng/PBKDF2.java | 216 + gnu/javax/crypto/prng/PRNGFactory.java | 143 + gnu/javax/crypto/prng/UMacGenerator.java | 228 + gnu/javax/crypto/sasl/AuthInfo.java | 143 + gnu/javax/crypto/sasl/AuthInfoProviderFactory.java | 89 + gnu/javax/crypto/sasl/ClientFactory.java | 210 + gnu/javax/crypto/sasl/ClientMechanism.java | 365 + .../crypto/sasl/ConfidentialityException.java | 84 + gnu/javax/crypto/sasl/IAuthInfoProvider.java | 117 + .../crypto/sasl/IAuthInfoProviderFactory.java | 62 + .../sasl/IllegalMechanismStateException.java | 86 + gnu/javax/crypto/sasl/InputBuffer.java | 339 + gnu/javax/crypto/sasl/IntegrityException.java | 83 + .../crypto/sasl/NoSuchMechanismException.java | 62 + gnu/javax/crypto/sasl/NoSuchUserException.java | 67 + gnu/javax/crypto/sasl/OutputBuffer.java | 225 + gnu/javax/crypto/sasl/SaslEncodingException.java | 66 + gnu/javax/crypto/sasl/SaslInputStream.java | 459 + gnu/javax/crypto/sasl/SaslOutputStream.java | 218 + gnu/javax/crypto/sasl/SaslUtil.java | 89 + gnu/javax/crypto/sasl/ServerFactory.java | 194 + gnu/javax/crypto/sasl/ServerMechanism.java | 371 + .../crypto/sasl/UserAlreadyExistsException.java | 70 + .../crypto/sasl/anonymous/AnonymousClient.java | 120 + .../crypto/sasl/anonymous/AnonymousServer.java | 107 + gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java | 109 + .../sasl/crammd5/CramMD5AuthInfoProvider.java | 200 + gnu/javax/crypto/sasl/crammd5/CramMD5Client.java | 201 + gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java | 66 + gnu/javax/crypto/sasl/crammd5/CramMD5Server.java | 185 + gnu/javax/crypto/sasl/crammd5/CramMD5Util.java | 137 + gnu/javax/crypto/sasl/crammd5/PasswordFile.java | 301 + gnu/javax/crypto/sasl/plain/PasswordFile.java | 309 + .../crypto/sasl/plain/PlainAuthInfoProvider.java | 206 + gnu/javax/crypto/sasl/plain/PlainClient.java | 193 + gnu/javax/crypto/sasl/plain/PlainRegistry.java | 67 + gnu/javax/crypto/sasl/plain/PlainServer.java | 196 + gnu/javax/crypto/sasl/srp/CALG.java | 292 + gnu/javax/crypto/sasl/srp/ClientStore.java | 173 + gnu/javax/crypto/sasl/srp/IALG.java | 159 + gnu/javax/crypto/sasl/srp/KDF.java | 169 + gnu/javax/crypto/sasl/srp/PasswordFile.java | 699 + gnu/javax/crypto/sasl/srp/SRP.java | 285 + gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java | 218 + gnu/javax/crypto/sasl/srp/SRPClient.java | 1211 ++ gnu/javax/crypto/sasl/srp/SRPRegistry.java | 219 + gnu/javax/crypto/sasl/srp/SRPServer.java | 1156 ++ gnu/javax/crypto/sasl/srp/SecurityContext.java | 164 + gnu/javax/crypto/sasl/srp/ServerStore.java | 196 + gnu/javax/crypto/sasl/srp/StoreEntry.java | 89 + gnu/javax/net/ssl/Base64.java | 311 + gnu/javax/net/ssl/EntropySource.java | 62 + gnu/javax/net/ssl/NullManagerParameters.java | 56 + gnu/javax/net/ssl/PrivateCredentials.java | 360 + gnu/javax/net/ssl/SRPManagerParameters.java | 81 + gnu/javax/net/ssl/SRPTrustManager.java | 99 + gnu/javax/net/ssl/StaticTrustAnchors.java | 1942 +++ gnu/javax/net/ssl/provider/Alert.java | 474 + gnu/javax/net/ssl/provider/AlertException.java | 76 + gnu/javax/net/ssl/provider/Certificate.java | 194 + gnu/javax/net/ssl/provider/CertificateRequest.java | 285 + gnu/javax/net/ssl/provider/CertificateType.java | 104 + gnu/javax/net/ssl/provider/CertificateVerify.java | 95 + gnu/javax/net/ssl/provider/CipherSuite.java | 754 + gnu/javax/net/ssl/provider/ClientHello.java | 253 + gnu/javax/net/ssl/provider/ClientKeyExchange.java | 181 + gnu/javax/net/ssl/provider/CompressionMethod.java | 104 + gnu/javax/net/ssl/provider/Constructed.java | 57 + gnu/javax/net/ssl/provider/ContentType.java | 135 + gnu/javax/net/ssl/provider/Context.java | 334 + gnu/javax/net/ssl/provider/DiffieHellman.java | 285 + gnu/javax/net/ssl/provider/DigestInputStream.java | 103 + gnu/javax/net/ssl/provider/DigestOutputStream.java | 107 + gnu/javax/net/ssl/provider/Enumerated.java | 79 + gnu/javax/net/ssl/provider/Extension.java | 214 + gnu/javax/net/ssl/provider/Extensions.java | 159 + gnu/javax/net/ssl/provider/Finished.java | 143 + .../net/ssl/provider/GNUSecurityParameters.java | 490 + gnu/javax/net/ssl/provider/Handshake.java | 440 + .../net/ssl/provider/JCESecurityParameters.java | 307 + gnu/javax/net/ssl/provider/JDBCSessionContext.java | 356 + gnu/javax/net/ssl/provider/Jessie.java | 91 + gnu/javax/net/ssl/provider/JessieDHPrivateKey.java | 99 + gnu/javax/net/ssl/provider/JessieDHPublicKey.java | 99 + .../net/ssl/provider/JessieRSAPrivateKey.java | 98 + gnu/javax/net/ssl/provider/JessieRSAPublicKey.java | 98 + gnu/javax/net/ssl/provider/KeyPool.java | 119 + gnu/javax/net/ssl/provider/MacException.java | 53 + gnu/javax/net/ssl/provider/OverflowException.java | 57 + gnu/javax/net/ssl/provider/ProtocolVersion.java | 180 + gnu/javax/net/ssl/provider/Random.java | 124 + gnu/javax/net/ssl/provider/RecordInput.java | 232 + gnu/javax/net/ssl/provider/RecordInputStream.java | 106 + gnu/javax/net/ssl/provider/RecordOutputStream.java | 189 + .../net/ssl/provider/RecordingInputStream.java | 131 + .../net/ssl/provider/SRPTrustManagerFactory.java | 225 + gnu/javax/net/ssl/provider/SSLHMac.java | 158 + gnu/javax/net/ssl/provider/SSLRSASignature.java | 235 + gnu/javax/net/ssl/provider/SSLRandom.java | 165 + gnu/javax/net/ssl/provider/SSLServerSocket.java | 283 + .../net/ssl/provider/SSLServerSocketFactory.java | 136 + gnu/javax/net/ssl/provider/SSLSocket.java | 3530 +++++ gnu/javax/net/ssl/provider/SSLSocketFactory.java | 133 + .../net/ssl/provider/SSLSocketInputStream.java | 181 + .../net/ssl/provider/SSLSocketOutputStream.java | 115 + gnu/javax/net/ssl/provider/SecurityParameters.java | 178 + gnu/javax/net/ssl/provider/ServerHello.java | 216 + gnu/javax/net/ssl/provider/ServerKeyExchange.java | 286 + gnu/javax/net/ssl/provider/Session.java | 381 + gnu/javax/net/ssl/provider/SessionContext.java | 250 + gnu/javax/net/ssl/provider/Signature.java | 158 + gnu/javax/net/ssl/provider/SynchronizedRandom.java | 104 + gnu/javax/net/ssl/provider/TLSHMac.java | 138 + gnu/javax/net/ssl/provider/TLSRandom.java | 252 + gnu/javax/net/ssl/provider/Util.java | 422 + .../net/ssl/provider/X509KeyManagerFactory.java | 359 + .../net/ssl/provider/X509TrustManagerFactory.java | 298 + gnu/javax/net/ssl/provider/XMLSessionContext.java | 619 + gnu/javax/security/auth/Password.java | 285 + .../security/auth/callback/AWTCallbackHandler.java | 452 + .../auth/callback/AbstractCallbackHandler.java | 258 + .../auth/callback/ConsoleCallbackHandler.java | 289 + .../auth/callback/DefaultCallbackHandler.java | 109 + gnu/javax/security/auth/callback/GnuCallbacks.java | 64 + .../auth/callback/SwingCallbackHandler.java | 587 + .../security/auth/login/ConfigFileParser.java | 338 + .../security/auth/login/ConfigFileTokenizer.java | 243 + .../security/auth/login/GnuConfiguration.java | 450 + gnu/regexp/CharIndexed.java | 14 +- gnu/regexp/CharIndexedCharArray.java | 11 +- gnu/regexp/CharIndexedInputStream.java | 12 +- gnu/regexp/CharIndexedString.java | 11 +- gnu/regexp/CharIndexedStringBuffer.java | 11 +- gnu/regexp/RE.java | 778 +- gnu/regexp/REMatch.java | 60 +- gnu/regexp/RESyntax.java | 40 +- gnu/regexp/REToken.java | 15 +- gnu/regexp/RETokenAny.java | 4 + gnu/regexp/RETokenBackRef.java | 16 +- gnu/regexp/RETokenChar.java | 6 +- gnu/regexp/RETokenEnd.java | 4 + gnu/regexp/RETokenEndSub.java | 4 + gnu/regexp/RETokenIndependent.java | 76 + gnu/regexp/RETokenLookAhead.java | 4 + gnu/regexp/RETokenLookBehind.java | 116 + gnu/regexp/RETokenNamedProperty.java | 301 + gnu/regexp/RETokenOneOf.java | 181 +- gnu/regexp/RETokenPOSIX.java | 4 + gnu/regexp/RETokenRange.java | 21 +- gnu/regexp/RETokenRepeated.java | 310 +- gnu/regexp/RETokenStart.java | 4 + gnu/regexp/RETokenWordBoundary.java | 5 + gnu/xml/aelfred2/XmlParser.java | 1 + gnu/xml/dom/DomCharacterData.java | 37 +- gnu/xml/dom/DomDocumentBuilder.java | 18 +- gnu/xml/dom/DomDocumentBuilderFactory.java | 23 + gnu/xml/dom/JAXPFactory.java | 23 + .../libxmlj/dom/GnomeDocumentBuilderFactory.java | 26 +- gnu/xml/stream/CRLFReader.java | 9 +- gnu/xml/stream/SAXParser.java | 26 +- gnu/xml/stream/UnicodeReader.java | 6 +- gnu/xml/stream/XIncludeFilter.java | 13 +- gnu/xml/stream/XMLParser.java | 116 +- gnu/xml/stream/XMLStreamWriterImpl.java | 331 +- gnu/xml/transform/AbstractNumberNode.java | 2 +- gnu/xml/transform/ApplyImportsNode.java | 27 +- gnu/xml/transform/ApplyTemplatesNode.java | 46 +- gnu/xml/transform/AttributeNode.java | 2 +- gnu/xml/transform/CallTemplateNode.java | 86 +- gnu/xml/transform/ChooseNode.java | 28 +- gnu/xml/transform/CommentNode.java | 31 +- gnu/xml/transform/CopyNode.java | 73 +- gnu/xml/transform/CopyOfNode.java | 48 +- gnu/xml/transform/DocumentFunction.java | 30 +- gnu/xml/transform/ElementNode.java | 4 +- gnu/xml/transform/ForEachNode.java | 36 +- gnu/xml/transform/IfNode.java | 36 +- gnu/xml/transform/LiteralNode.java | 7 +- gnu/xml/transform/MessageNode.java | 12 + gnu/xml/transform/OtherwiseNode.java | 31 +- gnu/xml/transform/ParameterNode.java | 65 +- gnu/xml/transform/ProcessingInstructionNode.java | 32 +- gnu/xml/transform/Stylesheet.java | 60 +- gnu/xml/transform/Template.java | 133 +- gnu/xml/transform/TemplateNode.java | 38 +- gnu/xml/transform/TextNode.java | 42 +- gnu/xml/transform/TransformerImpl.java | 12 +- gnu/xml/transform/ValueOfNode.java | 2 +- gnu/xml/transform/WhenNode.java | 36 +- gnu/xml/util/XHTMLWriter.java | 2 + gnu/xml/util/XMLWriter.java | 2 + gnu/xml/validation/datatype/Annotation.java | 61 + gnu/xml/validation/datatype/AnySimpleType.java | 59 + gnu/xml/validation/datatype/AnyType.java | 58 + gnu/xml/validation/datatype/AnyURIType.java | 94 + gnu/xml/validation/datatype/AtomicSimpleType.java | 78 + gnu/xml/validation/datatype/Base64BinaryType.java | 131 + gnu/xml/validation/datatype/BooleanType.java | 91 + gnu/xml/validation/datatype/ByteType.java | 133 + gnu/xml/validation/datatype/DateTimeType.java | 335 + gnu/xml/validation/datatype/DateType.java | 222 + gnu/xml/validation/datatype/DecimalType.java | 121 + gnu/xml/validation/datatype/DoubleType.java | 112 + gnu/xml/validation/datatype/DurationType.java | 239 + gnu/xml/validation/datatype/EntitiesType.java | 107 + gnu/xml/validation/datatype/EntityType.java | 88 + gnu/xml/validation/datatype/EnumerationFacet.java | 69 + gnu/xml/validation/datatype/Facet.java | 78 + gnu/xml/validation/datatype/FloatType.java | 112 + .../validation/datatype/FractionDigitsFacet.java | 72 + gnu/xml/validation/datatype/GDayType.java | 175 + gnu/xml/validation/datatype/GMonthDayType.java | 184 + gnu/xml/validation/datatype/GMonthType.java | 164 + gnu/xml/validation/datatype/GYearMonthType.java | 177 + gnu/xml/validation/datatype/GYearType.java | 152 + gnu/xml/validation/datatype/HexBinaryType.java | 92 + gnu/xml/validation/datatype/IDRefType.java | 87 + gnu/xml/validation/datatype/IDRefsType.java | 87 + gnu/xml/validation/datatype/IDType.java | 87 + gnu/xml/validation/datatype/IntType.java | 133 + gnu/xml/validation/datatype/IntegerType.java | 110 + gnu/xml/validation/datatype/LanguageType.java | 87 + gnu/xml/validation/datatype/LengthFacet.java | 72 + gnu/xml/validation/datatype/ListSimpleType.java | 83 + gnu/xml/validation/datatype/LongType.java | 133 + gnu/xml/validation/datatype/MaxExclusiveFacet.java | 111 + gnu/xml/validation/datatype/MaxInclusiveFacet.java | 112 + gnu/xml/validation/datatype/MaxLengthFacet.java | 72 + gnu/xml/validation/datatype/MinExclusiveFacet.java | 111 + gnu/xml/validation/datatype/MinInclusiveFacet.java | 112 + gnu/xml/validation/datatype/MinLengthFacet.java | 72 + gnu/xml/validation/datatype/NCNameType.java | 111 + gnu/xml/validation/datatype/NMTokenType.java | 102 + gnu/xml/validation/datatype/NMTokensType.java | 124 + gnu/xml/validation/datatype/NameType.java | 104 + .../validation/datatype/NegativeIntegerType.java | 111 + .../datatype/NonNegativeIntegerType.java | 121 + .../datatype/NonPositiveIntegerType.java | 121 + .../validation/datatype/NormalizedStringType.java | 88 + gnu/xml/validation/datatype/NotationType.java | 90 + gnu/xml/validation/datatype/PatternFacet.java | 71 + .../validation/datatype/PositiveIntegerType.java | 111 + gnu/xml/validation/datatype/QNameType.java | 122 + gnu/xml/validation/datatype/ShortType.java | 133 + gnu/xml/validation/datatype/SimpleType.java | 257 + gnu/xml/validation/datatype/StringType.java | 77 + gnu/xml/validation/datatype/TimeType.java | 303 + gnu/xml/validation/datatype/TokenType.java | 96 + gnu/xml/validation/datatype/TotalDigitsFacet.java | 72 + gnu/xml/validation/datatype/Type.java | 65 + gnu/xml/validation/datatype/TypeBuilder.java | 279 + gnu/xml/validation/datatype/TypeLibrary.java | 173 + .../validation/datatype/TypeLibraryFactory.java | 60 + gnu/xml/validation/datatype/UnionSimpleType.java | 83 + gnu/xml/validation/datatype/UnsignedByteType.java | 121 + gnu/xml/validation/datatype/UnsignedIntType.java | 121 + gnu/xml/validation/datatype/UnsignedLongType.java | 121 + gnu/xml/validation/datatype/UnsignedShortType.java | 122 + gnu/xml/validation/datatype/WhiteSpaceFacet.java | 75 + gnu/xml/xpath/LangFunction.java | 12 +- gnu/xml/xpath/NodeTypeTest.java | 1 + gnu/xml/xpath/Selector.java | 41 +- include/Makefile.am | 6 +- include/gnu_java_awt_peer_gtk_GtkMenuBarPeer.h | 1 - include/gnu_java_awt_peer_gtk_GtkScrollbarPeer.h | 2 +- include/gnu_java_awt_peer_gtk_GtkTextFieldPeer.h | 1 - include/gnu_java_awt_peer_gtk_GtkWindowPeer.h | 2 + include/java_lang_Math.h | 37 - include/java_lang_VMMath.h | 41 + java/awt/AWTEvent.java | 103 + java/awt/BasicStroke.java | 177 +- java/awt/BorderLayout.java | 123 +- java/awt/CardLayout.java | 26 +- java/awt/Checkbox.java | 27 +- java/awt/Choice.java | 25 +- java/awt/Component.java | 252 +- java/awt/Container.java | 412 +- java/awt/Cursor.java | 4 +- java/awt/EventQueue.java | 22 + java/awt/Frame.java | 698 +- java/awt/Graphics.java | 3 + java/awt/LightweightDispatcher.java | 154 + java/awt/Menu.java | 59 +- java/awt/MenuBar.java | 575 +- java/awt/MenuComponent.java | 2028 ++- java/awt/Scrollbar.java | 30 +- java/awt/TextField.java | 1 + java/awt/Toolkit.java | 208 +- java/awt/Window.java | 81 +- java/awt/datatransfer/DataFlavor.java | 50 +- java/awt/dnd/DragSource.java | 25 +- java/awt/event/AWTEventListenerProxy.java | 68 +- java/awt/peer/ComponentPeer.java | 284 +- java/awt/print/NoPrinterJob.java | 124 + java/awt/print/PageFormat.java | 437 +- java/awt/print/Pageable.java | 119 +- java/awt/print/Paper.java | 345 +- java/awt/print/PrinterGraphics.java | 35 +- java/awt/print/PrinterJob.java | 4 +- java/beans/DefaultPersistenceDelegate.java | 17 + java/beans/Encoder.java | 45 +- java/beans/EventSetDescriptor.java | 1109 +- java/beans/PersistenceDelegate.java | 5 +- java/beans/PropertyChangeSupport.java | 25 +- java/beans/XMLDecoder.java | 6 +- java/beans/XMLEncoder.java | 2 + java/io/InputStream.java | 4 +- java/io/InputStreamReader.java | 20 +- java/io/ObjectInputStream.java | 19 +- java/io/ObjectOutputStream.java | 4 +- java/lang/Character.java | 1391 +- java/lang/ClassNotFoundException.java | 5 +- java/lang/Math.java | 351 +- java/lang/String.java | 70 +- java/lang/System.java | 17 + java/lang/Thread.java | 2 +- java/lang/reflect/Proxy.java | 44 +- java/math/BigDecimal.java | 17 +- java/net/InetAddress.java | 4 +- java/net/ServerSocket.java | 10 +- java/net/SocketPermission.java | 384 +- java/net/URI.java | 13 +- java/net/URLClassLoader.java | 48 +- java/net/URLConnection.java | 5 +- java/rmi/AccessException.java | 5 +- java/rmi/AlreadyBoundException.java | 7 +- java/rmi/MarshalledObject.java | 103 +- java/rmi/Naming.java | 226 +- java/rmi/NoSuchObjectException.java | 9 +- java/rmi/NotBoundException.java | 11 +- java/rmi/RMISecurityException.java | 14 +- java/rmi/Remote.java | 19 +- java/rmi/RemoteException.java | 5 +- java/rmi/StubNotFoundException.java | 7 +- java/rmi/package.html | 2 +- java/rmi/registry/Registry.java | 24 +- java/rmi/server/RemoteObjectInvocationHandler.java | 221 + java/rmi/server/RemoteRef.java | 64 +- java/rmi/server/RemoteStub.java | 23 +- java/rmi/server/UnicastRemoteObject.java | 213 +- java/security/AlgorithmParameterGenerator.java | 197 +- java/security/AlgorithmParameters.java | 250 +- java/security/Identity.java | 263 +- java/security/IdentityScope.java | 168 +- java/security/KeyFactory.java | 204 +- java/security/KeyPairGenerator.java | 294 +- java/security/MessageDigest.java | 257 +- java/security/Policy.java | 175 +- java/security/ProtectionDomain.java | 137 +- java/security/Security.java | 396 +- java/security/Signature.java | 527 +- java/security/SignatureSpi.java | 290 +- java/security/SignedObject.java | 177 +- java/security/Signer.java | 92 +- .../interfaces/RSAMultiPrimePrivateCrtKey.java | 27 +- java/security/spec/PSSParameterSpec.java | 25 +- .../spec/RSAMultiPrimePrivateCrtKeySpec.java | 78 +- java/security/spec/RSAOtherPrimeInfo.java | 35 +- java/util/AbstractCollection.java | 16 +- java/util/Hashtable.java | 386 +- java/util/logging/LogManager.java | 53 +- java/util/logging/SimpleFormatter.java | 10 + java/util/regex/MatchResult.java | 81 + java/util/regex/Matcher.java | 25 +- java/util/regex/PatternSyntaxException.java | 1 + java/util/zip/ZipConstants.java | 10 +- java/util/zip/ZipFile.java | 397 +- java/util/zip/ZipOutputStream.java | 12 +- javax/crypto/EncryptedPrivateKeyInfo.java | 41 +- javax/print/CancelablePrintJob.java | 21 +- javax/print/Doc.java | 81 +- javax/print/DocFlavor.java | 671 +- javax/print/DocPrintJob.java | 76 +- javax/print/PrintService.java | 164 +- javax/print/SimpleDoc.java | 223 + javax/print/StreamPrintService.java | 19 +- javax/print/StreamPrintServiceFactory.java | 130 + javax/print/attribute/AttributeSetUtilities.java | 52 +- javax/print/attribute/DateTimeSyntax.java | 10 + javax/print/attribute/HashAttributeSet.java | 37 +- javax/print/attribute/standard/Compression.java | 4 +- javax/print/attribute/standard/Finishings.java | 4 +- javax/print/attribute/standard/JobMediaSheets.java | 4 +- javax/print/attribute/standard/JobSheets.java | 4 +- javax/print/attribute/standard/JobState.java | 4 +- javax/print/attribute/standard/JobStateReason.java | 4 +- javax/print/attribute/standard/Media.java | 4 +- .../attribute/standard/MediaPrintableArea.java | 22 +- javax/print/attribute/standard/MediaSize.java | 80 +- .../standard/MultipleDocumentHandling.java | 4 +- .../attribute/standard/PDLOverrideSupported.java | 4 +- javax/print/attribute/standard/PrintQuality.java | 4 +- .../attribute/standard/PrinterIsAcceptingJobs.java | 2 +- .../attribute/standard/PrinterStateReason.java | 4 +- .../attribute/standard/PrinterStateReasons.java | 2 +- .../standard/ReferenceUriSchemesSupported.java | 4 +- .../security/auth/login/AppConfigurationEntry.java | 40 +- javax/security/auth/login/Configuration.java | 9 +- javax/sound/sampled/LineEvent.java | 24 +- javax/swing/AbstractAction.java | 11 +- javax/swing/AbstractButton.java | 8 + javax/swing/CellRendererPane.java | 40 +- javax/swing/DefaultCellEditor.java | 342 +- javax/swing/DefaultListCellRenderer.java | 2 +- javax/swing/ImageIcon.java | 4 +- javax/swing/JApplet.java | 2 +- javax/swing/JCheckBox.java | 2 +- javax/swing/JComponent.java | 342 +- javax/swing/JDialog.java | 7 +- javax/swing/JEditorPane.java | 53 +- javax/swing/JFileChooser.java | 12 +- javax/swing/JFrame.java | 11 +- javax/swing/JInternalFrame.java | 21 +- javax/swing/JLayeredPane.java | 492 +- javax/swing/JMenu.java | 2 +- javax/swing/JMenuBar.java | 12 +- javax/swing/JOptionPane.java | 4 +- javax/swing/JPanel.java | 2 +- javax/swing/JPopupMenu.java | 2 +- javax/swing/JProgressBar.java | 16 +- javax/swing/JRootPane.java | 58 +- javax/swing/JSpinner.java | 317 +- javax/swing/JSplitPane.java | 7 +- javax/swing/JTabbedPane.java | 79 +- javax/swing/JTable.java | 821 +- javax/swing/JTextField.java | 20 +- javax/swing/JTextPane.java | 8 +- javax/swing/JTree.java | 17 +- javax/swing/JViewport.java | 96 +- javax/swing/JWindow.java | 54 +- javax/swing/Popup.java | 2 +- javax/swing/PopupFactory.java | 19 +- javax/swing/RepaintManager.java | 339 +- javax/swing/ScrollPaneLayout.java | 26 +- javax/swing/SpinnerDateModel.java | 150 +- javax/swing/SpinnerNumberModel.java | 187 +- javax/swing/SwingUtilities.java | 50 +- javax/swing/Timer.java | 7 +- javax/swing/ToolTipManager.java | 3 - javax/swing/UIManager.java | 6 +- javax/swing/ViewportLayout.java | 14 +- javax/swing/event/DocumentEvent.java | 2 +- javax/swing/event/SwingPropertyChangeSupport.java | 278 +- javax/swing/plaf/basic/BasicBorders.java | 36 +- .../swing/plaf/basic/BasicCheckBoxMenuItemUI.java | 1 - javax/swing/plaf/basic/BasicColorChooserUI.java | 5 +- javax/swing/plaf/basic/BasicComboPopup.java | 16 + javax/swing/plaf/basic/BasicHTML.java | 2 +- javax/swing/plaf/basic/BasicInternalFrameUI.java | 43 +- javax/swing/plaf/basic/BasicListUI.java | 34 +- javax/swing/plaf/basic/BasicLookAndFeel.java | 141 + javax/swing/plaf/basic/BasicMenuItemUI.java | 3 +- javax/swing/plaf/basic/BasicPopupMenuUI.java | 323 +- .../plaf/basic/BasicRadioButtonMenuItemUI.java | 1 - javax/swing/plaf/basic/BasicRootPaneUI.java | 6 +- javax/swing/plaf/basic/BasicSpinnerUI.java | 206 +- javax/swing/plaf/basic/BasicSplitPaneDivider.java | 31 - javax/swing/plaf/basic/BasicSplitPaneUI.java | 108 +- javax/swing/plaf/basic/BasicTabbedPaneUI.java | 7 +- javax/swing/plaf/basic/BasicTableHeaderUI.java | 351 +- javax/swing/plaf/basic/BasicTableUI.java | 160 +- javax/swing/plaf/basic/BasicTextUI.java | 218 +- javax/swing/plaf/basic/BasicTreeUI.java | 297 +- javax/swing/plaf/metal/MetalBorders.java | 93 +- javax/swing/plaf/metal/MetalFileChooserUI.java | 2 - javax/swing/plaf/metal/MetalLookAndFeel.java | 13 + javax/swing/plaf/metal/MetalRootPaneUI.java | 909 +- javax/swing/plaf/metal/MetalSplitPaneDivider.java | 8 + javax/swing/plaf/synth/ColorType.java | 130 + javax/swing/plaf/synth/Region.java | 474 + javax/swing/plaf/synth/SynthConstants.java | 85 + javax/swing/plaf/synth/SynthContext.java | 134 + javax/swing/plaf/synth/SynthGraphicsUtils.java | 283 + javax/swing/plaf/synth/SynthLookAndFeel.java | 272 + javax/swing/plaf/synth/SynthPainter.java | 80 + javax/swing/plaf/synth/SynthStyle.java | 144 + javax/swing/plaf/synth/SynthStyleFactory.java | 64 + javax/swing/plaf/synth/package.html | 47 + javax/swing/table/DefaultTableCellRenderer.java | 17 +- javax/swing/table/DefaultTableModel.java | 5 +- javax/swing/table/JTableHeader.java | 89 +- javax/swing/text/AbstractDocument.java | 87 +- javax/swing/text/AsyncBoxView.java | 1480 ++ javax/swing/text/BoxView.java | 594 +- javax/swing/text/ComponentView.java | 3 +- javax/swing/text/CompositeView.java | 41 +- javax/swing/text/DefaultCaret.java | 55 +- javax/swing/text/DefaultEditorKit.java | 332 +- javax/swing/text/DefaultFormatter.java | 1 - javax/swing/text/DefaultHighlighter.java | 140 +- javax/swing/text/DefaultStyledDocument.java | 2039 ++- javax/swing/text/DefaultTextUI.java | 1 + javax/swing/text/FlowView.java | 389 +- javax/swing/text/GapContent.java | 162 +- javax/swing/text/GlyphView.java | 126 +- javax/swing/text/IconView.java | 2 - javax/swing/text/JTextComponent.java | 391 +- javax/swing/text/LabelView.java | 6 +- javax/swing/text/MutableAttributeSet.java | 64 +- javax/swing/text/NavigationFilter.java | 27 + javax/swing/text/ParagraphView.java | 203 +- javax/swing/text/PasswordView.java | 44 +- javax/swing/text/PlainView.java | 105 +- javax/swing/text/Segment.java | 116 +- javax/swing/text/SimpleAttributeSet.java | 195 +- javax/swing/text/StringContent.java | 138 +- javax/swing/text/StyleConstants.java | 757 +- javax/swing/text/StyleContext.java | 25 +- javax/swing/text/Utilities.java | 97 +- javax/swing/text/View.java | 127 +- javax/swing/text/WrappedPlainView.java | 3 +- javax/swing/text/html/FormView.java | 230 + javax/swing/text/html/HTML.java | 79 +- javax/swing/text/html/HTMLDocument.java | 119 +- javax/swing/text/html/HTMLEditorKit.java | 33 +- javax/swing/text/html/InlineView.java | 166 + javax/swing/text/html/NullView.java | 102 + javax/swing/text/html/ObjectView.java | 110 + javax/swing/text/html/Option.java | 157 + javax/swing/text/html/ParagraphView.java | 209 + javax/swing/tree/DefaultTreeCellEditor.java | 208 +- javax/swing/undo/StateEdit.java | 6 +- javax/swing/undo/StateEditable.java | 6 +- javax/xml/parsers/DocumentBuilderFactory.java | 27 +- lib/Makefile.am | 3 +- lib/gen-classlist.sh.in | 1 + m4/acinclude.m4 | 13 + native/fdlibm/Makefile.am | 12 + native/fdlibm/e_acos.c | 32 +- native/fdlibm/e_asin.c | 24 +- native/fdlibm/e_atan2.c | 48 +- native/fdlibm/e_cosh.c | 89 + native/fdlibm/e_exp.c | 59 +- native/fdlibm/e_fmod.c | 42 +- native/fdlibm/e_hypot.c | 115 + native/fdlibm/e_log.c | 71 +- native/fdlibm/e_log10.c | 91 + native/fdlibm/e_pow.c | 137 +- native/fdlibm/e_rem_pio2.c | 96 +- native/fdlibm/e_remainder.c | 31 +- native/fdlibm/e_scalb.c | 8 +- native/fdlibm/e_sinh.c | 82 + native/fdlibm/e_sqrt.c | 118 +- native/fdlibm/fdlibm.h | 281 +- native/fdlibm/k_cos.c | 38 +- native/fdlibm/k_rem_pio2.c | 94 +- native/fdlibm/k_sin.c | 31 +- native/fdlibm/k_tan.c | 180 +- native/fdlibm/namespace.h | 4 + native/fdlibm/s_atan.c | 73 +- native/fdlibm/s_cbrt.c | 87 + native/fdlibm/s_ceil.c | 28 +- native/fdlibm/s_copysign.c | 59 +- native/fdlibm/s_cos.c | 20 +- native/fdlibm/s_expm1.c | 215 + native/fdlibm/s_fabs.c | 52 +- native/fdlibm/s_finite.c | 12 +- native/fdlibm/s_floor.c | 81 +- native/fdlibm/s_log1p.c | 165 + native/fdlibm/s_rint.c | 35 +- native/fdlibm/s_scalbn.c | 73 +- native/fdlibm/s_sin.c | 70 +- native/fdlibm/s_tan.c | 58 +- native/fdlibm/s_tanh.c | 82 + native/fdlibm/w_acos.c | 89 +- native/fdlibm/w_asin.c | 86 +- native/fdlibm/w_atan2.c | 83 +- native/fdlibm/w_cosh.c | 38 + native/fdlibm/w_exp.c | 104 +- native/fdlibm/w_fmod.c | 74 +- native/fdlibm/w_hypot.c | 39 + native/fdlibm/w_log.c | 88 +- native/fdlibm/w_log10.c | 42 + native/fdlibm/w_pow.c | 201 +- native/fdlibm/w_remainder.c | 91 +- native/fdlibm/w_sinh.c | 38 + native/fdlibm/w_sqrt.c | 61 +- .../gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c | 26 +- .../gnu_java_awt_peer_gtk_GtkCheckboxPeer.c | 9 +- .../gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer.c | 4 +- .../gnu_java_awt_peer_gtk_GtkMenuBarPeer.c | 28 +- .../gnu_java_awt_peer_gtk_GtkScrollbarPeer.c | 20 +- .../gnu_java_awt_peer_gtk_GtkTextFieldPeer.c | 33 - .../gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c | 45 +- native/jni/java-lang/Makefile.am | 2 +- native/jni/java-lang/java_lang_Math.c | 161 - native/jni/java-lang/java_lang_VMDouble.c | 22 +- native/jni/java-lang/java_lang_VMMath.c | 225 + native/jni/java-net/javanet.c | 2 +- native/jni/java-net/javanet.h | 1 + .../org.relaxng.datatype.DatatypeLibraryFactory | 1 + .../auth/callback/MessagesBundle.properties | 52 + resource/java/security/classpath.security | 3 + scripts/eclipse-gnu.xml | 90 +- scripts/math_symbols | 4 + scripts/unicode-muncher.pl | 637 +- vm/reference/gnu/classpath/jdwp/VMFrame.java | 7 +- vm/reference/gnu/classpath/jdwp/VMIdManager.java | 10 +- vm/reference/java/io/VMObjectInputStream.java | 39 +- vm/reference/java/lang/VMMath.java | 493 + vm/reference/java/lang/reflect/Constructor.java | 4 +- vm/reference/java/lang/reflect/Method.java | 4 +- 1049 files changed, 167657 insertions(+), 16647 deletions(-) create mode 100644 doc/unicode/SpecialCasing-4.0.0.txt create mode 100644 doc/unicode/UnicodeData-4.0.0.txt create mode 100644 doc/www.gnu.org/announce/20060113.wml create mode 100644 examples/gnu/classpath/examples/swing/MiniDemo.java create mode 100644 examples/gnu/classpath/examples/swing/SpinnerDemo.java create mode 100644 examples/gnu/classpath/examples/swing/TableDemo.java create mode 100644 external/relaxngDatatype/.cvsignore create mode 100644 external/relaxngDatatype/Makefile.am create mode 100755 external/relaxngDatatype/README.txt create mode 100755 external/relaxngDatatype/copying.txt create mode 100755 external/relaxngDatatype/org/relaxng/datatype/Datatype.java create mode 100755 external/relaxngDatatype/org/relaxng/datatype/DatatypeBuilder.java create mode 100755 external/relaxngDatatype/org/relaxng/datatype/DatatypeException.java create mode 100755 external/relaxngDatatype/org/relaxng/datatype/DatatypeLibrary.java create mode 100755 external/relaxngDatatype/org/relaxng/datatype/DatatypeLibraryFactory.java create mode 100755 external/relaxngDatatype/org/relaxng/datatype/DatatypeStreamingValidator.java create mode 100755 external/relaxngDatatype/org/relaxng/datatype/ValidationContext.java create mode 100755 external/relaxngDatatype/org/relaxng/datatype/helpers/DatatypeLibraryLoader.java create mode 100755 external/relaxngDatatype/org/relaxng/datatype/helpers/ParameterlessDatatypeBuilder.java create mode 100755 external/relaxngDatatype/org/relaxng/datatype/helpers/StreamingValidatorImpl.java create mode 100644 gnu/java/awt/peer/swing/SwingButtonPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingCanvasPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingComponent.java create mode 100644 gnu/java/awt/peer/swing/SwingComponentPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingContainerPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingFramePeer.java create mode 100644 gnu/java/awt/peer/swing/SwingLabelPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingMenuBarPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingMenuItemPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingMenuPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingPanelPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingTextFieldPeer.java create mode 100644 gnu/java/awt/peer/swing/SwingToolkit.java create mode 100644 gnu/java/awt/peer/swing/SwingWindowPeer.java create mode 100644 gnu/java/awt/peer/swing/package.html create mode 100644 gnu/java/beans/DefaultExceptionListener.java delete mode 100644 gnu/java/beans/decoder/DefaultExceptionListener.java create mode 100644 gnu/java/rmi/server/CombinedClassLoader.java create mode 100644 gnu/java/security/Properties.java create mode 100644 gnu/java/security/Registry.java create mode 100644 gnu/java/security/hash/BaseHash.java create mode 100644 gnu/java/security/hash/HashFactory.java create mode 100644 gnu/java/security/hash/Haval.java create mode 100644 gnu/java/security/hash/IMessageDigest.java create mode 100644 gnu/java/security/hash/MD2.java create mode 100644 gnu/java/security/hash/MD4.java create mode 100644 gnu/java/security/hash/MD5.java create mode 100644 gnu/java/security/hash/RipeMD128.java create mode 100644 gnu/java/security/hash/RipeMD160.java create mode 100644 gnu/java/security/hash/Sha160.java create mode 100644 gnu/java/security/hash/Sha256.java create mode 100644 gnu/java/security/hash/Sha384.java create mode 100644 gnu/java/security/hash/Sha512.java create mode 100644 gnu/java/security/hash/Tiger.java create mode 100644 gnu/java/security/hash/Whirlpool.java create mode 100644 gnu/java/security/jce/hash/HavalSpi.java create mode 100644 gnu/java/security/jce/hash/MD2Spi.java create mode 100644 gnu/java/security/jce/hash/MD4Spi.java create mode 100644 gnu/java/security/jce/hash/MD5Spi.java create mode 100644 gnu/java/security/jce/hash/MessageDigestAdapter.java create mode 100644 gnu/java/security/jce/hash/RipeMD128Spi.java create mode 100644 gnu/java/security/jce/hash/RipeMD160Spi.java create mode 100644 gnu/java/security/jce/hash/Sha160Spi.java create mode 100644 gnu/java/security/jce/hash/Sha256Spi.java create mode 100644 gnu/java/security/jce/hash/Sha384Spi.java create mode 100644 gnu/java/security/jce/hash/Sha512Spi.java create mode 100644 gnu/java/security/jce/hash/TigerSpi.java create mode 100644 gnu/java/security/jce/hash/WhirlpoolSpi.java create mode 100644 gnu/java/security/jce/prng/HavalRandomSpi.java create mode 100644 gnu/java/security/jce/prng/MD2RandomSpi.java create mode 100644 gnu/java/security/jce/prng/MD4RandomSpi.java create mode 100644 gnu/java/security/jce/prng/MD5RandomSpi.java create mode 100644 gnu/java/security/jce/prng/RipeMD128RandomSpi.java create mode 100644 gnu/java/security/jce/prng/RipeMD160RandomSpi.java create mode 100644 gnu/java/security/jce/prng/SecureRandomAdapter.java create mode 100644 gnu/java/security/jce/prng/Sha160RandomSpi.java create mode 100644 gnu/java/security/jce/prng/Sha256RandomSpi.java create mode 100644 gnu/java/security/jce/prng/Sha384RandomSpi.java create mode 100644 gnu/java/security/jce/prng/Sha512RandomSpi.java create mode 100644 gnu/java/security/jce/prng/TigerRandomSpi.java create mode 100644 gnu/java/security/jce/prng/WhirlpoolRandomSpi.java create mode 100644 gnu/java/security/jce/sig/DSSKeyFactory.java create mode 100644 gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java create mode 100644 gnu/java/security/jce/sig/DSSParameters.java create mode 100644 gnu/java/security/jce/sig/DSSParametersGenerator.java create mode 100644 gnu/java/security/jce/sig/DSSRawSignatureSpi.java create mode 100644 gnu/java/security/jce/sig/EncodedKeyFactory.java create mode 100644 gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java create mode 100644 gnu/java/security/jce/sig/MD2withRSA.java create mode 100644 gnu/java/security/jce/sig/MD5withRSA.java create mode 100644 gnu/java/security/jce/sig/RSAKeyFactory.java create mode 100644 gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java create mode 100644 gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java create mode 100644 gnu/java/security/jce/sig/SHA160withDSS.java create mode 100644 gnu/java/security/jce/sig/SHA160withRSA.java create mode 100644 gnu/java/security/jce/sig/SHA256withRSA.java create mode 100644 gnu/java/security/jce/sig/SHA384withRSA.java create mode 100644 gnu/java/security/jce/sig/SHA512withRSA.java create mode 100644 gnu/java/security/jce/sig/SignatureAdapter.java create mode 100644 gnu/java/security/key/IKeyPairCodec.java create mode 100644 gnu/java/security/key/IKeyPairGenerator.java create mode 100644 gnu/java/security/key/KeyPairCodecFactory.java create mode 100644 gnu/java/security/key/KeyPairGeneratorFactory.java create mode 100644 gnu/java/security/key/dss/DSSKey.java create mode 100644 gnu/java/security/key/dss/DSSKeyPairGenerator.java create mode 100644 gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java create mode 100644 gnu/java/security/key/dss/DSSKeyPairRawCodec.java create mode 100644 gnu/java/security/key/dss/DSSKeyPairX509Codec.java create mode 100644 gnu/java/security/key/dss/DSSPrivateKey.java create mode 100644 gnu/java/security/key/dss/DSSPublicKey.java create mode 100644 gnu/java/security/key/dss/FIPS186.java create mode 100644 gnu/java/security/key/rsa/GnuRSAKey.java create mode 100644 gnu/java/security/key/rsa/GnuRSAPrivateKey.java create mode 100644 gnu/java/security/key/rsa/GnuRSAPublicKey.java create mode 100644 gnu/java/security/key/rsa/RSAKeyPairGenerator.java create mode 100644 gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java create mode 100644 gnu/java/security/key/rsa/RSAKeyPairRawCodec.java create mode 100644 gnu/java/security/key/rsa/RSAKeyPairX509Codec.java create mode 100644 gnu/java/security/prng/BasePRNG.java create mode 100644 gnu/java/security/prng/EntropySource.java create mode 100644 gnu/java/security/prng/IRandom.java create mode 100644 gnu/java/security/prng/LimitReachedException.java create mode 100644 gnu/java/security/prng/MDGenerator.java create mode 100644 gnu/java/security/prng/PRNGFactory.java create mode 100644 gnu/java/security/prng/RandomEvent.java create mode 100644 gnu/java/security/prng/RandomEventListener.java create mode 100644 gnu/java/security/sig/BaseSignature.java create mode 100644 gnu/java/security/sig/ISignature.java create mode 100644 gnu/java/security/sig/ISignatureCodec.java create mode 100644 gnu/java/security/sig/SignatureCodecFactory.java create mode 100644 gnu/java/security/sig/SignatureFactory.java create mode 100644 gnu/java/security/sig/dss/DSSSignature.java create mode 100644 gnu/java/security/sig/dss/DSSSignatureRawCodec.java create mode 100644 gnu/java/security/sig/dss/DSSSignatureX509Codec.java create mode 100644 gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java create mode 100644 gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java create mode 100644 gnu/java/security/sig/rsa/EMSA_PSS.java create mode 100644 gnu/java/security/sig/rsa/RSA.java create mode 100644 gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java create mode 100644 gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java create mode 100644 gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java create mode 100644 gnu/java/security/sig/rsa/RSAPSSSignature.java create mode 100644 gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java create mode 100644 gnu/java/security/sig/rsa/RSASignatureFactory.java create mode 100644 gnu/java/security/util/Base64.java create mode 100644 gnu/java/security/util/DerUtil.java create mode 100644 gnu/java/security/util/ExpirableObject.java create mode 100644 gnu/java/security/util/FormatUtil.java create mode 100644 gnu/java/security/util/PRNG.java create mode 100644 gnu/java/security/util/Prime2.java create mode 100644 gnu/java/security/util/Sequence.java create mode 100644 gnu/java/security/util/SimpleList.java create mode 100644 gnu/java/security/util/Util.java delete mode 100644 gnu/javax/crypto/DiffieHellmanImpl.java create mode 100644 gnu/javax/crypto/assembly/Assembly.java create mode 100644 gnu/javax/crypto/assembly/Cascade.java create mode 100644 gnu/javax/crypto/assembly/CascadeStage.java create mode 100644 gnu/javax/crypto/assembly/CascadeTransformer.java create mode 100644 gnu/javax/crypto/assembly/DeflateTransformer.java create mode 100644 gnu/javax/crypto/assembly/Direction.java create mode 100644 gnu/javax/crypto/assembly/LoopbackTransformer.java create mode 100644 gnu/javax/crypto/assembly/ModeStage.java create mode 100644 gnu/javax/crypto/assembly/Operation.java create mode 100644 gnu/javax/crypto/assembly/PaddingTransformer.java create mode 100644 gnu/javax/crypto/assembly/Stage.java create mode 100644 gnu/javax/crypto/assembly/Transformer.java create mode 100644 gnu/javax/crypto/assembly/TransformerException.java create mode 100644 gnu/javax/crypto/cipher/Anubis.java create mode 100644 gnu/javax/crypto/cipher/BaseCipher.java create mode 100644 gnu/javax/crypto/cipher/Blowfish.java create mode 100644 gnu/javax/crypto/cipher/Cast5.java create mode 100644 gnu/javax/crypto/cipher/CipherFactory.java create mode 100644 gnu/javax/crypto/cipher/DES.java create mode 100644 gnu/javax/crypto/cipher/IBlockCipher.java create mode 100644 gnu/javax/crypto/cipher/IBlockCipherSpi.java create mode 100644 gnu/javax/crypto/cipher/Khazad.java create mode 100644 gnu/javax/crypto/cipher/NullCipher.java create mode 100644 gnu/javax/crypto/cipher/Rijndael.java create mode 100644 gnu/javax/crypto/cipher/Serpent.java create mode 100644 gnu/javax/crypto/cipher/Square.java create mode 100644 gnu/javax/crypto/cipher/TripleDES.java create mode 100644 gnu/javax/crypto/cipher/Twofish.java create mode 100644 gnu/javax/crypto/cipher/WeakKeyException.java create mode 100644 gnu/javax/crypto/jce/DiffieHellmanImpl.java create mode 100644 gnu/javax/crypto/jce/GnuCrypto.java create mode 100644 gnu/javax/crypto/jce/GnuSasl.java create mode 100644 gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java create mode 100644 gnu/javax/crypto/jce/cipher/AESSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/ARCFourSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/AnubisSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/BlowfishSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/Cast5Spi.java create mode 100644 gnu/javax/crypto/jce/cipher/CipherAdapter.java create mode 100644 gnu/javax/crypto/jce/cipher/DESSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/KhazadSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/NullCipherSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/PBES2.java create mode 100644 gnu/javax/crypto/jce/cipher/RijndaelSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/SerpentSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/SquareSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/TripleDESSpi.java create mode 100644 gnu/javax/crypto/jce/cipher/TwofishSpi.java create mode 100644 gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java create mode 100644 gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java create mode 100644 gnu/javax/crypto/jce/keyring/GnuKeyring.java create mode 100644 gnu/javax/crypto/jce/mac/HMacHavalSpi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacMD2Spi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacMD4Spi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacMD5Spi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacSHA160Spi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacSHA256Spi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacSHA384Spi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacSHA512Spi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacTigerSpi.java create mode 100644 gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java create mode 100644 gnu/javax/crypto/jce/mac/MacAdapter.java create mode 100644 gnu/javax/crypto/jce/mac/OMacAnubisImpl.java create mode 100644 gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java create mode 100644 gnu/javax/crypto/jce/mac/OMacCast5Impl.java create mode 100644 gnu/javax/crypto/jce/mac/OMacDESImpl.java create mode 100644 gnu/javax/crypto/jce/mac/OMacImpl.java create mode 100644 gnu/javax/crypto/jce/mac/OMacKhazadImpl.java create mode 100644 gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java create mode 100644 gnu/javax/crypto/jce/mac/OMacSerpentImpl.java create mode 100644 gnu/javax/crypto/jce/mac/OMacSquareImpl.java create mode 100644 gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java create mode 100644 gnu/javax/crypto/jce/mac/OMacTwofishImpl.java create mode 100644 gnu/javax/crypto/jce/mac/TMMH16Spi.java create mode 100644 gnu/javax/crypto/jce/mac/UHash32Spi.java create mode 100644 gnu/javax/crypto/jce/mac/UMac32Spi.java create mode 100644 gnu/javax/crypto/jce/params/BlockCipherParameters.java create mode 100644 gnu/javax/crypto/jce/params/DEREncodingException.java create mode 100644 gnu/javax/crypto/jce/params/DERReader.java create mode 100644 gnu/javax/crypto/jce/params/DERWriter.java create mode 100644 gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java create mode 100644 gnu/javax/crypto/jce/prng/CSPRNGSpi.java create mode 100644 gnu/javax/crypto/jce/prng/FortunaImpl.java create mode 100644 gnu/javax/crypto/jce/prng/ICMRandomSpi.java create mode 100644 gnu/javax/crypto/jce/prng/UMacRandomSpi.java create mode 100644 gnu/javax/crypto/jce/sig/DHKeyFactory.java create mode 100644 gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java create mode 100644 gnu/javax/crypto/jce/sig/DHParameters.java create mode 100644 gnu/javax/crypto/jce/sig/DHParametersGenerator.java create mode 100644 gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java create mode 100644 gnu/javax/crypto/jce/spec/TMMHParameterSpec.java create mode 100644 gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java create mode 100644 gnu/javax/crypto/key/BaseKeyAgreementParty.java create mode 100644 gnu/javax/crypto/key/GnuSecretKey.java create mode 100644 gnu/javax/crypto/key/IKeyAgreementParty.java create mode 100644 gnu/javax/crypto/key/IncomingMessage.java create mode 100644 gnu/javax/crypto/key/KeyAgreementException.java create mode 100644 gnu/javax/crypto/key/KeyAgreementFactory.java create mode 100644 gnu/javax/crypto/key/OutgoingMessage.java create mode 100644 gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java create mode 100644 gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java create mode 100644 gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java create mode 100644 gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java create mode 100644 gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java create mode 100644 gnu/javax/crypto/key/dh/DiffieHellmanSender.java create mode 100644 gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java create mode 100644 gnu/javax/crypto/key/dh/ElGamalReceiver.java create mode 100644 gnu/javax/crypto/key/dh/ElGamalSender.java create mode 100644 gnu/javax/crypto/key/dh/GnuDHKey.java create mode 100644 gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java create mode 100644 gnu/javax/crypto/key/dh/GnuDHPrivateKey.java create mode 100644 gnu/javax/crypto/key/dh/GnuDHPublicKey.java create mode 100644 gnu/javax/crypto/key/dh/RFC2631.java create mode 100644 gnu/javax/crypto/key/srp6/SRP6Host.java create mode 100644 gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java create mode 100644 gnu/javax/crypto/key/srp6/SRP6SaslClient.java create mode 100644 gnu/javax/crypto/key/srp6/SRP6SaslServer.java create mode 100644 gnu/javax/crypto/key/srp6/SRP6TLSClient.java create mode 100644 gnu/javax/crypto/key/srp6/SRP6TLSServer.java create mode 100644 gnu/javax/crypto/key/srp6/SRP6User.java create mode 100644 gnu/javax/crypto/key/srp6/SRPAlgorithm.java create mode 100644 gnu/javax/crypto/key/srp6/SRPKey.java create mode 100644 gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java create mode 100644 gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java create mode 100644 gnu/javax/crypto/key/srp6/SRPPrivateKey.java create mode 100644 gnu/javax/crypto/key/srp6/SRPPublicKey.java create mode 100644 gnu/javax/crypto/keyring/AuthenticatedEntry.java create mode 100644 gnu/javax/crypto/keyring/BaseKeyring.java create mode 100644 gnu/javax/crypto/keyring/BinaryDataEntry.java create mode 100644 gnu/javax/crypto/keyring/CertPathEntry.java create mode 100644 gnu/javax/crypto/keyring/CertificateEntry.java create mode 100644 gnu/javax/crypto/keyring/CompressedEntry.java create mode 100644 gnu/javax/crypto/keyring/EncryptedEntry.java create mode 100644 gnu/javax/crypto/keyring/Entry.java create mode 100644 gnu/javax/crypto/keyring/EnvelopeEntry.java create mode 100644 gnu/javax/crypto/keyring/GnuPrivateKeyring.java create mode 100644 gnu/javax/crypto/keyring/GnuPublicKeyring.java create mode 100644 gnu/javax/crypto/keyring/IKeyring.java create mode 100644 gnu/javax/crypto/keyring/IPrivateKeyring.java create mode 100644 gnu/javax/crypto/keyring/IPublicKeyring.java create mode 100644 gnu/javax/crypto/keyring/MalformedKeyringException.java create mode 100644 gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java create mode 100644 gnu/javax/crypto/keyring/MeteredInputStream.java create mode 100644 gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java create mode 100644 gnu/javax/crypto/keyring/PasswordEncryptedEntry.java create mode 100644 gnu/javax/crypto/keyring/PasswordProtectedEntry.java create mode 100644 gnu/javax/crypto/keyring/PrimitiveEntry.java create mode 100644 gnu/javax/crypto/keyring/PrivateKeyEntry.java create mode 100644 gnu/javax/crypto/keyring/Properties.java create mode 100644 gnu/javax/crypto/keyring/PublicKeyEntry.java create mode 100644 gnu/javax/crypto/mac/BaseMac.java create mode 100644 gnu/javax/crypto/mac/HMac.java create mode 100644 gnu/javax/crypto/mac/HMacFactory.java create mode 100644 gnu/javax/crypto/mac/IMac.java create mode 100644 gnu/javax/crypto/mac/MacFactory.java create mode 100644 gnu/javax/crypto/mac/MacInputStream.java create mode 100644 gnu/javax/crypto/mac/MacOutputStream.java create mode 100644 gnu/javax/crypto/mac/OMAC.java create mode 100644 gnu/javax/crypto/mac/TMMH16.java create mode 100644 gnu/javax/crypto/mac/UHash32.java create mode 100644 gnu/javax/crypto/mac/UMac32.java create mode 100644 gnu/javax/crypto/mode/BaseMode.java create mode 100644 gnu/javax/crypto/mode/CBC.java create mode 100644 gnu/javax/crypto/mode/CFB.java create mode 100644 gnu/javax/crypto/mode/CTR.java create mode 100644 gnu/javax/crypto/mode/EAX.java create mode 100644 gnu/javax/crypto/mode/ECB.java create mode 100644 gnu/javax/crypto/mode/IAuthenticatedMode.java create mode 100644 gnu/javax/crypto/mode/ICM.java create mode 100644 gnu/javax/crypto/mode/IMode.java create mode 100644 gnu/javax/crypto/mode/ModeFactory.java create mode 100644 gnu/javax/crypto/mode/OFB.java create mode 100644 gnu/javax/crypto/pad/BasePad.java create mode 100644 gnu/javax/crypto/pad/IPad.java create mode 100644 gnu/javax/crypto/pad/PKCS1_V1_5.java create mode 100644 gnu/javax/crypto/pad/PKCS7.java create mode 100644 gnu/javax/crypto/pad/PadFactory.java create mode 100644 gnu/javax/crypto/pad/SSL3.java create mode 100644 gnu/javax/crypto/pad/TBC.java create mode 100644 gnu/javax/crypto/pad/TLS1.java create mode 100644 gnu/javax/crypto/pad/WrongPaddingException.java create mode 100644 gnu/javax/crypto/prng/ARCFour.java create mode 100644 gnu/javax/crypto/prng/CSPRNG.java create mode 100644 gnu/javax/crypto/prng/Fortuna.java create mode 100644 gnu/javax/crypto/prng/ICMGenerator.java create mode 100644 gnu/javax/crypto/prng/IPBE.java create mode 100644 gnu/javax/crypto/prng/PBKDF2.java create mode 100644 gnu/javax/crypto/prng/PRNGFactory.java create mode 100644 gnu/javax/crypto/prng/UMacGenerator.java create mode 100644 gnu/javax/crypto/sasl/AuthInfo.java create mode 100644 gnu/javax/crypto/sasl/AuthInfoProviderFactory.java create mode 100644 gnu/javax/crypto/sasl/ClientFactory.java create mode 100644 gnu/javax/crypto/sasl/ClientMechanism.java create mode 100644 gnu/javax/crypto/sasl/ConfidentialityException.java create mode 100644 gnu/javax/crypto/sasl/IAuthInfoProvider.java create mode 100644 gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java create mode 100644 gnu/javax/crypto/sasl/IllegalMechanismStateException.java create mode 100644 gnu/javax/crypto/sasl/InputBuffer.java create mode 100644 gnu/javax/crypto/sasl/IntegrityException.java create mode 100644 gnu/javax/crypto/sasl/NoSuchMechanismException.java create mode 100644 gnu/javax/crypto/sasl/NoSuchUserException.java create mode 100644 gnu/javax/crypto/sasl/OutputBuffer.java create mode 100644 gnu/javax/crypto/sasl/SaslEncodingException.java create mode 100644 gnu/javax/crypto/sasl/SaslInputStream.java create mode 100644 gnu/javax/crypto/sasl/SaslOutputStream.java create mode 100644 gnu/javax/crypto/sasl/SaslUtil.java create mode 100644 gnu/javax/crypto/sasl/ServerFactory.java create mode 100644 gnu/javax/crypto/sasl/ServerMechanism.java create mode 100644 gnu/javax/crypto/sasl/UserAlreadyExistsException.java create mode 100644 gnu/javax/crypto/sasl/anonymous/AnonymousClient.java create mode 100644 gnu/javax/crypto/sasl/anonymous/AnonymousServer.java create mode 100644 gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java create mode 100644 gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java create mode 100644 gnu/javax/crypto/sasl/crammd5/CramMD5Client.java create mode 100644 gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java create mode 100644 gnu/javax/crypto/sasl/crammd5/CramMD5Server.java create mode 100644 gnu/javax/crypto/sasl/crammd5/CramMD5Util.java create mode 100644 gnu/javax/crypto/sasl/crammd5/PasswordFile.java create mode 100644 gnu/javax/crypto/sasl/plain/PasswordFile.java create mode 100644 gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java create mode 100644 gnu/javax/crypto/sasl/plain/PlainClient.java create mode 100644 gnu/javax/crypto/sasl/plain/PlainRegistry.java create mode 100644 gnu/javax/crypto/sasl/plain/PlainServer.java create mode 100644 gnu/javax/crypto/sasl/srp/CALG.java create mode 100644 gnu/javax/crypto/sasl/srp/ClientStore.java create mode 100644 gnu/javax/crypto/sasl/srp/IALG.java create mode 100644 gnu/javax/crypto/sasl/srp/KDF.java create mode 100644 gnu/javax/crypto/sasl/srp/PasswordFile.java create mode 100644 gnu/javax/crypto/sasl/srp/SRP.java create mode 100644 gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java create mode 100644 gnu/javax/crypto/sasl/srp/SRPClient.java create mode 100644 gnu/javax/crypto/sasl/srp/SRPRegistry.java create mode 100644 gnu/javax/crypto/sasl/srp/SRPServer.java create mode 100644 gnu/javax/crypto/sasl/srp/SecurityContext.java create mode 100644 gnu/javax/crypto/sasl/srp/ServerStore.java create mode 100644 gnu/javax/crypto/sasl/srp/StoreEntry.java create mode 100644 gnu/javax/net/ssl/Base64.java create mode 100644 gnu/javax/net/ssl/EntropySource.java create mode 100644 gnu/javax/net/ssl/NullManagerParameters.java create mode 100644 gnu/javax/net/ssl/PrivateCredentials.java create mode 100644 gnu/javax/net/ssl/SRPManagerParameters.java create mode 100644 gnu/javax/net/ssl/SRPTrustManager.java create mode 100644 gnu/javax/net/ssl/StaticTrustAnchors.java create mode 100644 gnu/javax/net/ssl/provider/Alert.java create mode 100644 gnu/javax/net/ssl/provider/AlertException.java create mode 100644 gnu/javax/net/ssl/provider/Certificate.java create mode 100644 gnu/javax/net/ssl/provider/CertificateRequest.java create mode 100644 gnu/javax/net/ssl/provider/CertificateType.java create mode 100644 gnu/javax/net/ssl/provider/CertificateVerify.java create mode 100644 gnu/javax/net/ssl/provider/CipherSuite.java create mode 100644 gnu/javax/net/ssl/provider/ClientHello.java create mode 100644 gnu/javax/net/ssl/provider/ClientKeyExchange.java create mode 100644 gnu/javax/net/ssl/provider/CompressionMethod.java create mode 100644 gnu/javax/net/ssl/provider/Constructed.java create mode 100644 gnu/javax/net/ssl/provider/ContentType.java create mode 100644 gnu/javax/net/ssl/provider/Context.java create mode 100644 gnu/javax/net/ssl/provider/DiffieHellman.java create mode 100644 gnu/javax/net/ssl/provider/DigestInputStream.java create mode 100644 gnu/javax/net/ssl/provider/DigestOutputStream.java create mode 100644 gnu/javax/net/ssl/provider/Enumerated.java create mode 100644 gnu/javax/net/ssl/provider/Extension.java create mode 100644 gnu/javax/net/ssl/provider/Extensions.java create mode 100644 gnu/javax/net/ssl/provider/Finished.java create mode 100644 gnu/javax/net/ssl/provider/GNUSecurityParameters.java create mode 100644 gnu/javax/net/ssl/provider/Handshake.java create mode 100644 gnu/javax/net/ssl/provider/JCESecurityParameters.java create mode 100644 gnu/javax/net/ssl/provider/JDBCSessionContext.java create mode 100644 gnu/javax/net/ssl/provider/Jessie.java create mode 100644 gnu/javax/net/ssl/provider/JessieDHPrivateKey.java create mode 100644 gnu/javax/net/ssl/provider/JessieDHPublicKey.java create mode 100644 gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java create mode 100644 gnu/javax/net/ssl/provider/JessieRSAPublicKey.java create mode 100644 gnu/javax/net/ssl/provider/KeyPool.java create mode 100644 gnu/javax/net/ssl/provider/MacException.java create mode 100644 gnu/javax/net/ssl/provider/OverflowException.java create mode 100644 gnu/javax/net/ssl/provider/ProtocolVersion.java create mode 100644 gnu/javax/net/ssl/provider/Random.java create mode 100644 gnu/javax/net/ssl/provider/RecordInput.java create mode 100644 gnu/javax/net/ssl/provider/RecordInputStream.java create mode 100644 gnu/javax/net/ssl/provider/RecordOutputStream.java create mode 100644 gnu/javax/net/ssl/provider/RecordingInputStream.java create mode 100644 gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java create mode 100644 gnu/javax/net/ssl/provider/SSLHMac.java create mode 100644 gnu/javax/net/ssl/provider/SSLRSASignature.java create mode 100644 gnu/javax/net/ssl/provider/SSLRandom.java create mode 100644 gnu/javax/net/ssl/provider/SSLServerSocket.java create mode 100644 gnu/javax/net/ssl/provider/SSLServerSocketFactory.java create mode 100644 gnu/javax/net/ssl/provider/SSLSocket.java create mode 100644 gnu/javax/net/ssl/provider/SSLSocketFactory.java create mode 100644 gnu/javax/net/ssl/provider/SSLSocketInputStream.java create mode 100644 gnu/javax/net/ssl/provider/SSLSocketOutputStream.java create mode 100644 gnu/javax/net/ssl/provider/SecurityParameters.java create mode 100644 gnu/javax/net/ssl/provider/ServerHello.java create mode 100644 gnu/javax/net/ssl/provider/ServerKeyExchange.java create mode 100644 gnu/javax/net/ssl/provider/Session.java create mode 100644 gnu/javax/net/ssl/provider/SessionContext.java create mode 100644 gnu/javax/net/ssl/provider/Signature.java create mode 100644 gnu/javax/net/ssl/provider/SynchronizedRandom.java create mode 100644 gnu/javax/net/ssl/provider/TLSHMac.java create mode 100644 gnu/javax/net/ssl/provider/TLSRandom.java create mode 100644 gnu/javax/net/ssl/provider/Util.java create mode 100644 gnu/javax/net/ssl/provider/X509KeyManagerFactory.java create mode 100644 gnu/javax/net/ssl/provider/X509TrustManagerFactory.java create mode 100644 gnu/javax/net/ssl/provider/XMLSessionContext.java create mode 100644 gnu/javax/security/auth/Password.java create mode 100644 gnu/javax/security/auth/callback/AWTCallbackHandler.java create mode 100644 gnu/javax/security/auth/callback/AbstractCallbackHandler.java create mode 100644 gnu/javax/security/auth/callback/ConsoleCallbackHandler.java create mode 100644 gnu/javax/security/auth/callback/DefaultCallbackHandler.java create mode 100644 gnu/javax/security/auth/callback/GnuCallbacks.java create mode 100644 gnu/javax/security/auth/callback/SwingCallbackHandler.java create mode 100644 gnu/javax/security/auth/login/ConfigFileParser.java create mode 100644 gnu/javax/security/auth/login/ConfigFileTokenizer.java create mode 100644 gnu/javax/security/auth/login/GnuConfiguration.java create mode 100644 gnu/regexp/RETokenIndependent.java create mode 100644 gnu/regexp/RETokenLookBehind.java create mode 100644 gnu/regexp/RETokenNamedProperty.java create mode 100644 gnu/xml/validation/datatype/Annotation.java create mode 100644 gnu/xml/validation/datatype/AnySimpleType.java create mode 100644 gnu/xml/validation/datatype/AnyType.java create mode 100644 gnu/xml/validation/datatype/AnyURIType.java create mode 100644 gnu/xml/validation/datatype/AtomicSimpleType.java create mode 100644 gnu/xml/validation/datatype/Base64BinaryType.java create mode 100644 gnu/xml/validation/datatype/BooleanType.java create mode 100644 gnu/xml/validation/datatype/ByteType.java create mode 100644 gnu/xml/validation/datatype/DateTimeType.java create mode 100644 gnu/xml/validation/datatype/DateType.java create mode 100644 gnu/xml/validation/datatype/DecimalType.java create mode 100644 gnu/xml/validation/datatype/DoubleType.java create mode 100644 gnu/xml/validation/datatype/DurationType.java create mode 100644 gnu/xml/validation/datatype/EntitiesType.java create mode 100644 gnu/xml/validation/datatype/EntityType.java create mode 100644 gnu/xml/validation/datatype/EnumerationFacet.java create mode 100644 gnu/xml/validation/datatype/Facet.java create mode 100644 gnu/xml/validation/datatype/FloatType.java create mode 100644 gnu/xml/validation/datatype/FractionDigitsFacet.java create mode 100644 gnu/xml/validation/datatype/GDayType.java create mode 100644 gnu/xml/validation/datatype/GMonthDayType.java create mode 100644 gnu/xml/validation/datatype/GMonthType.java create mode 100644 gnu/xml/validation/datatype/GYearMonthType.java create mode 100644 gnu/xml/validation/datatype/GYearType.java create mode 100644 gnu/xml/validation/datatype/HexBinaryType.java create mode 100644 gnu/xml/validation/datatype/IDRefType.java create mode 100644 gnu/xml/validation/datatype/IDRefsType.java create mode 100644 gnu/xml/validation/datatype/IDType.java create mode 100644 gnu/xml/validation/datatype/IntType.java create mode 100644 gnu/xml/validation/datatype/IntegerType.java create mode 100644 gnu/xml/validation/datatype/LanguageType.java create mode 100644 gnu/xml/validation/datatype/LengthFacet.java create mode 100644 gnu/xml/validation/datatype/ListSimpleType.java create mode 100644 gnu/xml/validation/datatype/LongType.java create mode 100644 gnu/xml/validation/datatype/MaxExclusiveFacet.java create mode 100644 gnu/xml/validation/datatype/MaxInclusiveFacet.java create mode 100644 gnu/xml/validation/datatype/MaxLengthFacet.java create mode 100644 gnu/xml/validation/datatype/MinExclusiveFacet.java create mode 100644 gnu/xml/validation/datatype/MinInclusiveFacet.java create mode 100644 gnu/xml/validation/datatype/MinLengthFacet.java create mode 100644 gnu/xml/validation/datatype/NCNameType.java create mode 100644 gnu/xml/validation/datatype/NMTokenType.java create mode 100644 gnu/xml/validation/datatype/NMTokensType.java create mode 100644 gnu/xml/validation/datatype/NameType.java create mode 100644 gnu/xml/validation/datatype/NegativeIntegerType.java create mode 100644 gnu/xml/validation/datatype/NonNegativeIntegerType.java create mode 100644 gnu/xml/validation/datatype/NonPositiveIntegerType.java create mode 100644 gnu/xml/validation/datatype/NormalizedStringType.java create mode 100644 gnu/xml/validation/datatype/NotationType.java create mode 100644 gnu/xml/validation/datatype/PatternFacet.java create mode 100644 gnu/xml/validation/datatype/PositiveIntegerType.java create mode 100644 gnu/xml/validation/datatype/QNameType.java create mode 100644 gnu/xml/validation/datatype/ShortType.java create mode 100644 gnu/xml/validation/datatype/SimpleType.java create mode 100644 gnu/xml/validation/datatype/StringType.java create mode 100644 gnu/xml/validation/datatype/TimeType.java create mode 100644 gnu/xml/validation/datatype/TokenType.java create mode 100644 gnu/xml/validation/datatype/TotalDigitsFacet.java create mode 100644 gnu/xml/validation/datatype/Type.java create mode 100644 gnu/xml/validation/datatype/TypeBuilder.java create mode 100644 gnu/xml/validation/datatype/TypeLibrary.java create mode 100644 gnu/xml/validation/datatype/TypeLibraryFactory.java create mode 100644 gnu/xml/validation/datatype/UnionSimpleType.java create mode 100644 gnu/xml/validation/datatype/UnsignedByteType.java create mode 100644 gnu/xml/validation/datatype/UnsignedIntType.java create mode 100644 gnu/xml/validation/datatype/UnsignedLongType.java create mode 100644 gnu/xml/validation/datatype/UnsignedShortType.java create mode 100644 gnu/xml/validation/datatype/WhiteSpaceFacet.java delete mode 100644 include/java_lang_Math.h create mode 100644 include/java_lang_VMMath.h create mode 100644 java/awt/LightweightDispatcher.java create mode 100644 java/awt/print/NoPrinterJob.java create mode 100644 java/rmi/server/RemoteObjectInvocationHandler.java create mode 100644 java/util/regex/MatchResult.java create mode 100644 javax/print/SimpleDoc.java create mode 100644 javax/print/StreamPrintServiceFactory.java create mode 100644 javax/swing/plaf/synth/ColorType.java create mode 100644 javax/swing/plaf/synth/Region.java create mode 100644 javax/swing/plaf/synth/SynthConstants.java create mode 100644 javax/swing/plaf/synth/SynthContext.java create mode 100644 javax/swing/plaf/synth/SynthGraphicsUtils.java create mode 100644 javax/swing/plaf/synth/SynthLookAndFeel.java create mode 100644 javax/swing/plaf/synth/SynthPainter.java create mode 100644 javax/swing/plaf/synth/SynthStyle.java create mode 100644 javax/swing/plaf/synth/SynthStyleFactory.java create mode 100644 javax/swing/plaf/synth/package.html create mode 100644 javax/swing/text/AsyncBoxView.java create mode 100644 javax/swing/text/html/FormView.java create mode 100644 javax/swing/text/html/InlineView.java create mode 100644 javax/swing/text/html/NullView.java create mode 100644 javax/swing/text/html/ObjectView.java create mode 100644 javax/swing/text/html/Option.java create mode 100644 javax/swing/text/html/ParagraphView.java create mode 100644 native/fdlibm/e_cosh.c create mode 100644 native/fdlibm/e_hypot.c create mode 100644 native/fdlibm/e_log10.c create mode 100644 native/fdlibm/e_sinh.c create mode 100644 native/fdlibm/s_cbrt.c create mode 100644 native/fdlibm/s_expm1.c create mode 100644 native/fdlibm/s_log1p.c create mode 100644 native/fdlibm/s_tanh.c create mode 100644 native/fdlibm/w_cosh.c create mode 100644 native/fdlibm/w_hypot.c create mode 100644 native/fdlibm/w_log10.c create mode 100644 native/fdlibm/w_sinh.c delete mode 100644 native/jni/java-lang/java_lang_Math.c create mode 100644 native/jni/java-lang/java_lang_VMMath.c create mode 100644 resource/META-INF/services/org.relaxng.datatype.DatatypeLibraryFactory create mode 100644 resource/gnu/javax/security/auth/callback/MessagesBundle.properties create mode 100644 vm/reference/java/lang/VMMath.java diff --git a/.classpath b/.classpath index f17003859..60e126dbc 100644 --- a/.classpath +++ b/.classpath @@ -1,6 +1,8 @@ - + + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index ab52b98db..812e62a84 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,4 +1,4 @@ -#Tue Jan 11 17:36:29 MST 2005 +#Tue Feb 07 05:21:36 EST 2006 org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false @@ -68,7 +68,9 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18 org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=17 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=17 org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line @@ -178,16 +180,15 @@ org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=82 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 @@ -232,8 +233,11 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert org.eclipse.jdt.core.compiler.source=1.5 -org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=insert org.eclipse.jdt.core.formatter.continuation_indentation=2 org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false diff --git a/AUTHORS b/AUTHORS index 6e1359a1a..1be8b4406 100644 --- a/AUTHORS +++ b/AUTHORS @@ -22,6 +22,7 @@ Anthony Green (green@redhat.com) Jochen Hoenicke (Jochen.Hoenicke@Informatik.Uni-Oldenburg.de) Andrew John Hughes (gnu_andrew@member.fsf.org) Kazumitsu Ito (kaz@maczuka.gcd.org) +Olivier Jolly (olivier.jolly@pcedev.com) Brian Jones (cbj@gnu.org) Roman Kennke (roman@kennke.org) Michael Koch (konqueror@gmx.de) diff --git a/ChangeLog b/ChangeLog index 5490624c1..0b8150e46 100644 --- a/ChangeLog +++ b/ChangeLog @@ -46,6 +46,31 @@ (plus(MathContext)): Likewise. (numDigitsInLong): Fixed to properly handle negatives. +2006-02-25 Chris Burdess + + * gnu/java/net/CRLFInputStream.java, + gnu/java/net/LineInputStream.java: Streams that use mark + capabilities on the underlying stream do not expose mark + functionality themselves. + * gnu/xml/stream/CRLFReader.java: Fix incorrect end condition when + off > 0. + +2006-02-25 Ito Kazumitsu + + * gnu/regexp/REMatch.java(matchFlags): New int field used as + option flags passed to match methods. + (MF_FIND_ALL): New flag. + * gnu/regexp/RETokenOneOf.java(matchP): Unless MF_FIND_ALL is set, + do not try other possibilties once a match is found. + * gnu/regexp/RETokenRepeated.java(findDoables): Set MF_FIND_ALL + so that all possibilities can be found. + (match): Rewritten using new methods matchMinimum and _match. + (_match): New method which performs a depth-first recursive search. + (matchMinimum): New method. + (initVisited), (visitedContains), (addVisited): New methods for + manipulating an array of icharacter positions which _match has + already visited. + 2006-02-24 Anthony Balkissoon * java/math/BigDecimal.java: @@ -66,6 +91,113 @@ (toBigIntegerExact): New method. (stripTrailingZeros): Likewise. +2006-02-24 David Daney + + PR classpath/26082 + * gnu/java/net/protocol/http/HTTPConnection.java (pool): Changed to + type Pool. + (Pool): New inner class. + (timeLastUsed): New field. + (setPool): Changed parameter type to Pool. + (release): Moved pool management logic to new class Pool. + * gnu/java/net/protocol/http/HTTPURLConnection.java (connectionPool): + Removed. + (maxConnections) : Removed. + (GetHTTPPropertiesAction.run): Don't initialize maxConnections. + (getConnection): Moved pool management logic to HTTPConnection.Pool. + +2006-02-24 Lillian Angel + + * java/awt/Container.java: + Added new field. True if Container has been cleared and + heavyweights need to be repainted. + (paint): Fixed comment. Fixed to use backCleared and + reset backCleared. + (update): Set backCleared to true after the background + of the container has been cleared. + +2006-02-24 Lillian Angel + + * java/awt/TextField.java + (addNotify): Added call to super. + +2006-02-24 Lillian Angel + + * java/awt/Component.java + (reshape): Reverted last patch. Should have check here. + (addNotify): Added check. If parent is lightweight, then + initialize listener on the parent. + (HeavyweightInLightweightListener): New class. + +2006-02-24 Roman Kennke + + * javax/swing/plaf/basic/BasicComboPopup.java + (show): Register the popup with the autocloser after it has been + opened completely, by putting the registration on the eventqueue. + +2006-02-24 Andrew John Hughes + + * gnu/java/security/prng/BasePRNG.java: + (clone()): Added cast of buffer to byte[]. + * gnu/javax/crypto/mac/TMMH16.java: + (clone()): Fixed casting of cloned arrays. + * native/fdlibm/fdlibm.h: + Added missing defines from old fdlibm.h needed by Darwin. + (GET_FLOAT_WORD(i,d)): Re-added. + (SET_FLOAT_WORD(d,i)): Re-added. + +2006-02-24 Roman Kennke + + * java/awt/Container.java: + (dispatcher): Removed field. + (dispatchEventImpl): Removed lightweight dispatching. + (addNotifyContainerChildren): Removed LightweightDispatcher + handling. + (LightweightDispatcher): Removed class. + * java/awt/LightweightDispatcher.java: New class. + * java/awt/Toolkit.java + (Toolkit): Install LightweightDispatcher in global listener + array. + +2006-02-24 Chris Burdess + + Fixes PR 26324 + * gnu/java/net/CRLFInputStream.java: Fix incorrect end condition when + off > 0. + +2006-02-24 Andrew John Hughes + + * NEWS: Mentions the VMMath runtime changes. + * doc/vmintegration.texinfo: Updated to include + VMMath. + +2006-02-24 Roman Kennke + + * javax/swing/plaf/basic/BasicLookAndFeel.java + (PopupHelper.autoClosePopups): New field. + (PopupHelper.mousePressed): Also autoclose any registered popups. + (PopupHelper.registerForAutoClose): New method. + (PopupHelper.autoClosePopups): New method. + (popupHelper): Changed type of field to PopupHelper. + (registerForAutoClose): New method. + * javax/swing/plaf/basic/BasicComboPopup.java + (show): Register this popup for autoclosing. + +2006-02-24 Raif S. Naffah + + * gnu/javax/crypto/mac/TMMH16.java (clone): New method. + * gnu/java/security/prng/MDGenerator.java (clone): New method. + * gnu/java/security/prng/BasePRNG.java (clone): Clone buffer. + +2006-02-24 Roman Kennke + + Reported by Ingo Proetel + * java/util/logging/LogManager.java + (addLogger): Search the parent loggers for log level + configuration and inherit that. + (readConfiguration): Provide minimal default configuration + if no configuration can be found otherwise. + 2006-02-23 Anthony Balkissoon * java/math/BigDecimal.java: @@ -82,6 +214,316 @@ comments to explain behaviour. (scaleByPowerOfTen): New method. +2006-02-23 Roman Kennke + + * javax/swing/JRootPane.java + (isOptimizedDrawingEnabled): Implemented to return true + when the glassPane is not visible. + +2006-02-23 Roman Kennke + + * javax/swing/plaf/basic/BasicLookAndFeel.java + (PopupHelper): New inner class. + (popupHelper): New field. + (initialize): New method. + (uninitialize): New method. + * javax/swing/plaf/basic/BasicPopupMenuUI.java + (mouseInputListener): Removed field. + (PopupMenuHandler.popupMenuWillBecomeInvisible): Removed + handling of GlassPane. + (PopupMenuHandler.popupMenuWillBecomeVisible): Removed + handling of GlassPane. + (MouseInputHandler): Removed class. + +2006-02-23 Roman Kennke + + * java/awt/AWTEvent.java + (eventIdToMask): New utility method. + * java/awt/EventQueue.java + (dispatchEvent): Also globally dispatch events via the toolkit. + (globalDispatchEvent): New method. + * java/awt/Toolkit.java + (awtEventListeners): New field. + (Toolkit()): Initialize new field. + (createComponent): Create GLightweightPeer here. + (addAWTEventListener): Implemented and documented. + (removeAWTEventListener): Implemented and documented. + (getAWTEventListeners): Implemented and documented both method + variants. + * java/awt/event/AWTEventListenerProxy.java + (eventDispatched): Don't filter events here. + +2006-02-23 Chris Burdess + + Fixes PR 26410 + * gnu/xml/dom/DomDocumentBuilderFactory.java, + gnu/xml/dom/JAXPFactory.java, + gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java, + javax/xml/parsers/DocumentBuilderFactory.java: Add and trivially + implement DocumentBuilderFactory.get/setFeature methods. + +2006-02-23 Lillian Angel + + * gnu/java/awt/peer/GLightweightPeer.java + (repaint): Scott's proposed fix. Send repaint to the + component's parent. + * gnu/java/awt/peer/gtk/GtkComponentPeer.java + (setBounds): Removed next_parent, not needed. Removed + lightweightChild, we always need to compensate for the + menu bar's height. + * java/awt/Component.java + (setBounds): Removed check. Caused lots of problems, because some + components were not being invalidated. Components should be + invalidated when they are resized or moved, and in some cases, + when a parent is resized/moved, the components do not know + about it and do not adjust. + * java/awt/Graphics.java + (hitClip): Scott's proposed fix. Added check to handle a + null clip. + +2006-02-23 Wolfgang Baer + + * javax/print/attribute/standard/MediaSize.java: + (media): Field renamed to mediaName for serialization. + (MediaSize): Adapted to new fieldname. + (getMediaSizeName): Likewise. + * javax/print/attribute/HashAttributeSet.java: + (interfaceName): Field renamed to myInterface for serialization. + (HashAttributeSet): Adapted to the new fieldname. + (add): Likewise. + (addAll): Likewise. + (addInternal): Likewise. + (attributeMap): Made transient. + (readObject): New serialization method. + (writeObject): Likewise. + * javax/print/attribute/AttributeSetUtilities.java: + (SynchronizedAttributeSet.set): Field renamed to attrset for serialization. + (SynchronizedAttributeSet.add): Adapted to the new fieldname. + (SynchronizedAttributeSet.addAll): Likewise. + (SynchronizedAttributeSet.clear): Likewise. + (SynchronizedAttributeSet.containsKey): Likewise. + (SynchronizedAttributeSet.containsValue): Likewise. + (SynchronizedAttributeSet.equals): Likewise. + (SynchronizedAttributeSet.get): Likewise. + (SynchronizedAttributeSet.hashCode): Likewise. + (SynchronizedAttributeSet.isEmpty): Likewise. + (SynchronizedAttributeSet.remove): Likewise. + (SynchronizedAttributeSet.size): Likewise. + (SynchronizedAttributeSet.toArray): Likewise. + (UnmodifiableAttributeSet.set): Field renamed to attrset for serialization. + (UnmodifiableAttributeSet.add): Adapted to the new fieldname. + (UnmodifiableAttributeSet.addAll): Likewise. + (UnmodifiableAttributeSet.clear): Likewise. + (UnmodifiableAttributeSet.containsKey): Likewise. + (UnmodifiableAttributeSet.containsValue): Likewise. + (UnmodifiableAttributeSet.equals): Likewise. + (UnmodifiableAttributeSet.get): Likewise. + (UnmodifiableAttributeSet.hashCode): Likewise. + (UnmodifiableAttributeSet.isEmpty): Likewise. + (UnmodifiableAttributeSet.remove): Likewise. + (UnmodifiableAttributeSet.size): Likewise. + (UnmodifiableAttributeSet.toArray): Likewise. + * javax/print/attribute/standard/MediaPrintableArea.java: + (width): Field renamed to w for serialization. + (height): Field renamed to h for serialization. + (MediaPrintableArea): Adapted to the new fieldnames. + (MediaPrintableArea): Likewise. + (equals): Likewise. + (hashCode): Likewise. + (getHeight): Likewise. + (getWidth): Likewise. + +2006-02-23 Andrew John Hughes + + * include/java_lang_VMMath.h: + (Java_java_lang_VMMath_cbrt(JNIEnv*,jclass,jdouble)): Added. + (Java_java_lang_VMMath_cosh(JNIEnv*,jclass,jdouble)): Added. + (Java_java_lang_VMMath_expm1(JNIEnv*,jclass,jdouble)): Added. + (Java_java_lang_VMMath_hypot(JNIEnv*,jclass,jdouble,jdouble)): Added. + (Java_java_lang_VMMath_log10(JNIEnv*,jclass,jdouble)): Added. + (Java_java_lang_VMMath_log1p(JNIEnv*,jclass,jdouble)): Added. + (Java_java_lang_VMMath_sinh(JNIEnv*,jclass,jdouble)): Added. + (Java_java_lang_VMMath_tanh(JNIEnv*,jclass,jdouble)): Added. + * java/lang/Math.java: + (cbrt(double)): Implemented. + (cosh(double)): Implemented. + (expm1(double)): Implemented. + (hypot(double,double)): Implemented. + (log10(double)): Implemented. + (log1p(double)): Implemented. + (signum(double)): Implemented. + (signum(float)): Implemented. + (sinh(double)): Implemented. + (tanh(double)): Implemented. + * native/fdlibm/Makefile.am: + Added new files from fdlibm 5.3. + * native/fdlibm/e_acos.c, + * native/fdlibm/e_asin.c, + * native/fdlibm/e_atan2.c, + * native/fdlibm/e_exp.c, + * native/fdlibm/e_fmod.c, + * native/fdlibm/e_log.c, + * native/fdlibm/e_rem_pio2.c, + * native/fdlibm/e_remainder.c, + * native/fdlibm/e_scalb.c, + * native/fdlibm/e_sqrt.c, + * native/fdlibm/k_cos.c, + * native/fdlibm/k_rem_pio2.c, + * native/fdlibm/k_sin.c, + * native/fdlibm/k_tan.c, + * native/fdlibm/s_atan.c, + * native/fdlibm/s_ceil.c, + * native/fdlibm/s_copysign.c, + * native/fdlibm/s_cos.c, + * native/fdlibm/s_fabs.c, + * native/fdlibm/s_finite.c, + * native/fdlibm/s_floor.c, + * native/fdlibm/s_rint.c, + * native/fdlibm/s_scalbn.c, + * native/fdlibm/s_sin.c, + * native/fdlibm/s_tan.c, + * native/fdlibm/w_acos.c, + * native/fdlibm/w_asin.c, + * native/fdlibm/w_atan2.c, + * native/fdlibm/w_acos.c, + * native/fdlibm/w_exp.c, + * native/fdlibm/w_fmod.c, + * native/fdlibm/w_log.c, + * native/fdlibm/w_pow.c, + * native/fdlibm/w_remainder.c, + * native/fdlibm/w_sqrt.c: + Updated to fdlibm 5.3. + * native/fdlibm/e_cosh.c, + * native/fdlibm/e_hypot.c, + * native/fdlibm/e_log10.c, + * native/fdlibm/e_sinh.c, + * native/fdlibm/s_cbrt.c, + * native/fdlibm/s_expm1.c, + * native/fdlibm/s_log1p.c, + * native/fdlibm/s_tanh.c, + * native/fdlibm/w_cosh.c, + * native/fdlibm/w_hypot.c, + * native/fdlibm/w_log10.c, + * native/fdlibm/w_sinh.c: + Imported from fdlibm 5.3. + * native/fdlibm/fdlibm.h: + Imported from fdlibm 5.3 with Classpath additions. + * native/fdlibm/namespace.h: + Updated from new math_symbols file. + * native/jni/java-lang/java_lang_VMMath.c: + (Java_java_lang_VMMath_cbrt(JNIEnv*,jclass,jdouble)): Implemented. + (Java_java_lang_VMMath_cosh(JNIEnv*,jclass,jdouble)): Implemented. + (Java_java_lang_VMMath_expm1(JNIEnv*,jclass,jdouble)): Implemented. + (Java_java_lang_VMMath_hypot(JNIEnv*,jclass,jdouble,jdouble)): + Implemented. + (Java_java_lang_VMMath_log10(JNIEnv*,jclass,jdouble)): Implemented. + (Java_java_lang_VMMath_log1p(JNIEnv*,jclass,jdouble)): Implemented. + (Java_java_lang_VMMath_sinh(JNIEnv*,jclass,jdouble)): Implemented. + (Java_java_lang_VMMath_tanh(JNIEnv*,jclass,jdouble)): Implemented. + * scripts/math_symbols: + Added tanh, expm1, log10 and log1p. + * vm/reference/java/lang/VMMath.java: + (cbrt(double)): Implemented. + (cosh(double)): Implemented. + (expm1(double)): Implemented. + (hypot(double,double)): Implemented. + (log10(double)): Implemented. + (log1p(double)): Implemented. + (sinh(double)): Implemented. + (tanh(double)): Implemented. + +2006-02-23 Wolfgang Baer + + * javax/print/DocFlavor.java: Added documentation all over. + (BYTE_ARRAY.TEXT_HTML_HOST): Include host charset encoding to mimetype. + (BYTE_ARRAY.TEXT_PLAIN_HOST): Likewise. + (INPUT_STREAM.TEXT_HTML_HOST): Likewise. + (INPUT_STREAM.TEXT_PLAIN_HOST): Likewise. + (URL.TEXT_HTML_HOST): Likewise. + (URL.TEXT_PLAIN_HOST): Likewise. + (hostEncoding): Initialize with host default charset encoding. + (mediaSubtype): Made transient. + (mediaType): Likewise. + (params): Made transient. Changed type to TreeMap. + (className): Removed, changed to myClassName. + (myClassName): New field as defined in serialized form. + (DocFlavor): Adapted to new variable types, names. + (parseMimeType): Reimplemented. + (getParameter): Search with lowercase name. + (getRepresentationClassName): Adapted to changed variable name. + (hashCode): Likewise. + (toString): Reimplemented. + (readObject): New method for serialization. + (writeObject): Likewise. + +2006-02-23 Roman Kennke + + * javax/swing/RepaintManager.java + (commitBuffer): Clip the repaint area with the current clip. + +2006-02-23 Raif S. Naffah + + * gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java + (DEFAULT_PRIME_SIZE): Made public. + (DEFAULT_EXPONENT_SIZE): Likewise. + (setup): Handle DHParameterSpec as well. + * gnu/javax/crypto/key/dh/GnuDHKey.java (getEncoded): Return + defaultFormat instead of Raw. + * gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java + (checkIsConstructed): Removed. + (checkIsBigInteger): Likewise. + (decodePublicKey): Use DerUtil. + * gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java + (checkIsConstructed): Removed. + (checkIsBigInteger): Likewise. + (decodePrivateKey): Use DerUtil. + * gnu/javax/crypto/jce/GnuCrypto.java (run): Updated mapping of + KeyAgreement.DH. + Added mappings for AlgorithmParameters.DH and + AlgorithmParameterGenerator.DH. + * gnu/javax/crypto/jce/DiffieHellmanImpl.java: New file. + * gnu/javax/crypto/jce/sig/DHParametersGenerator.java: Likewise. + * gnu/javax/crypto/jce/sig/DHParameters.java: Likewise. + * gnu/javax/crypto/jce/sig/DHKeyFactory.java (engineGeneratePrivate): + Return result. + (engineGeneratePublic): Likewise. + * gnu/java/security/util/DerUtil.java: New file. + * gnu/java/security/sig/rsa/RSASignatureFactory.java (getNames): + Include only valid RSA PKCS1 (v1.5) signature names. + * gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java + (RSAPKCS1V1_5SignatureX509Codec): Removed. + (checkIsConstructed): Likewise. + * gnu/java/security/sig/dss/DSSSignatureX509Codec.java + (checkIsConstructed): Removed. + (checkIsBigInteger): Likewise. + (decodeSignature): Use DerUtil. + * gnu/java/security/key/rsa/RSAKeyPairX509Codec.java + (checkIsConstructed): Removed. + (checkIsBigInteger): Likewise. + (decodePublicKey): Use DerUtil. + * gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java + (checkIsConstructed): Removed. + (checkIsBigInteger): Likewise. + (decodePrivateKey): Use DerUtil. + * gnu/java/security/key/dss/DSSKeyPairX509Codec.java + (checkIsConstructed): Removed. + (checkIsBigInteger): Likewise. + (decodePublicKey): Use DerUtil. + * gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java + (checkIsConstructed): Removed. + (checkIsBigInteger): Likewise. + (decodePrivateKey): Use DerUtil. + * gnu/java/security/key/dss/DSSKeyPairGenerator.java + (DEFAULT_MODULUS_LENGTH): Made it public. + * gnu/java/security/key/dss/DSSKey.java (getEncoded): Return + defaultFormat instead of Raw. + * gnu/java/security/jce/sig/DSSParametersGenerator.java: New file. + * gnu/java/security/jce/sig/DSSParameters.java: Likewise.. + * gnu/java/security/jce/sig/DSSKeyFactory.java (engineGeneratePrivate): + Return result. + (engineGeneratePublic): Likewise. + * gnu/javax/crypto/DiffieHellmanImpl: Removed. + 2006-02-22 Anthony Balkissoon * java/math/BigDecimal.java: @@ -91,6 +533,71 @@ (BigDecimal(char[], int, int)): Likewise. (BigDecimal(String)): Fixed handling of exponent and scale. +2006-02-22 Mark Wielaard + + * java/awt/Checkbox.java (setState): Check that state actually changed + before calling peer. + (dispatchEventImpl): Set new state if ItemEvent. + * gnu/java/awt/peer/gtk/GtkCheckboxPeer.java (changing): Removed. + (create): Set currentState. + (setState): Make synchronized, check and set currentState before + calling gtkToggleButtonSetActive. + (postItemEvent): Make synchronized, check and set currentState before + posting ItemEvent. + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c + (postItemEventID): Method now takes boolean. + (item_toggled_cb): Likewise. + +2006-02-22 Robert Schuster + + * javax/swing/text/DefaultHighlighter.java: + (changeHighlight): Added code to minimize the damaged area. + +2006-02-22 Robert Schuster + + * javax/swing/text/PlainDocument.java: + (getPreferredSpan): Added missing 'break'. + statement which corrects an unwanted fall through. + (updateDamage): Update maxLineLength correctly when text is + removed, call preferenceChanged accordingly. + (viewToModel): Restrict line number to be within 0 and the + number of elements-1. + +2006-02-22 Robert Schuster + + * javax/swing/text/Utilities.java: + (getPositionAbove): Prefer first value by changing comparison + from < to <=. + (getPositionBelow): Dito. + +2006-02-22 Robert Schuster + + * javax/swing/text/DefaultEditorKit.java: Added checks and fallback + behavior when magic caret position is null. + +2006-02-22 Roman Kennke + + * javax/swing/JTextField.java + (isValidateRoot): New method. + +2006-02-22 Roman Kennke + + * javax/swing/JEditorPane.java + (getPreferredSize): Rewritten to behave like the reference impl. + (getScrollableTracksViewportWidth): Likewise. + (getScrollableTracksViewportHeight): Likewise. + +2006-02-22 Roman Kennke + + * javax/swing/RepaintManager.java + (addInvalidComponent): Also consider the component itself. + +2006-02-22 Mark Wielaard + + * javax/swing/text/html/HTMLDocument.java (createDefaultRoot): Fully + qualify AbstractDocument.AttributeContext. + (blockOpen): Likewise. + 2006-02-21 Anthony Balkissoon * java/math/BigDecimal.java: @@ -112,6 +619,4974 @@ * java/math/MathContext.java: New class. * java/math/RoundingMode: New Enum. +2006-02-21 Mark Wielaard + + * java/awt/Component.java (translateEvent): Translate + AdjustmentEvents to 1.0 Events. + * java/awt/Scrollbar.java (dispatchEventImpl): Set valueIsAdjusting. + Call setValue() before processing event. + * gnu/java/awt/peer/gtk/GtkScrollbarPeer.java (setValues): Check + whether we are currently changing and being called back from the + Scrollbar component. + (setBarValues): New native method. + (postAdjustmentEvent): Mark AdjustmentEvent as user generated. + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkScrollbarPeer.c + (Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_setValues): Renamed to + Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_setBarValue + * include/gnu_java_awt_peer_gtk_GtkScrollbarPeer.h: Regenerated. + +2006-02-21 Roman Kennke + + * javax/swing/text/View.java + (setParent): Set child parent to null when disconnecting + the view from the View hierarchy. + +2006-02-21 Wolfgang Baer + + * javax/print/StreamPrintService.java: Added and enhanced documentation. + +2006-02-21 Roman Kennke + + * javax/swing/text/WrappedPlainView.java + (calculateBreakPosition): Changed to use the view's allocation instead + of the container's preferredSize. + +2006-02-21 Wolfgang Baer + + * java/awt/CardLayout.java: + (first): Updated api documentation. + (last): Likewise. + (next): Likewise. + (previous): Likewise. + (show): Clarified api docs. Return if name is null. Throw + IllegalArgumentException if layout of container is not this. + (gotoComponent): Updated api documentation. Throw + IllegalArgumentException if layout of container is not this. + +2006-02-21 Roman Kennke + + * javax/swing/text/NavigationFilter.java + (getNextVisualPositionFrom): New method. + +2006-02-21 Roman Kennke + + * javax/swing/plaf/basic/BasicTextUI.java + (RootView.setView): Call setParent() on the view with this as + argument instead of null. + (setView): Don't set root view's parent here. + +2006-02-21 Roman Kennke + + * javax/swing/text/AbstractDocument.java + (AbstractElement.getAttribute): Use getResolveParent() to fetch + the resolving parent. + (AbstractElement.getResolveParent): Fixed to handle possible null + parent. + * javax/swing/text/BoxView.java + (childReqs): New field. + (paint): Added debugging code (commented out). + (getPreferredSpan): Rewritten to use new update* methods. + (getMaximumSpan): Rewritten to return Integer.MAX_VALUE + for the minor axis and preferredSpan for the major axis. + (getMinimumSpan): Rewritten to use new update* methods. + (baselineRequirements): Rewritten to avoid creation of + unnecessary SizeRequirements objects. + (baselineLayout): Rewritten to use new update* methods. + (calculateMajorAxisRequirements): Rewritten to avoid creation of + unnecessary SizeRequirements objects. + (calculateMinorAxisRequirements): Rewritten to avoid creation of + unnecessary SizeRequirements objects. + (layout): Some robustness fixes for the layout. Turned AssertionErrors + into warnings. + (layoutMajorAxis): Rewritten to use new update* methods. + (layoutMinorAxis): Rewritten to use new update* methods. + (getChildRequirements): Replaced by the update* methods. + (getAlignment): Use update* methods. + (updateChildRequirements): New methods. Updates the child requirements + if necessary. + (updateRequirements): New methods. Updates the BoxView requirements + if necessary. + * javax/swing/text/DefaultStyledDocument.java + (ElementBuffer.insert): Added warning for illegal replacement operation. + * javax/swing/text/FlowView.java + (layoutRow): When offset doesn't change, return -1. + (LogicalView): Now subclasses BoxView. + (loadChildren): Let the CompositeView.setParent() load the children + of the logicalView. + (calculateMinorRequirements): New overridden method. + * javax/swing/text/GlyphView.java + (DefaultGlyphPainter.paint): Fixed typo. + (startOffset): Made field private. + (endOffset): Made field private. + (paint): Call getStartOffset() and getEndOffset() instead of the + element methods. + (isStrikeThrough): Fixed typo. + (breakView): Use Utilities.getBreakLocation() to determine best + break location. + (changedUpdate): Call preferencedChange on this instead of parent. + (removeUpdate): Call preferencedChange on this instead of parent. + * javax/swing/text/ParagraphView.java + (Row.getAlignment): For Y_AXIS, call super. + (getAlignment): Likewise. + * javax/swing/text/Utilities.java + (getBreakLocation): Set Segment object directly on the BreakIterator. + * javax/swing/text/html/HTML.java + (Attribute): Made class non-serializable and final as specified. + (Attribute(String)): Made constructor private. + (Attribute.compareTo): Removed. + (Attribute.equals): Removed. + (Attribute.hashCode): Removed. + (Tag): Made class non-comparable and non-serializable as specified. + (Tag.compareTo): Removed. + (Tag.equals): Removed. + (Tag.hashCode): Removed. + * javax/swing/text/html/HTMLDocument.java + (HTMLReader.blockOpen): Add tag as name attribute to element. + * javax/swing/text/html/HTMLEditorKit.java + (HTMLFactory.create): Create NullView for tags, removed unused + fallback. + * javax/swing/text/html/InlineView.java + (setPropertiesFromAttributes): Call super. + * javax/swing/text/html/NullView.java: New class. + +2006-02-21 Roman Kennke + + PR classpath/26368 + * javax/swing/text/GapContent.java + (GapContentPosition): Made class private. + (InsertUndo): Made class private. + (UndoRemove): Made class private. + (WeakPositionComparator): New inner class. + (positions): Made field private. + (createPosition): Clear up GC'ed positions before creating + a new one. Store position as WeakReference. + (getPositionsInRange): Changed to handle WeakReference + positions. + (setPositionsInRange): Changed to handle WeakReference + positions. + (adjustPositionsInRange): Changed to handle WeakReference + positions. + (dumpPositions): Handle WeakReference positions. + (clearPositionReferences): New method. + +2006-02-21 Robert Schuster + + * javax/swing/plaf/basic/BasicTextUI.java: + (paint): Remove unneccessary part of the if-expression. + (damageRange): Added case where the range spans multiple lines. + * javax/swing/text/DefaultCaret.java: + (clearHighlight): New method. + (handleHighlight): Removed unneccessary part of the if-expression. + (setDot): Use clearHighlight method. + * javax/swing/text/DefaultHighlighter.java: Use ArrayList instead + of Vector. + (paint): Prevented calling size() on every loop iteration, fixed + calculation of allocation area bounds. + (getHighlights): Implemented. + (removeHighlight): Mark damaged area in textcomponent. + (addHighlight): Mark damaged area in textcomponent. + (changeHighlight): Mark damaged area in textcomponent. + (DefaultHighlighter.HighlightEntry): Made it a real + Highlighter.Highlight implementation. + (DefaultHighlighter.DefaultHighlightPainter.paint): Fixed + calculations. + +2006-02-20 Stuart Ballard + + * java/util/zip/ZipConstants.java + (LOCSIG): Change type to long. + (EXTSIG): Likewise. + (CENSIG): Likewise. + (ENDSIG): Likewise. + * java/util/zip/ZipOutputStream.java + (writeLeInt(long)): New method. + +2006-02-21 Michael Koch + + * gnu/javax/net/ssl/provider/PRNG.java: Removed. + +2006-02-20 Mark Wielaard + + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c + (begin_drawing_operation): Output stacktrace and return on bad cairo + status. + (end_drawing_operation): Likewise. And reset cairo_t. + +2006-02-20 Robert Schuster + + * javax/swing/text/DefaultEditorKit.java: Fixed comparison + in backward selection action. + +2006-02-20 Olivier Jolly + + * java/lang/reflect/Proxy.java: + (ProxyData.getProxyData): Skipped overriding of core methods. + (ProxyData.isCoreObjectMethod): New method. + +2006-02-20 Mark Wielaard + + * gnu/java/nio/charset/Provider.java (Provider): Package private. + +2006-02-20 Roman Kennke + + * javax/swing/text/html/Option.java: New class. + +2006-02-20 Lillian Angel + + * java/swt/Window.java + (show): Calling show() on the owned windows caused problems. + Changed back to get the peer and call setVisible. + +2006-02-20 Roman Kennke + + * javax/swing/plaf/basic/BasicTextUI.java + (damageRange): Implemented this method. + +2006-02-20 Robert Schuster + + * javax/swing/text/GapContent.java: + (shiftGapEndUp): Corrected new mark value. + * javax/swing/text/AbstractDocument.java: + (remove): Changed order of operations. + +2006-02-20 Robert Schuster + + * javax/swing/text/GapContent.java: + (shiftGapEndUp): Reverted. + * javax/swing/text/AbstractDocument.java: + (remove): Reverted. + +2006-02-20 Robert Schuster + + * javax/swing/text/GapContent.java: + (shiftGapEndUp): Corrected new mark value. + * javax/swing/text/AbstractDocument.java: + (remove): Changed order of operations. + +2006-02-20 Mark Wielaard + + * java/awt/Menu.java (add(MenuItem)): Use item.getParent() to get + parent field. + (insert): Likewise. + (addNotify): Add the item after addNotifying it. + * java/awt/MenuBar.java (setHelpMenu): Only call removeNotify() when + there is a peer. Use getParent() and setParent() to manipulate parent + field. + (add(Menu)): Use getParent() and setParent() to manipulate parent + field. Call addNotify() and addMenu() when there is a peer. + (remove(int)): Call removeNotify() and delMenu() when there is a peer. + (addNotify): Use getPeer()/setPeer(). Call addMenu() and addHelpMenu() + when there is a peer. + * gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java (create): Document. + (GtkMenuComponentPeer): Document. Take MenuComponent as argument. + (setFont): Call setFont(Font). + (setFont(Font)): Document. Only set font when not null. + * gnu/java/awt/peer/gtk/GtkMenuItemPeer.java (create): Document. Made + protected. + (connectSignals): Likewise. + (GtkMenuItemPeer): Document. Don't try to add item. Always call + connectSignals(). + * gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java (create): Make + protected. + (postMenuActionEvent): Document. + * gnu/java/awt/peer/gtk/GtkMenuPeer.java (create): Document. Made + protected. + (addItem): Document. Made private. + (addTearOff): Made private. + (connectSignals): New protected overridden method. + (GtkMenuPeer): Correctly cast setupAccelGroup() arguments. + * gnu/java/awt/peer/gtk/GtkMenuBarPeer.java (hasHelpMenu): New field. + (create): Document. + (addMenu): Made private, take GtkMenuPeer as argument and document. + (GtkMenuBarPeer): Document. + (nativeSetHelpMenu): Removed. + (addHelpMenu): Implement. + (delMenu): Document. + (addMenu): Implement. + * gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java (setParent): Removed. + * include/gnu_java_awt_peer_gtk_GtkMenuBarPeer.h: Regenerated. + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuBarPeer.c + (Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_nativeSetHelpMenu): + Removed. + +2006-02-20 Audrius Meskauskas + + * gnu/java/rmi/server/RMIObjectInputStream.java (resolveProxyClass): + Expect that proxy interfaces may have different class loaders. + * gnu/java/rmi/server/UnicastServerRef.java: Rewritten. + * java/rmi/registry/Registry.java, + * java/rmi/server/UnicastRemoteObject.java: + Documented about proxy stubs. + * gnu/java/rmi/server/CombinedClassLoader.java, + java/rmi/server/RemoteObjectInvocationHandler.java: New files. + * NEWS: Added entry. + +2006-02-19 Mark Wielaard + + * gnu/java/awt/peer/gtk/GtkContainerPeer.java (endValidate): Set + Parent and Bounds of our children if either or parent is showing, or + we are a Window and are showing ourselves now. + +2006-02-19 Audrius Meskauskas + + * gnu/classpath/tools/rmi/rmic/RmicCompiler.java (convertStubName): + New method. + * gnu/classpath/tools/rmi/rmic/templates/Stub_12.jav: + Another stub name fix. + +2006-02-19 Audrius Meskauskas + + * gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java (compile): + Call convertStubName. (convertStubName): New method. + * gnu/classpath/tools/rmi/RMIC.java (main): Stub name fix. + * gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java + (convertStubName): New method. + (getMethodHashCode): + Use existing gnu.java.rmi.server.RMIHashes.getMethodHash. + * gnu/classpath/tools/rmi/rmic/templates/Stub_12.jav: Stub name fix. + +2006-02-19 Audrius Meskauskas + + * java/rmi/server/UnicastRemoteObject.java: Documenting. + +2006-02-19 Audrius Meskauskas + + * gnu/java/rmi/server/UnicastServerRef.java: Reformatted. + +2006-02-18 Audrius Meskauskas + + * javax/swing/JViewport.java (paintBackingStore): If the component has + not been scrolled, only repaint the buffer part, indicated by + the parameter graphics clip. + +2006-02-19 Raif S. Naffah + + * gnu/javax/crypto/key/OutgoingMessage.java (writePublicKey): Handle new + internal format. + (writePrivateKey): Likewise. + (writeKey): New method. + (getKeyType): Likewise. + * gnu/javax/crypto/key/IncomingMessage.java (readPublicKey): Handle new + internal format. + (readPrivateKey): Likewise. + (getKeyPairCodec): New method. + * gnu/javax/crypto/key/srp6/SRPKey.java (getFormat): Always return Raw. + * gnu/javax/crypto/key/dh/GnuDHKey.java (getFormat): Use FormatUtil. + * gnu/java/security/Registry.java (RSA_SIG_PREFIX): New constant. + (RSA_PSS_ENCODING): Likewise.. + (RSA_PKCS1_V1_5_ENCODING): Likewise. + (RSA_PSS_SIG): Redefined using other constants. + (RSA_PKCS1_V1_5_SIG): Likewise. + (MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE): New constant. + * gnu/java/security/util/FormatUtil.java: New file. + * gnu/java/security/sig/SignatureFactory.java (names): New field. + (getInstance): Let RSASignatureFactory handle RSA signature names. + (getNames): Handle new RSA signature (with format) names. + * gnu/java/security/sig/SignatureCodecFactory.java: New file. + * gnu/java/security/sig/BaseSignature.java (BaseSignature): Add check + for null md. + (name): Include hash algorithm name. + * gnu/java/security/sig/rsa/RSASignatureFactory.java: New file. + * gnu/java/security/sig/rsa/RSAPSSSignature.java + (RSAPSSSignature): Call constructor with IMessageDigest. + (RSAPSSSignature(ImessageDigest,int)): New constructor. + * gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java: New + file. + * gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java: + Likewise. + * gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java + (RSAPKCS1V1_5Signature(String)): Call constructor with IMessageDigest. + (RSAPKCS1V1_5Signature(IMessageDigest)): New constructor. + * gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java (getInstance): Added + hash algorithm name to exception. + * gnu/java/security/sig/dss/DSSSignatureX509Codec.java: New file. + * gnu/java/security/key/KeyPairCodecFactory.java + (names): New class field. + (getInstance(Sitrng)): Deconstruct and call getInstance(String,String). + (getInstance(String,String)): New method. + (getInstance(String,int)): New method. + (getInstance(byte[])): Removed. + (getInstance(Key)): Handle new formats. + (getNames): Likewise. + (getEncodingName(int)): Moved to FormatUtil. + (getEncodingShortName(int)): Likewise. + (getRawCodec(String)): New method. + (getX509Codec(String)): Likewise. + (getPKCS8Codec(String)): Likewise. + (getRawCodec(Key)): Likewise. + (getX509Codec(Key)): Likewise. + (getPKCS8Codec(Key)): Likewise. + * gnu/java/security/key/dss/DSSKey.java (getFormat): Use FormatUtil. + * gnu/java/security/key/rsa/GnuRSAKey.java (getFormat): Likewise. + * gnu/java/security/jce/sig/SHA512withRSA.java: New File. + * gnu/java/security/jce/sig/SHA384withRSA.java: Likewise. + * gnu/java/security/jce/sig/SHA256withRSA.java: Likewise. + * gnu/java/security/jce/sig/SHA160withRSA.java: Likewise. + * gnu/java/security/jce/sig/SHA160withDSS.java: Likewsie. + * gnu/java/security/jce/sig/MD5withRSA.java: Likewise. + * gnu/java/security/jce/sig/MD2withRSA.java: Likewise. + +2006-02-18 Mark Wielaard + + * java/awt/dnd/DragSource.java (getDefaultDragSource): Return new + DragSource. + (NoDragGestureRecognizer): New static class. + (createDragGestureRecognizer): Return NoDragGestureRecognizer when + Toolkit doesn't support drag and drop. + +2006-02-18 Mark Wielaard + + * javax/swing/AbstractAction.java (AbstractAction()): Nothing to do. + (AbstractAction(String)): Just call putValue() for NAME. + (putValue): Nothing to do is old and new value are both null. + +2006-02-18 Mark Wielaard + + * javax/swing/JRootPane.java (layoutContainer): Get contentPane + through getContentPane(). + (preferredLayoutSize): Likewise. + +2006-02-18 Mark Wielaard + + * javax/swing/JMenuBar.java (paintBorder): Check whether border is + actually set before painting. + +2006-02-18 Mark Wielaard + + * javax/swing/text/html/HTMLDocument.java (addContent): + Fully qualify AbstractDocument.AttributeContext and + DefaultStyledDocument.ElementSpec.ContentType for gcj 4.0. + +2006-02-18 Mark Wielaard + + * java/awt/datatransfer/DataFlavor.java (tryToLoadClass): Rewritten. + (getRepresentationClassFromMime): Add exception cause to + IllegalArgumentException. + +2006-02-17 Lillian Angel + + * gnu/java/awt/peer/gtk/GtkComponentPeer.java: + Removed unneeded import. + * gnu/java/awt/peer/gtk/GtkFramePeer.java: + Removed unneeded imports. + * java/awt/BorderLayout.java: + Fixed comment, this is not yet handled in the JDK 1.5. + * java/awt/Container.java: + Removed unneeded import. + +2006-02-17 Lillian Angel + + * gnu/java/awt/peer/gtk/GtkComponentPeer.java + (setBounds): Removed check. Coordinates should always be changed + to incorporate the parent's coordinates. + * gnu/java/awt/peer/gtk/GtkFramePeer.java + (setMenuBar): Added checks. Don't validate component if it has + not been validated yet, it will be validated later. Only validate + if it has already been validated, in that case it needs to be + revalidated. + * java/awt/Window.java + (show): Added check. If the window is visible, then bring it to the + front. Otherwise, iterate through all its children windows and show them. + No need to do both. + +2006-02-17 Roman Kennke + + * javax/swing/text/html/ParagraphView.java: New file. + +2006-02-17 Audrius Meskauskas + + * javax/swing/JTable.java (getCellRect): return +rowMargin if spacing + is included. (moveToCellBeingEdited): Adjusted to start editing at the + same location where was the initial text. + * javax/swing/plaf/basic/BasicTableUI.java (paint): Rewritten. + +2006-02-17 Chris Burdess + + Fixes PRs 26319, 26320, 26321, 26322, 26325 + * gnu/xml/stream/SAXParser.java: On error, reset parser before + rethrowing exception. + * gnu/xml/stream/XMLParser.java: Only report "illegal use of + 1.1-style prefix unbinding in 1.0 document" error for xmlns + prefixes, not xmlns attributes. Fix a problem with empty namespace + stack at the end of a document. Permit parameter entity references + in element and attribute-list definition name area. Corrected + normalisation of whitespace character entity references in CDATA + attribute values. Fixed number of characters read following a + reset when detecting end of character data with characters after a + Unicode surrogate pair. + +2006-02-17 Roman Kennke + + * javax/swing/text/html/HTMLEditorKit.java + (HTMLFactory.create): Create InlineView for content tags. + * javax/swing/text/html/HTMLDocument.java + (HTMLReader.flush): Call create() on first flush and insert + on subsequent flushes. + +2006-02-17 Roman Kennke + + * javax/swing/text/AbstractDocument.java + (BranchElement.getStartOffset): Implemented workaround for wrong + NPE. + (BranchElement.getEndOffset): Implemented workaround for wrong + NPE. + (ElementBuffer.split): Use createBranchElement() instead of + new BranchElement(). + (ElementBuffer.insertFracture): Use createBranchElement() instead of + new BranchElement(). + (ElementBuffer.recreateAfterFracture): Use createBranchElement() + instead of new BranchElement(). + (createDefaultRoot): Use createBranchElement() and createLeafElement + instead of the constructors. + (create): Rewritten. + +2006-02-17 Keith Seitz + + * gnu/classpath/jdwp/id/JdwpId.java (size): Remove. + (SIZE): New constant. + * gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java + (executeIDsizes): Use SIZE constant. + * vm/reference/gnu/classpath/jdwp/VMFrame.java (size): Remove. + (SIZE): New constant. + +2006-02-17 Audrius Meskauskas + + * javax/swing/JTable.java (IconCellRenderer): Set the component + text to empty string. (createDefaultRenderers): Register + IconCellRenderer also for ImageIcon. + (getCellEditor(int, int), getCellRenderer(int, int)): + Use model index for data model and column index for column model. + (getColumnClass): Convert to model index before requesting class + from model. + +2006-02-17 Roman Kennke + + * javax/swing/text/html/HTMLDocument.java + (createDefaultRoot): Implemented. + (createLeafElement): Implemented. + (createBranchElement): Implemented. + (BlockElement.getName): Fixed to handle HTML.Tag objects as name. + (RunElement.getName): Fixed to handle HTML.Tag objects as name. + (HTMLReader.ParagraphAction.start): Call blockOpen at the very least. + (HTMLReader.ParagraphAction.end): Call blockClose at the very least. + (HTMLReader.blockOpen): Add name attribute with the current tag. + (HTMLReader.addContent): Add name attribute with HTML.Tag.CONTENT. + +2006-02-17 Audrius Meskauskas + + * javax/swing/plaf/basic/BasicTableHeaderUI.java (MouseInputHandler): + Rewritten. + * javax/swing/table/JTableHeader.java: Documenting related methods. + +2006-02-17 Jeroen Frijters + + Fixes PR 25752 + * gnu/java/net/protocol/ftp/FTPURLConnection.java + (connect): Changed to use SystemProperties. + (getInputStream): Try changeWorkingDirectory to figure out if + url is a directory, if not use retrieve. + (getOutputStream): Don't worry about directories, simply always + try to do a store. + +2006-02-17 Jeroen Frijters + + * gnu/java/net/protocol/ftp/ActiveModeDTP.java + (ActiveModeDTP): Mark accept thread as daemon. + +2006-02-17 Michael Koch + + * tools/.cvsignore: Ignore tools.zip. + +2006-02-16 Keith Seitz + + * vm/reference/gnu/classpath/jdwp/VMIdManager.java (newReferenceTypeId): + Set the ID's reference. + (): Remove comments for field, method, and frame ID types, + which will not be handled by VMIdManager. + +2006-02-17 Audrius Meskauskas + + * javax/swing/JTable.java (getCellEditor, getCellRenderer): + Use model index, not the column number. + * javax/swing/plaf/basic/BasicTableHeaderUI.java (MouseInputHandler): + Rewritten. (draggingHeaderRect): New field. (paint): Animate column + movement by painting draggingHeaderRect. + * NEWS: Added entry about JTable columns. + +2006-02-16 Keith Seitz + + * gnu/classpath/jdwp/id/JdwpId.java (size): Make static. Return + default size of eight bytes. + * gnu/classpath/jdwp/id/ObjectId.java (size): Remove. + * gnu/classpath/jdwp/id/ReferenceTypeId.java (size): Remove. + * gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java + (executeIDsizes): Use new static methods. + * vm/reference/gnu/classpath/jdwp/VMFrame.java (size): New static + method. + +2006-02-16 David Daney + + PR classpath/26312 + * gnu/java/net/protocol/http/ChunkedInputStream.java (read): Mask + return value with 0xff. + +2006-02-16 Keith Seitz + + * gnu/classpath/jdwp/event/EventRequest.java (getFilters): New method. + (matches): Use Iterator instead of ListIterator. + +2006-02-16 Keith Seitz + + * gnu/classpath/jdwp/Jdwp.java (_doInitialization): Name the packet + processor thread for easier debugging. + (_enforceSuspendPolicy): Suspend the current thread, not the JDWP + main thread. + +2006-02-16 Audrius Meskauskas + + * javax/swing/JTable.java + (TableColumnPropertyChangeHandler.propertyChange): Return without + action if table header resizing column in not null. (doLayout): + Only repaint the header if it is not null. + * javax/swing/plaf/basic/BasicTableHeaderUI.java + (MouseInputHandler.mouseExited, MouseInputHandler.mouseReleased): + Rewritten. (MouseInputHandler.endResizing): New method. + +2006-02-16 Roman Kennke + + * javax/swing/text/html/InlineView.java: New file. + +2006-02-16 Roman Kennke + + * javax/swing/JTabbedPane.java + (AccessibleJTable.getAccessibleChild): Implemented to return + the Page instance for the specified index. + (Page): Changed to implement Accessible and extend + AccessibleContext. + (Page.getAccessibleContext): New method. + (Page.getAccessibleRole): New method. + (Page.getAccessibleStateSet): New method. + (Page.getAccessibleIndexInParent): New method. + (Page.getAccessibleChildrenCount): New method. + (Page.getAccessibleChild): New methdod. + (Page.getLocale): New method. + +2006-02-16 Roman Kennke + + * javax/swing/plaf/basic/BasicTabbedPaneUI.java + (TabbedPaneLayout.calculateTabRects): Expand tabRuns array when + tabCount gets greater than tabRuns.length. + (TabbedPaneScrollLayout.calculateTabRects): Expand tabRuns array + when tabCount gets greater than tabRuns.length. + (paintTabArea): Don't set tabCount == runCount. + +2006-02-16 Roman Kennke + + * javax/swing/plaf/basic/BasicTextUI.java + (installUI): Moved installation of PropertyChangeListener + to installListeners(). Call modelChanged() after everything is + is installed. + (installListeners): Install PropertyChangeListener here. + (uninstallUI): Moved uninstallation of PropertyChangeListener + to uninstallListeners. + (uninstallListeners): Uninstall PropertyChangeListener here. + +2006-02-16 Audrius Meskauskas + + * javax/swing/JTable.java (doLayout): + case AUTO_RESIZE_SUBSEQUENT_COLUMNS rewritten. Repaint the header + on exit. + javax/swing/plaf/basic/BasicTableHeaderUI.java + (MouseInputHandler.mouseDragged): Do not repaint the header. + +2006-02-16 Roman Kennke + + * javax/swing/JViewport.java + (static_initializer): Set default scrollMode to backingstore. + +2006-02-16 Audrius Meskauskas + + * javax/swing/JTable.java (moveToCellBeingEdited): Clone the value, + returned by getCellRect. To not translate the component. + +2006-02-16 Roman Kennke + + * javax/swing/JComponent.java + (rectCache): Made field non-static to avoid nasty interferences. + (computeVisibleRect): Avoid creation of new Rectangles and double + calculations on ints by using Swing.computeIntersection() instead + of Rectangle2D.intersect(). + (repaint): Interect the dirty region with the visible rectangle + of this component to avoid unnecessary painting. + +2006-02-16 Gary Benson + + * java/lang/Thread.java (stop): Add a missing access check. + +2006-02-16 Robert Schuster + + * javax/swing/text/JTextComponent.java: + (replaceSelection): Added code to update the magic caret position. + * javax/swing/text/DefaultEditorKit.java: Added code to update + the magic caret position of the text component in all relevant + movement actions, make use of the magic caret position in up + and down movements and selections, simplified some actions + (code-wise). + +2006-02-15 Anthony Balkissoon + + * gnu/java/lang/CharData.java: Regenerated from + doc/unicode/UnicodeData-4.0.0.txt, doc/unicode/SpecialCasing-4.0.0.txt + and scripts/unicode-muncher.pl. + * java/lang/Character.java: + (PrivateUseCharacters): New private static class. + (UnassignedCharacters): Likewise. + (blocks): Changed from char[] to char[][] to reflect the changes in + gnu/java/lang/CharData. There is now one char[] per Unicode code + plane. + (data): Likewise. + (numValue): Likewise. + (upper): Likewise. + (lower): Likewise. + (direction): Likewise. + (readChar): Replaced this method with new method readCodePoint. + (readCodePoint): New method. + (isLowerCase(char)): Redirected to new isLowerCase(int). + (isLowerCase(int)): New method. + (isUpperCase(char)): Redirected to new isUpperCase(int). + (isUpperCase(int)): New method. + (isTitleCase(char)): Redirected to new isTitleCase(int). + (isTitleCase(int)): New method. + (isDigit(char)): Redirected to new isDigit(int). + (isDigit(int)): New method. + (isDefined(char)): Redirected to new isDefined(int). + (isDefined(int)): New method. + (isLetter(char)): Redirected to new isLetter(int). + (isLetter(int)): New method. + (isLetterOrDigit(char)): Redirected to new isLetterOrDigit(int). + (isLetterOrDigit(int)): New method. + (isJavaIdentifierStart(char)): Redirected to new + isJavaIdentifierStart(int). + (isJavaIdentifierStart(int)): New method. + (isJavaIdentifierPart(char)): Redirected to new + isJavaIdentifierPart(int). + (isJavaIdentifierPart(int)): New method. + (isUnicodeIdentifierStart(char)): Redirected to new + isUnicodeIdentifierStart(int). + (isUnicodeIdentifierStart(int)): New method. + (isUnicodeIdentifierPart(char)): Redirected to new + isUnicodeIdentifierPart(int). + (isUnicodeIdentifierPart(int)): New method. + (isIdentifierIgnorable(char)): Redirected to new + isIdentifierIgnorable(int). + (isIdentifierIgnorable(int)): New method. + (toLowerCase(char)): Changed access to lower to correspond with new + char[][] type of lower. + (toLowerCase(int)) New method. + (toUpperCase(char)): Changed access to upper to correspond with new + char[][] type of upper. + (toUpperCase(int)): New method. + (toTitleCase(int)): New method. + (digit(char, int)): Replaced call to readChar with call to + readCodePoint and changed access to numValue to reflect new char[][] + type of numValue. + (digit(int, int)): New method. + (getNumericValue(char)): Changed access to numValue to reflect new + char[][] type of numValue. + (getNumericValue(int)): New method. + (isSpaceChar(char)): Redirected to new isSpaceChar(int). + (isSpaceChar(int)): New method. + (isWhitespace(char)): Redirected to new isWhitespace(int). + (isWhitespace(int)): New method. + (isISOControl(char)): Redirected to new isISOControl(int). + (isISOControl(int)): New method. + (getType(char)): Redirected to new getType(int). + (getType(int)): New method. + (getDirectionality(char)): Redirected to new getDirectionality(int). + (getDirectionality(int)): New method. + (isMirrored(char)): Changed call to readChar to readCodePoint. + (isMirrored(int)): New method. + * java/lang/String.java: + (upperCaseExpansion): Changed access to Character.direction to reflect + new char[][] type of direction. + (offsetByCodePoints): New method. + * scripts/unicode-muncher.pl: Adapted this script to handle Unicode + 4.0.0 which introduced supplementary character assignments. + +2006-02-15 Audrius Meskauskas + + * javax/swing/JTable.java, + javax/swing/plaf/basic/BasicTableHeaderUI.java, + javax/swing/table/DefaultTableModel.java: Documented. + +2006-02-15 Lillian Angel + + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c: + Removed duplicate methods. + +2006-02-15 Audrius Meskauskas + + * javax/swing/JTable.java (distributeSpillResizing): New method. + (doLayout): Use distributeSpillResizing when resizing. + * javax/swing/plaf/basic/BasicTableHeaderUI.java (MouseInputHandler): + Rewritten. (installListeners): Add mouse motion listener. + (uninstallListeners): Remove mouse motion listener. + +2006-02-15 Lillian Angel + + * gnu/java/awt/peer/gtk/GtkDialogPeer.java + (setVisible): Removed method. + * gnu/java/awt/peer/gtk/GtkWindowPeer.java + (setLocation): New method. + (setLocationUnlocked): New method. + (show): Changed to use setLocation instead of setBounds. + * java/awt/Component.java + (show): Should call peer.show(), not peer.setVisible(), so the + location of the component is correctly set. + (preferredSize): Added curly braces so else statements are + properly associated with if's. + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c + (Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetLocation): + New function. + (Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSet + LocationUnlocked): New function. + * include/gnu_java_awt_peer_gtk_GtkWindowPeer.h: + Added declarations for Java_gnu_java_awt_peer_gtk_ + GtkWindowPeer_nativeSetLocation and + Java_gnu_java_awt_peer_gtk_GtkWindowPeer + _nativeSetLocationUnlocked. + +2006-02-15 Mark Wielaard + + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer.c + (Java_gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer_create): + Downcast gtk_plug_new result when used. + +2006-02-15 Olivier Jolly + + * java/io/ObjectOutputStream.java (writeClassDescriptor): + Call assignNewHandle() after writing Proxy class. + +2006-02-15 Olivier jolly + + Fixes bug #14144 + * java/io/ObjectInputStream.java (readClassDescriptor): + Class doesn't have to be abstract for first_nonserial. + +2006-02-15 Roman Kennke + + * javax/swing/JInternalFrame.java + (setClosed): Call dispose to actually make the frame invisible + and unselected. + +2006-02-15 Roman Kennke + + * javax/swing/JInternalFrame.java + (dispose): Call setVisible(false) instead of hide. + (doDefaultCloseOperation): Likewise. + +2006-02-15 Roman Kennke + + * javax/swing/JComponent.java + (paintChildren): Also check for the visibility of a child component + to avoid artifacts. + (repaint): Simply add this component to the RepaintManager rather than + trying to do useless optimization here. + +2006-02-15 David Gilbert + + * javax/swing/JSpinner.java + (DefaultEditor.DefaultEditor(JSpinner)): Add self to text field as a + PropertyChangeListener, + (DefaultEditor.getSpinner): Updated API docs, + (DefaultEditor.dismiss): Likewise, + (DefaultEditor.getTextField): Likewise, + (DefaultEditor.layoutContainer): Likewise, + (DefaultEditor.minimumLayoutSize): Likewise, + (DefaultEditor.preferredLayoutSize): Likewise, + (DefaultEditor.propertyChange): Implemented, + (DefaultEditor.stateChanged): Implemented, + (DefaultEditor.removeLayoutComponent): Updated API docs, + (DefaultEditor.addLayoutComponent): Likewise, + (NumberEditor.NumberEditor(JSpinner)): Set formatter for text field, + (NumberEditor.NumberEditor(JSpinner, String)): Likewise, + (NumberEditor.getFormat): Implemented, + (NumberEditor.getModel): Updated API docs, + (NumberEditorFormatter): New static inner class, + (ListEditor.getModel): Updated API docs, + (DateEditor.dateFormat): Removed, + (DateEditor.DateEditor(JSpinner)): Set formatter for text field, + (DateEditor.DateEditor(JSpinner, String)): Likewise, + (DateEditor.init): Removed, + (DateEditor.getFormat): Reimplemented, + (DateEditorFormatter): New static inner class, + (ModelListener): New inner class, + (model): Updated API docs, + (editor): Likewise, + (listener): Removed, + (JSpinner()): Updated API docs, + (JSpinner(SpinnerModel)): Set up ModelListener, + (setEditor): Fire property change, + (getModel): Updated API docs, + (setModel): Removed check for null editor, + (setValue): Updated API docs, + (getUIClassID): Updated API docs, + (createEditor): Handle SpinnerListModel case, + * javax/swing/plaf/basic/BasicSpinnerUI.java + (createUI): Updated API docs, + (createPropertyChangeListener): Added FIXME, + (installDefaults): Set text field border to null, + (DefaultLayoutManager): Updated API docs, + (DefaultLayoutManager.layoutContainer): Modified layout, + (DefaultLayoutManager.minimumLayoutSize): Ignore button heights, + (DefaultLayoutManager.preferredLayoutSize): Likewise, + (DefaultLayoutManager.removeLayoutComponent): Removed tabs, + (DefaultLayoutManager.addLayoutComponent): Likewise, + (DefaultLayoutManager.minSize): Renamed prefSize, + (DefaultLayoutManager.setBounds): Reformatted, + (DefaultLayoutManager.editor): Added API docs, + (DefaultLayoutManager.next): Likewise, + (DefaultLayoutManager.previous): Likewise, + * javax/swing/plaf/metal/MetalLookAndFeel.java + (initComponentDefaults): Added entry for 'Spinner.border', + * examples/gnu/classpath/examples/swing/SpinnerDemo.java: New file. + +2006-02-15 Chris Burdess + + * gnu/xml/validation/datatype/BooleanType.java, + gnu/xml/validation/datatype/ByteType.java, + gnu/xml/validation/datatype/DateTimeType.java, + gnu/xml/validation/datatype/DateType.java, + gnu/xml/validation/datatype/DecimalType.java, + gnu/xml/validation/datatype/DoubleType.java, + gnu/xml/validation/datatype/DurationType.java, + gnu/xml/validation/datatype/FloatType.java, + gnu/xml/validation/datatype/GDayType.java, + gnu/xml/validation/datatype/GMonthDayType.java, + gnu/xml/validation/datatype/GMonthType.java, + gnu/xml/validation/datatype/GYearMonthType.java, + gnu/xml/validation/datatype/GYearType.java, + gnu/xml/validation/datatype/IntType.java, + gnu/xml/validation/datatype/IntegerType.java, + gnu/xml/validation/datatype/LongType.java, + gnu/xml/validation/datatype/MaxExclusiveFacet.java, + gnu/xml/validation/datatype/MaxInclusiveFacet.java, + gnu/xml/validation/datatype/MinExclusiveFacet.java, + gnu/xml/validation/datatype/MinInclusiveFacet.java, + gnu/xml/validation/datatype/NegativeIntegerType.java, + gnu/xml/validation/datatype/NonNegativeIntegerType.java, + gnu/xml/validation/datatype/NonPositiveIntegerType.java, + gnu/xml/validation/datatype/PositiveIntegerType.java, + gnu/xml/validation/datatype/ShortType.java, + gnu/xml/validation/datatype/SimpleType.java, + gnu/xml/validation/datatype/TimeType.java, + gnu/xml/validation/datatype/TypeBuilder.java, + gnu/xml/validation/datatype/UnsignedByteType.java, + gnu/xml/validation/datatype/UnsignedIntType.java, + gnu/xml/validation/datatype/UnsignedLongType.java, + gnu/xml/validation/datatype/UnsignedShortType.java: Provide value + objects for datatypes. Make maxExclusive,minExclusive,maxInclusive, + minInclusive facets use the value space of the base type, and + implement. + +2006-02-15 Mark Wielaard + + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer.c + (Java_gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer_create): + gtk_plug_new() returns a GtkWindow. + +2006-02-15 David Gilbert + + * javax/swing/SpinnerNumberModel.java + (getNextValue): Check for null maximum, + (getPreviousValue): Check for null minimum. + +2006-02-15 Roman Kennke + + * javax/swing/plaf/basic/BasicTableUI.java + (paint): Paint vertical and horizontal lines one pixel shifted + left/top. + +2006-02-15 Jeroen Frijters + + * java/util/zip/ZipFile.java + (checkZipFile): Inlined readLeInt and rewritten for robustness. + (readLeShort(DataInput,byte[]), readLeInt(DataInput,byte[], + readLeShort(byte[],int), readLeInt(byte[],int)): Removed. + (readEntries): Rewritten to use PartialInputStream. + (locBuf, checkLocalHeader): Removed. + (getInputStream): Rewritten to use new PartialInputStream. + (PartialInputStream): Rewritten to do buffering. + +2006-02-15 Michael Koch + + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer.c + (Java_gnu_java_awt_peer_gtk_GtkEmbeddedWindowPeer_create): + Make sure the embedded window gets no decorations. + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c + (window_get_frame_extents): Return early of the window has no + decorations. + +2006-02-15 Audrius Meskauskas + + * examples/gnu/classpath/examples/swing/TableDemo.java + (TModel, createContent): Explain which value appears in the header. + * javax/swing/JTable.java (setColumnModel): Only set the + column header value if the getHeaderValue() returns null. + +2006-02-14 Mark Wielaard + + Fixes bug #23931 + * gnu/java/awt/peer/gtk/GtkImage.java (errorImage): New static field. + (getErrorImage): New static method. + * gnu/java/awt/peer/gtk/GtkToolkit.java (GtkErrorImage): Removed. + (bufferedImageOrError): Renamed to ... + (imageOrError): Renamed from bufferedImageOrError, takes Image. + Returns GtkImage.getErrorImage() when argument null. + (createImage(String)): Always use imageOrError. + (createImage(URL)): Likewise. + (createImage(ImageProducer)): Likewise. + (createImage(byte[],int,int)): Likewise. + +2006-02-14 Roman Kennke + + * javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java: Removed + unneeded imports. + * javax/swing/plaf/basic/BasicInternalFrameUI.java: Likewise. + * javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java: Likewise. + * javax/swing/plaf/basic/BasicRootPaneUI.java: Likewise. + * javax/swing/plaf/basic/BasicSplitPaneDivider.java: Likewise. + * javax/swing/plaf/basic/BasicHTML.java: Fixed API comment. + +2006-02-14 Roman Kennke + + * javax/swing/text/AsyncBoxView.java + (ChildState.locator): Removed wrong field. + (ChildState): Removed initialization of removed field. + (locator): Changed access modifier to be protected as specified. + +2006-02-14 Roman Kennke + + * javax/swing/ToolTipManager.java: Removed unneeded imports. + * javax/swing/Timer.java: Some small reindention. + (task): Made package private to avoid synthetic accessor method. + +2006-02-14 Roman Kennke + + * javax/swing/SwingUtilities.java + (layoutCompoundLabel): Dont set textIconGap to 0 when there is + no icon. + +2006-02-14 Audrius Meskauskas + + * examples/gnu/classpath/examples/swing/TableDemo.java: + Making the columns variable width. + * javax/swing/JTable.java (distributeSpill, doLayout): + Call getPreferredSize and not getSize(). + +2006-02-14 Roman Kennke + + * javax/swing/DefaultCellEditor.java + (DefaultCellEditor): API doc fixlet. + +2006-02-14 Roman Kennke + + * javax/swing/JViewport.java + (isPaintRoot): New field. + (repaint): Only call super here. Also added a comment regarding + the diversion from the JDK. + (paintBlit): Implemented real blitting. + (paintImmediately2): New method. Overrides the same package private + method in JComponent. + +2006-02-14 Roman Kennke + + * javax/swing/plaf/basic/BasicTableUI.java + (paint): Check for boundary cases when determining the painting + area. + +2006-02-14 Mark Wielaard + + * java/awt/Menu.java (add): Always set parent of item to this. Call + addNotify() on item when we have a MenuPeer already. + (insert): Always adjust parent for item. Call addNotify() on item if + we already have a peer. + (remove(int)): Always clear item parent. Call removeNotify() on item + if we had a peer. + +2006-02-14 Audrius Meskauskas + + * javax/swing/JTable.java (rowAtPoint): Return -1 if the computed + row == getRowCount(). + +2006-02-14 Lillian Angel + + * gnu/java/awt/peer/gtk/GtkDialogPeer.java + (setVisible): New method to override super. Need to set the + native bounds of the component, so it appears at the + correct location. + +2006-02-14 Mark Wielaard + + * java/awt/Frame.java (setMenuBar): Update MenuBar parent. + (remove): If menu component is the current MenuBar remove it, + otherwise call super.remove(). + * java/awt/MenuBar.java (frame): Remove field. + * java/awt/MenuComponent.java (postEvent): Use getParent() always. + +2006-02-14 Audrius Meskauskas + + * tools/gnu/classpath/tools/giop/NameServicePersistent.java: Refer + to NameServicePersistent. + * tools/gnu/classpath/tools/giop/NameServicePersistent.txt: New file. + * tools/gnu/classpath/tools/giop/NamingServicePersistent.txt: Deleted. + +2006-02-14 Audrius Meskauskas + + * NEWS: Updated tool status. + * gnu/CORBA/NamingService/NamingMap.java (Map): Made protected. + (constructor, bind, rebind): Rewritten. + * gnu/CORBA/NamingService/TransientContext.java: Rewritten. + * tools/gnu/classpath/tools/giop/README: Updated. + * tools/gnu/classpath/tools/giop/NameServicePersistent.java, + tools/gnu/classpath/tools/giop/NamingServicePersistent.txt, + tools/gnu/classpath/tools/giop/nameservice/PersistentContext.java, + tools/gnu/classpath/tools/giop/nameservice/PersistentContextMap.java, + tools/gnu/classpath/tools/giop/nameservice/PersistentMap.java: + New files. + +2006-02-14 David Gilbert + + * javax/swing/JComponent.java + (getListeners): Check for PropertyChangeListener.class and delegate to + getPropertyChangeListeners() for that case. + +2006-02-13 Roman Kennke + + * javax/swing/plaf/basic/BasicTableUI.java + (paint): Determine the cells that need painting based on the + current clip. Use getCellRect() for calculating the cell + bounds. + +2006-02-13 Roman Kennke + + * javax/swing/JTable.java + (rectCache): New field. + (getCellRect): Returns cached Rectangle instance. + +2006-02-13 Roman Kennke + + * javax/swing/JLayeredPane.java + (removeAll): New method. Avoid potential memory leak. + (isOptimizedDrawingEnabled): Replaced heuristic with accurate + calculation. + +2006-02-14 Stuart Ballard + + * javax/swing/undo/StateEdit.java (RCSID): Match Sun's value. + * javax/swing/undo/StateEditable.java (RCSID): Likewise. + +2006-02-13 Tom Tromey + + * vm/reference/java/lang/reflect/Method.java: Javadoc fix. + * vm/reference/java/lang/reflect/Constructor.java: Javadoc fix. + +2006-02-13 Roman Kennke + + * javax/swing/RepaintManager.java + (offscreenBuffers): New field. + (doubleBuffer): Removed field. + (repaintUnderway): New field. + (commitRequests): New field. + (RepaintManager): Initialize new fields. + (paintDirtyRegions): Handle repaintUnderway flag. Commit + buffers when done. + (getOffscreenBuffer): Returns the offscreen buffer for the + corresponding root component. + (commitBuffer): New method. + (commitRemainingBuffers): New method. + * javax/swing/JComponent.java + (paint): Call paintDoubleBuffered with the current clip. + (paintImmediately2): Don't paint on screen here. + (paintDoubleBuffered): Rewritten for real double buffering. + (paintSimple): Draw to screen in this method. + +2006-02-13 Roman Kennke + + * javax/swing/JRootPane.java + (JRootPane): Set opaque property to true. + +2006-02-13 Tom Tromey + + * .classpath: Updated for external/relaxngDatatype. + +2006-02-13 Chris Burdess + + * gnu/xml/stream/UnicodeReader.java, + gnu/xml/validation/datatype/Annotation.java, + gnu/xml/validation/datatype/AnySimpleType.java, + gnu/xml/validation/datatype/AnyType.java, + gnu/xml/validation/datatype/AnyURIType.java, + gnu/xml/validation/datatype/AtomicSimpleType.java, + gnu/xml/validation/datatype/Base64BinaryType.java, + gnu/xml/validation/datatype/BooleanType.java, + gnu/xml/validation/datatype/ByteType.java, + gnu/xml/validation/datatype/DateTimeType.java, + gnu/xml/validation/datatype/DateType.java, + gnu/xml/validation/datatype/DecimalType.java, + gnu/xml/validation/datatype/DoubleType.java, + gnu/xml/validation/datatype/DurationType.java, + gnu/xml/validation/datatype/EntitiesType.java, + gnu/xml/validation/datatype/EntityType.java, + gnu/xml/validation/datatype/EnumerationFacet.java, + gnu/xml/validation/datatype/Facet.java, + gnu/xml/validation/datatype/FloatType.java, + gnu/xml/validation/datatype/FractionDigitsFacet.java, + gnu/xml/validation/datatype/GDayType.java, + gnu/xml/validation/datatype/GMonthDayType.java, + gnu/xml/validation/datatype/GMonthType.java, + gnu/xml/validation/datatype/GYearMonthType.java, + gnu/xml/validation/datatype/GYearType.java, + gnu/xml/validation/datatype/HexBinaryType.java, + gnu/xml/validation/datatype/IDRefType.java, + gnu/xml/validation/datatype/IDRefsType.java, + gnu/xml/validation/datatype/IDType.java, + gnu/xml/validation/datatype/IntType.java, + gnu/xml/validation/datatype/IntegerType.java, + gnu/xml/validation/datatype/LanguageType.java, + gnu/xml/validation/datatype/LengthFacet.java, + gnu/xml/validation/datatype/ListSimpleType.java, + gnu/xml/validation/datatype/LongType.java, + gnu/xml/validation/datatype/MaxExclusiveFacet.java, + gnu/xml/validation/datatype/MaxInclusiveFacet.java, + gnu/xml/validation/datatype/MaxLengthFacet.java, + gnu/xml/validation/datatype/MinExclusiveFacet.java, + gnu/xml/validation/datatype/MinInclusiveFacet.java, + gnu/xml/validation/datatype/MinLengthFacet.java, + gnu/xml/validation/datatype/NCNameType.java, + gnu/xml/validation/datatype/NMTokenType.java, + gnu/xml/validation/datatype/NMTokensType.java, + gnu/xml/validation/datatype/NameType.java, + gnu/xml/validation/datatype/NegativeIntegerType.java, + gnu/xml/validation/datatype/NonNegativeIntegerType.java, + gnu/xml/validation/datatype/NonPositiveIntegerType.java, + gnu/xml/validation/datatype/NormalizedStringType.java, + gnu/xml/validation/datatype/NotationType.java, + gnu/xml/validation/datatype/PatternFacet.java, + gnu/xml/validation/datatype/PositiveIntegerType.java, + gnu/xml/validation/datatype/QNameType.java, + gnu/xml/validation/datatype/ShortType.java, + gnu/xml/validation/datatype/SimpleType.java, + gnu/xml/validation/datatype/StringType.java, + gnu/xml/validation/datatype/TimeType.java, + gnu/xml/validation/datatype/TokenType.java, + gnu/xml/validation/datatype/TotalDigitsFacet.java, + gnu/xml/validation/datatype/Type.java, + gnu/xml/validation/datatype/TypeBuilder.java, + gnu/xml/validation/datatype/TypeLibrary.java, + gnu/xml/validation/datatype/TypeLibraryFactory.java, + gnu/xml/validation/datatype/UnionSimpleType.java, + gnu/xml/validation/datatype/UnsignedByteType.java, + gnu/xml/validation/datatype/UnsignedIntType.java, + gnu/xml/validation/datatype/UnsignedLongType.java, + gnu/xml/validation/datatype/UnsignedShortType.java, + gnu/xml/validation/datatype/WhiteSpaceFacet.java, + resource/META-INF/services/org.relaxng.datatype.DatatypeLibraryFactory: + RELAX NG datatype library implementation for XML Schema Datatypes. + +2006-02-13 Chris Burdess + + * LICENCE, + NEWS, + configure.ac, + doc/README.jaxp, + external/Makefile.am, + external/relaxngDatatype/.cvsignore, + external/relaxngDatatype/Makefile.am, + external/relaxngDatatype/README.txt, + external/relaxngDatatype/copying.txt, + external/relaxngDatatype/org/relaxng/datatype/Datatype.java, + external/relaxngDatatype/org/relaxng/datatype/DatatypeBuilder.java, + external/relaxngDatatype/org/relaxng/datatype/DatatypeException.java, + external/relaxngDatatype/org/relaxng/datatype/DatatypeLibrary.java, + external/relaxngDatatype/org/relaxng/datatype/DatatypeLibraryFactory.java, + external/relaxngDatatype/org/relaxng/datatype/DatatypeStreamingValidator.java, + external/relaxngDatatype/org/relaxng/datatype/ValidationContext.java, + external/relaxngDatatype/org/relaxng/datatype/helpers/DatatypeLibraryLoader.java, + external/relaxngDatatype/org/relaxng/datatype/helpers/ParameterlessDatatypeBuilder.java, + external/relaxngDatatype/org/relaxng/datatype/helpers/StreamingValidatorImpl.java, + lib/Makefile.am, + lib/gen-classlist.sh.in: Added external RELAX NG pluggable + datatypes library API. + +2006-02-13 Mark Wielaard + + * gnu/java/awt/peer/gtk/GtkGenericPeer.java (awtWidget): Made field + final. + (gtkWidgetModifyFont(Font)): New protected helper method. + (gtkWidgetModifyFont(String,int,int)): Made protected and document. + * gnu/java/awt/peer/gtk/GtkButtonPeer.java (gtkWidgetModifyFont): Made + protected and document. + * gnu/java/awt/peer/gtk/GtkCheckboxPeer.java (gtkWidgetModifyFont): + Likewise. + * gnu/java/awt/peer/gtk/GtkLabelPeer.java (gtkWidgetModifyFont): + Likewise. + * gnu/java/awt/peer/gtk/GtkListPeer.java (gtkWidgetModifyFont): + Likewise. + * gnu/java/awt/peer/gtk/GtkMenuBarPeer.java (create): Made protected. + (setFont): Removed method. Done in GtkMenuComponent. + * gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java (create): Made + abstract and protected. + (setFont): Made private, add implementation. + (setFont(Font)): Implemented. + * gnu/java/awt/peer/gtk/GtkMenuItemPeer.java (gtkWidgetModifyFont): + Made protected and document. + (create): Made protected. + (setFont): Removed method. Done in GtkMenuComponent. + * gnu/java/awt/peer/gtk/GtkTextAreaPeer.java + (gtkWidgetModifyFont): Made protected and document. + * gnu/java/awt/peer/gtk/GtkTextFieldPeer.java (gtkWidgetModifyFont): + Removed, similar to GtkGenericPeer super class implementation. + * include/gnu_java_awt_peer_gtk_GtkTextFieldPeer.h: Regenerated. + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextFieldPeer.c + (Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_gtkWidgetModifyFont): + Removed. + +2006-02-13 Mark Wielaard + + * java/lang/Math.java (static): Explicitly call + System.loadLibrary("javalang"). + +2006-02-13 Wolfgang Baer + + * javax/print/StreamPrintServiceFactory.java: New file. + +2006-02-13 Tom Tromey + + * tools/.cvsignore: Added Makefile. + +2006-02-13 Wolfgang Baer + + * java/awt/print/PrinterGraphics.java: Reformatted. + * java/awt/print/Paper.java: Likewise. + * java/awt/print/PageFormat.java: Likewise. + * java/awt/print/Pageable.java: Likewise. + +2006-02-13 Lillian Angel + + * java/awt/BorderLayout.java + (layoutContainer): Rewrote part of this function to + properly set the bounds of the components. + (setBounds): Removed method, not needed. + +2006-02-13 Roman Kennke + + * javax/swing/text/DefaultStyledDocument.java + (ElementBuffer.clone): Fixed replace call. + (clone): Removed method. + +2006-02-13 Roman Kennke + + * java/rmi/server/UnicastRemoteObject.java: Reformatted. + +2006-02-13 Roman Kennke + + * java/rmi/server/UnicastRemoteObject.java + (exportObject(Remote)): Forward method call to export(Remote,int). + +2006-02-13 Andrew John Hughes + + * include/Makefile.am: + Swapped Math.h for VMMath.h + * include/java_lang_Math.h: + Removed. + * include/java_lang_VMMath.h: + New autogenerated header for the new class. + * java/lang/Math.java: + (sin(double)): Changed to link to VMMath. + (cos(double)): Changed to link to VMMath. + (tan(double)): Changed to link to VMMath. + (asin(double)): Changed to link to VMMath. + (acos(double)): Changed to link to VMMath. + (atan(double)): Changed to link to VMMath. + (atan2(double)): Changed to link to VMMath. + (exp(double)): Changed to link to VMMath. + (log(double)): Changed to link to VMMath. + (sqrt(double)): Changed to link to VMMath. + (pow(double,double)): Changed to link to VMMath. + (IEEEremainder(double,double)): Changed to link to VMMath. + (ceil(double)): Changed to link to VMMath. + (floor(double)): Changed to link to VMMath. + (rint(double)): Changed to link to VMMath. + * native/jni/java-lang/Makefile.am: + Replaced java_lang_Math.c with java_lang_VMMath.c + * native/jni/java-lang/java_lang_Math.c: + Removed. + * native/jni/java-lang/java_lang_VMMath.c: + Renamed from java_lang_Math.c. + * vm/reference/java/lang/VMMath.java: + New class. + (sin(double)): New native method. + (cos(double)): New native method. + (tan(double)): New native method. + (asin(double)): New native method. + (acos(double)): New native method. + (atan(double)): New native method. + (atan2(double)): New native method. + (exp(double)): New native method. + (log(double)): New native method. + (sqrt(double)): New native method. + (pow(double,double)): New native method. + (IEEEremainder(double,double)): New native method. + (ceil(double)): New native method. + (floor(double)): New native method. + (rint(double)): New native method. + +2006-02-13 Lillian Angel + + * java/awt/Component.java + (repaint): No need to call isShowing, it is done in the other repaint call. + (repaint): Likewise. + (repaint): Likewise. + +2006-02-13 Lillian Angel + + * java/awt/Component.java + (repaint): Reverted last change. + (repaint): Likewise. + (repaint): Likewise. + +2006-02-13 Lillian Angel + + * gnu/java/awt/peer/gtk/GtkPanelPeer.java + (handleEvent): Made more efficent by handling paint event and + setting the clip for the graphics. + * gnu/java/awt/peer/gtk/GtkWindowPeer.java + (handleEvent): Likewise. + * java/awt/Component.java + (repaint): No need to call isShowing, it is done in the other repaint call. + (repaint): Likewise. + (repaint): Likewise. + +2006-02-13 Roman Kennke + + * javax/swing/text/AbstractDocument.java + (setParent): Added API docs. Call setParent(null) on children before + disconnecting this view from the View hierarchy. + +2006-02-13 Roman Kennke + + * javax/swing/text/AbstractDocument.java + (readUnlock): Don't attempt to unlock when the current threads also + holds a write lock. + +2006-02-13 David Gilbert + + * javax/swing/plaf/metal/MetalBorders.java + (ButtonBorder.getBorderInsets(Component)): Return insets directly, + (ButtonBorder.getBorderInsets(Component, Insets)): Don't check for null + insets argument, + (Flush3DBorder.borderInsets): New field, + (Flush3DBorder.getBorderInsets(Component)): Return insets directly, + (Flush3DBorder.getBorderInsets(Component, Insets)): Don't check for + null insets argument, and populate result from borderInsets, + (PaletteBorder.borderInsets): New field, + (PaletteBorder.getBorderInsets(Component)): Return insets directly, + (PaletteBorder.getBorderInsets(Component, Insets)): Don't check for + null insets argument, and populate result from borderInsets, + (InternalFrameBorder.borderInsets): New field, + (InternalFrameBorder.getBorderInsets(Component)): Return insets + directly, + (InternalFrameBorder.getBorderInsets(Component, Insets)): Don't check + for null insets argument, and populate result from borderInsets, + (MenuItemBorder.borderInsets): Initialise to correct value. + +2006-02-13 Roman Kennke + + * javax/swing/text/AsyncBoxView.java: New file. + +2006-02-13 Ito Kazumitsu + + Fixes bug #26166 + * gnu/regexp/RE.java(initialize): Parsing of character class expression + was moved to a new method parseCharClass. + (parseCharClass): New method originally in initialize. Added parsing + of nested character classes. + (ParseCharClassResult): New inner class used as a return value of + parseCharClass. + (getCharExpression),(getNamedProperty): Made static. + * gnu/regexp/RESyntax.java(RE_NESTED_CHARCLASS): New syntax flag. + * gnu/regexp/RETokenOneOf.java(addition): New Vector for storing + nested character classes. + (RETokenOneOf): New constructor accepting the Vector addition. + (getMinimumLength), (getMaximumLength): Returns 1 if the token + stands for only one character. + (match): Added the processing of the Vector addition. + (matchN), (matchP): Do not check next token if addition is used. + +2006-02-12 Olivier Jolly + + * AUTHORS: add self. + +2006-02-12 Tom Tromey + + * gnu/classpath/ServiceProviderLoadingAction.java: Javadoc fix. + * gnu/classpath/ServiceFactory.java (ServiceIterator): Javadoc fix. + (securityContext): Likewise. + (log): Likewise. + +2006-02-12 Dalibor Topic + + Fixes PR 26218. + + * gnu/java/net/protocol/file/Connection.java (unquote): + Convert Unicode characters outside basic plane to UTF-8, + rather than throwing an exception. + +2006-02-12 Tom Tromey + + * javax/sound/sampled/LineEvent.java (readObject): New method. + (writeObject): Likewise. + (serialVersionUID): New field. + +2006-02-12 Mark Wielaard + + * java/beans/PropertyChangeSupport.java (addPropertyChangeListener): + Silently ignores null listener. + (addPropertyChangeListener(String, PropertyChangeListener): Likewise. + (getPropertyChangeListeners): Returns empty PropertyChangeListener + array for null propertyName. + +2006-02-12 Wolfgang Baer + + * java/rmi/MarshalledObject.java: Added api docs to the class. + * java/rmi/Remote.java: Added interface api docs. + * java/rmi/package.html: Added package description. + * java/rmi/AccessException.java: Minor api doc fixes. + * java/rmi/NoSuchObjectException.java: Likewise. + * java/rmi/AlreadyBoundException.java: Likewise. + * java/rmi/RemoteException.java: Likewise. + * java/rmi/NotBoundException.java: Likewise. + * java/rmi/RMISecurityException.java: Likewise. + * java/rmi/StubNotFoundException.java: Likewise. + +2006-02-12 Mark Wielaard + + * gnu/java/awt/peer/gtk/GtkComponentPeer.java (postKeyEvent): Call + q() to get EventQueue. + * gnu/java/awt/peer/gtk/GtkGenericPeer.java (q): Remove static field. + (enableQueue): Remove static method. + * gnu/java/awt/peer/gtk/GtkToolkit.java (getSystemEventQueueImpl): + Don't call GtkGenericPeer.enableQueue(). + +2006-02-12 Wolfgang Baer + + * java/rmi/MarshalledObject.java: Reformatted. + * java/rmi/Naming.java: Likewise. + +2006-02-12 Jeroen Frijters + + * java/io/InputStream.java + (read(byte[],int,int)): Changed argument validation to prevent + integer overflow. Remove redundant check. + +2006-02-12 Jeroen Frijters + + Fixes PR 26220 + * java/io/InputStreamReader.java + (InputStreamReader(InputStream)): Use SystemProperties. + (InputStreamReader(InputStream,Charset)): Corrected @since tag. + Throw NullPointerException if in is null. + Added maxBytesPerChar initialisation. + (InputStreamReader(InputStream,CharsetDecoder)): Corrected @since tag. + Throw NullPointerException if in is null. + +2006-02-12 Raif S. Naffah + + * gnu/javax/crypto/key/dh/GnuDHPublicKey.java + (GnuDHPublicKey(4)): Call constructor with 5 arguments. + (GnuDHPublicKey): New constructor. + (getEncoded): Removed. + (valueOf): Added support for ASN.1 encoding. + (getEncoded(int)): Likewise. + (equals): New method. + * gnu/javax/crypto/key/dh/GnuDHPrivateKey.java + (GnuDHPrivateKey(4)): Call constructor with 5 arguments. + (GnuDHPrivateKey(5)): New constructor. + (getEncoded): Removed. + (valueOf): Added support for ASN.1 encoding. + (getEncoded(int)): Likewise. + (equals): New method. + * gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java + (PREFERRED_ENCODING_FORMAT): New constant. + (DEFAULT_ENCODING_FORMAT): Likewise. + (preferredFormat): New field. + (setup): Handle preferred encoding format identifier. + (generate): Call constructors with format identifier. + * gnu/javax/crypto/key/dh/GnuDHKey.java (defaultFormat): New field. + (GnuDHKey): Added an int argument. + (getEncoded): New method. + (getFormat): New implementation. + (getEncoded(int)): New abstract method. + * gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java: New file. + * gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java: Likewise. + * gnu/javax/crypto/jce/GnuCrypto.java (run): Added mappings for DH + key-pair generator and key-factory. + * gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java: New file. + * gnu/javax/crypto/jce/sig/DHKeyFactory.java: Likewise. + * gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java: Made it public. + * gnu/java/security/jce/sig/EncodedKeyFactory.java + (invokeConstructor): New method. + (getConcreteClass): Likewise. + (getConcreteCtor): Likewise. + (invokeValueOf): Likewise. + (getValueOfMethod): Likewise. + (engineGeneratePublic): Add support for DH keys. + (engineGeneratePrivate): Likewise. + (decodeDHPublicKey(DHPublicKeySpec)): New method. + (decodeDHPublicKey(byte[])): Likewise. + (decodeDHPrivateKey(DHPrivateKeySpec)): Likewise. + (decodeDHPrivateKey(byte[])): Likewise. + +2006-02-11 Mark Wielaard + + * gnu/java/awt/peer/gtk/GtkComponentPeer.java (repaintTimer): + Removed field. + (repaint): Immediately post to queue when tm <= 0, otherwise call + RepaintTimerTask.schedule(). + (RepaintTimerTask): Make static. + (RepaintTimerTask.repaintTimer): New static final field. + (RepaintTimerTask.awtComponent): New field. + (schedule): New static method. + +2006-02-11 Audrius Meskauskas + + * tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java + * tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java + * tools/gnu/classpath/tools/giop/grmic/templates/Tie.jav, + tools/gnu/classpath/tools/giop/grmic/templates/TieMethod.jav, + tools/gnu/classpath/tools/giop/grmic/templates/TieMethodVoid.jav: + Rewritten. + * tools/gnu/classpath/tools/giop/grmic/HashFinder.java: New file. + +2006-02-11 Raif S. Naffah + + * gnu/java/security/jce/sig/EncodedKeyFactory.java + (engineGeneratePublic): Added support for raw key-specifications. + (engineGeneratePrivate): Likewise. + (decodeDSSPublicKey): New method. + (decodeRSAPublicKey): Likewise. + (decodeDSSPrivateKey): Likewise. + (decodeRSAPrivateKey): Likewise. + * gnu/java/security/key/rsa/RSAKeyPairX509Codec.java + (encodePrivateKey): Throw InvalidParameterException. + (decodePublicKey): Likewise. + (decodePrivateKey): Likewise. + * gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java + (encodePublicKey): Likewise. + (encodePrivateKey): Likewise. + (decodePublicKey): Likewise. + * gnu/java/security/key/dss/DSSKeyPairX509Codec.java + (encodePrivateKey): Likewise. + (decodePublicKey): Likewise. + (decodePrivateKey): Likewise. + * gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java + (encodePublicKey): Likewise. + (encodePrivateKey): Likewise. + (decodePublicKey): Likewise. + +2006-02-10 Roman Kennke + + * javax/swing/text/StyleContext.java + (registerStaticAttributeKey): New static method. + +2006-02-10 Roman Kennke + + * javax/swing/text/DefaultStyledDocument.java + (ElementBuffer.clone): New method. + +2006-02-10 Roman Kennke + + * javax/swing/text/ParagraphView.java + (findOffsetToCharactersInString): New method. + (getClosestPositionTo): New method. + (getPartialSize): New method. + (getTabBase): New method. + (adjustRow): New method. + (breakView): New method. + (getBreakWeight): New method. + +2006-02-10 Roman Kennke + + * javax/swing/text/GapContent.java + (updateUndoPositions): New method. + * javax/swing/text/StringContent.java + (updateUndoPositions): New method. + +2006-02-10 Raif S. Naffah + + * gnu/java/security/key/rsa/GnuRSAPrivateKey.java (GnuRSAPrivateKey(9)): + Made it public. + * gnu/java/security/jce/sig/RSAKeyFactory.java: New file. + * gnu/java/security/jce/sig/DSSKeyFactory.java (engineGeneratePublic): + Added support for encoded key specifications. + (engineGeneratePrivate): Likewise. + (engineGetKeySpec): Likewise. + (engineTranslateKey): Corrected order of MPIs and use ctors with 5 args. + +2006-02-10 Robert Schuster + + * javax/swing/text/Utilities.java: + (getTabbedTextOffset): Fixed usage of variable p0. + (getPositionAbove): Rewritten. + (getPositionBelow): Rewritten. + +2006-02-09 Roman Kennke + + * javax/swing/text/BoxView.java + (getAxis): Added @since tag. + (setAxis): Added @since tag. + (layoutChanged): Added @since tag. + (isLayoutValid): Added @since tag. + (paint): Don't call setSize here. This is done in RootView already. + (getMaximumSpan): Reimplemented to return the requirements' + maximum size. Added API docs. + (getMinimumSpan): New method. + (layout): Fixed layout order. + (modelToView): Call layout instead of setSize here. + (getResizeWeight): New method. + (getChildAllocation): New method. + (forwardUpdate): New method. + (viewToModel): New method. + (flipEastEndWestEnds): New method. + * javax/swing/text/CompositeView.java + (modelToView): Made this method more robust by returning a default + location if it's not possible to calculate one via the children. + This default location returns the left or right edge of this + view. + (createDefaultLocation): New helper method. + * javax/swing/text/IconView.java + (modelToView): Don't throw BadLocationException. This should + really only be thrown if the position is outside the document + model, not if it's outside the view's boundary. + +2006-02-09 Audrius Meskauskas + + * tools/Makefile.am: Handle rmi and giop folders separately. + +2006-02-09 David Gilbert + + * javax/swing/SpinnerDateModel.java: Updated API docs all over, + * javax/swing/SpinnerNumberModel.java: Likewise. + +2006-02-09 David Gilbert + + * javax/swing/SpinnerDateModel.java: Removed tabs, + * javax/swing/SpinnerNumberModel.java: Likewise. + +2006-02-09 Anthony Balkissoon + + * doc/unicode/SpecialCasing-4.0.0.txt: New file. + * doc/unicode/UnicodeData-4.0.0.txt: New file. + +2006-02-09 Wolfgang Baer + + Fixes bug #26081 + * gnu/java/net/protocol/http/HTTPURLConnection.java: + (isRedirect): Removed, moved to Response.java. + (connect): If error condition redirect responseSink to errorSink. + (getInputStream): If error condition throw IOException, for the error + codes 404 and 410 throw a FileNotFoundException. + * gnu/java/net/protocol/http/Response.java (isError): New method. + (isRedirect): New method, moved from HTTPURLConnection.java. + +2006-02-09 Audrius Meskauskas + + * tools/Makefile.am: Add tools/gnu/classpath/tools/rmi folder. + * tools/gnu/classpath/tools/giop/GRMIC.txt: Explain it called from RMIC. + * tools/gnu/classpath/tools/giop/grmic/Generator.java (getResource): + Better diagnostic. + * tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java: + Rewritten. + * tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java: Implement + AbstractMethodGenerator. + * tools/gnu/classpath/tools/AbstractMethodGenerator.java, + tools/gnu/classpath/tools/rmi/RMIC.java, + tools/gnu/classpath/tools/rmi/RMIC.txt, + tools/gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java, + tools/gnu/classpath/tools/rmi/rmic/RmicCompiler.java, + tools/gnu/classpath/tools/rmi/rmic/WrapUnWrapper.java, + tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12.jav, + tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12Method.jav, + tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12MethodVoid.jav: + New files. + * NEWS: Corrected entry about the tools. + +2006-02-09 Lillian Angel + + * gnu/java/awt/peer/gtk/GtkComponentPeer.java + (handleEvent): Added more to check to prevent assertion errors. + * gnu/java/awt/peer/gtk/GtkPanelPeer.java + (handleEvent): Likewise. + * gnu/java/awt/peer/gtk/GtkWindowPeer.java + (handleEvent): Likewise. + +2006-02-09 Mark Wielaard + + * javax/swing/JTable.java (tableChanged): Interpret null event as + "everything changed". + +2006-02-09 Roman Kennke + + * javax/swing/text/DefaultCaret.java + (DocumentHandler.removeUpdate): When update policy is + 'on eventqueue', and the update doesn't come from the + event queue, check if the current dot location is still + valid. + (moveDot): Make sure the new dot location is valid. + (setDot): Set the mark the same as the dot. + +2006-02-09 Roman Kennke + + * javax/swing/text/AbstractDocument.java + (remove): Perform all operations within a write lock and in the + correct order. + +2006-02-09 Mark Wielaard + + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkScrollbarPeer.c + (Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_create): Make sure max is + creater than min, adjusting page_size if necessary. + (Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_setValues): Likewise. + +2006-02-09 Lillian Angel + + * gnu/java/awt/peer/gtk/GtkPanelPeer.java + (handleEvent): Added code to handle PaintEvent.UPDATE. + Sun does not call update(Graphics g) on Panels. + * gnu/java/awt/peer/gtk/GtkWindowPeer.java + (handleEvent): New method. Added code to handle PaintEvent.UPDATE. + Sun does not call update(Graphics g) on Panels. + +2006-02-09 Roman Kennke + + * javax/swing/text/BoxView.java + (myAxis): Made field private. + (xLayoutValid): Replaced by layoutValid array. + (yLayoutValid): Replaced by layoutValid array. + (layoutValid): New field. + (spansX): Replaced by spans array. + (spansY): Replaced by spans array. + (spans): New field. + (offsetsX): Replaced by offsets array. + (offsetsY): Replaced by offsets array. + (offsets): New field. + (requirements): New field. + (BoxView): Initialize new fields. + (layoutChanged): Rewritten to use the layoutValid array. + (isLayoutValid): Rewritten to use the layoutValid array. + (replace): Use the new arrays. + (getPreferredSpan): Rewritten to call calculateXXXRequirements + instead of baselineRequirements. + (baselineRequirements): Rewritten to calculate baseline requirements. + (baselineLayout): Rewritten to calculate baseline layout. + (childAllocation): Use new arrays. + (layout): Rewritten. Only update the layout if necessary. + (layoutMajorAxis): Directly set layoutValid. + (layoutMinorAxis): Directly set layoutValid. Use cached size + requirements. + (getWidth): Use new span array. + (getHeight): Likewise. + (setSize): Rewritten to simply call layout(). + (validateLayout): Removed unneeded method. + (getSpan): Use new arrays. + (getOffset): Use new arrays. + (getAlignment): Use cached requirements if possible. + (preferenceChanged): Use new arrays. + * javax/swing/text/FlowView.java + (FlowStrategy.insertUpdate): Do nothing here. + (FlowStrategy.removeUpdate): Do nothing here. + (FlowStrategy.changedUpdate): Do nothing here. + (FlowStrategy.layoutRow): Rewritten. + (FlowStrategy.createView): Rewritten. + (FlowStrategy.adjustRow): New method. + (LogicalView.getViewIndex): Fixed condition for finding child + view. + (layoutDirty): New field indicating the state of the layout. + (FlowView): Initialize new field. + (loadChildren): Set parent on logical view so that preferenceChanges + get propagated upwards. + (layout): Rewritten to match the specs. + (insertUpdate): Set layout to dirty. + (removeUpdate): Set layout to dirty. + (changedUpdate): Set layout to dirty. + * javax/swing/text/GlyphView.java + (getBreakWeight): Rewritten to use the Utilities class. Commented + out though because that is broken. + (insertUpdate): Call preferenceChanged on this object instead of + parent. + * javax/swing/text/ParagraphView.java + (Row.loadChildren): Overridden to be a noop to prevent initial + creation of child views. This is carried out by the flow layout. + * javax/swing/text/View.java + (getPreferredSpan): Added API docs. + (getResizeWeight): Added API docs. + (getMaximumSpan): Added API docs. Rewritten to only have one exit + point. + (getMinimumSpan): Added API docs. Rewritten to return 0 when + resizable instead of Integer.MAX_VALUE. + (getAlignment): Added API docs. + (replace): Added API docs. + (forwardUpdate): Rewritten to only notify child views that need to + be notified. + +2006-02-09 Roman Kennke + + * javax/swing/plaf/basic/BasicTextUI.java + (RootView.paint): Call setSize() before painting the view. + +2006-02-09 Ito Kazumitsu + + Fixes bug #26112 + * gnu/regexp/RE.java(REG_REPLACE_USE_BACKSLASHESCAPE): New execution + flag which enables backslash escape in a replacement. + (getReplacement): New public static method. + (substituteImpl),(substituteAllImpl): Use getReplacement. + * gnu/regexp/REMatch.java(substituteInto): Replace $n even if n>=10. + * java/util/regex/Matcher.java(appendReplacement) + Use RE#getReplacement. + (replaceFirst),(replaceAll): Use RE.REG_REPLACE_USE_BACKSLASHESCAPE. + +2006-02-09 Raif S. Naffah + + * gnu/java/security/key/rsa/RSAKeyPairX509Codec.java: New file. + * gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java: Likewise. + * gnu/java/security/key/rsa/RSAKeyPairGenerator.java + (PREFERRED_ENCODING_FORMAT): New constant. + (DEFAULT_ENCODING_FORMAT): Likewise. + (preferredFormat): New field. + (setup): Add support for preferred encoding format. + (generate): Call key constructors with explicit format identifier. + * gnu/java/security/key/rsa/GnuRSAPublicKey.java (GnuRSAPublicKey(2)): + Call constructor with 3 arguments.. + (GnuRSAPublicKey(3)): New constructor. + (valueOf): Added support for ASN.1 format. + (getEncoded): Likewise. + * gnu/java/security/key/rsa/GnuRSAPrivateKey.java (GnuRSAPrivateKey(4)): + Call constructor with 5 arguments. + (GnuRSAPrivateKey(5)): New constructor. + (GnuRSAPrivateKey(9)): New constructor. + (valueOf): Added support for ASN.1 format. + (getEncoded): Likewise. + * gnu/java/security/key/rsa/GnuRSAKey.java (defaultFormat): New field. + (GnuRSAKey): Modified constructor. + (getFormat): Return preferred format identifier. + * gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java + (decodePrivateKey): Fixed documentation. + Check Version field. + * gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java + (initialize(int,SecureRandom)): Set ASN.1 as the preferred encoding + format. + (initialize(AlgorithmParameterSpec,SecureRandom)): Likewise. + * gnu/java/security/jce/sig/EncodedKeyFactory.java + (engineGeneratePublic): Added support for RSA. + (engineGeneratePrivate): Likewise. + +2006-02-09 Wolfgang Baer + + * java/net/URLConnection.java: + (setAllowUserInteraction): Throw IllegalStateException if connected. + (getRequestProperty): Document return value if key is null. + * gnu/java/net/protocol/http/HTTPURLConnection.java: + (getRequestProperty): Return null if key is null. + (getRequestProperties): Throw IllegalStateException if connected. + (setRequestProperty): Call super method for exception tests. + (addRequestProperty): Likewise. + +2006-02-09 Wolfgang Baer + + * gnu/java/net/protocol/http/Request.java: + (Request): Remove initialization of removed field. + (requestBodyNegotiationThreshold): Removed now unused field. + (setRequestBodyNegotiationThreshold): Remove now unused method. + (dispatch): Do not use 'Expect 100-continue' header if content-length + is over a treshold. If user specified 'Expect 100-continue' still + initialize the expectingContinue variable. + +2006-02-08 David Gilbert + + * javax/swing/SpinnerNumberModel.java + (SpinnerNumberModel(Number, Comparable, Comparable, Number): Allow + maximum and minimum to take null values, + (setValue): Only fire ChangeEvent if new value is different to old + value, + (setMinimum): Fixed test for updating value, + (setMaximum): Likewise, + (setStepSize): Likewise. + +2006-02-08 Tom Tromey + + * tools/.cvsignore: Added Makefile.in. + +2006-02-08 Audrius Meskauskas + + * java/rmi/server/RemoteRef.java, + java/rmi/server/RemoteStub.java: Commented. + +2006-02-08 David Gilbert + + * javax/swing/SpinnerDateModel.java + (SpinnerDateModel(Date, Comparable, Comparable, int)): Added argument + checks, + (getPreviousValue): Check result against start, not end, + (setValue): Check that value actually changes before firing + ChangeEvent. + +2006-02-08 Lillian Angel + + * java/awt/Choice.java + (select): Fixed up code, added some checks to prevent errors. + (dispatchEventImpl): Removed. This function is not needed. It + causes several assertion errors. + +2006-02-08 Roman Kennke + + * javax/swing/text/PlainView.java + (drawLine): Call drawUnselectedText() with end offset - 1 to avoid + drawing unnecessary characters. + +2006-02-08 Lillian Angel + + * gnu/java/awt/peer/gtk/GtkComponentPeer.java + (handleEvent): Fixed check to determine if height or + width is less than 1. + +2006-02-08 Audrius Meskauskas + + *tools/Makefile.am (ALL_TOOLS_FILES): Add $(TOOLS_HELPS). + +2006-02-08 Audrius Meskauskas + + * examples/gnu/classpath/examples/CORBA/swing/x5/_GameManagerImpl_Tie.java, + examples/gnu/classpath/examples/CORBA/swing/x5/_PlayerImpl_Tie.java: + Documenting the code generator. + * gnu/CORBA/IOR.java (toStringFormatted, + CodeSet_component.toStringFormatted): New methods. + * tools/Makefile.am (TOOLS_JAVA_FILES, READMES): Rewritten. + * tools/gnu/classpath/tools/giop/README: Rewritten. + * tools/gnu/classpath/tools/giop/GRMIC.java (main): Rewritten. + (printHelpAndExit): Removed. + *tools/gnu/classpath/tools/giop/IorParser.java, + tools/gnu/classpath/tools/giop/IorParser.txt, + tools/gnu/classpath/tools/giop/NameService.java, + tools/gnu/classpath/tools/giop/NamingService.txt, + tools/gnu/classpath/tools/HelpPrinter.java: New files. + NEWS: Added note about GIOP tools. + +2006-02-07 Audrius Meskauskas + + * .classpath: New source patch (tools). + * Makefile.am (SUBDIRS, DIST_SUBDIRS): added "tools". + * configure.ac (AC_CONFIG_FILES): added tools/Makefile + * tools/gnu/classpath/tools/Makefile.am, + tools/gnu/classpath/tools/giop/GRMIC.java + tools/gnu/classpath/tools/giop/GRMIC.txt, + tools/gnu/classpath/tools/giop/README, + tools/gnu/classpath/tools/giop/grmic/CompilationError.java, + tools/gnu/classpath/tools/giop/grmic/Generator.java, + tools/gnu/classpath/tools/giop/grmic/GiopIo.java, + tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java, + tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java, + tools/gnu/classpath/tools/giop/grmic/templates/ImplTie.jav, + tools/gnu/classpath/tools/giop/grmic/templates/Stub.jav, + tools/gnu/classpath/tools/giop/grmic/templates/StubMethod.jav, + tools/gnu/classpath/tools/giop/grmic/templates/StubMethodVoid.jav, + tools/gnu/classpath/tools/giop/grmic/templates/Tie.jav, + tools/gnu/classpath/tools/giop/grmic/templates/TieMethod.jav, + tools/gnu/classpath/tools/giop/grmic/templates/TieMethodVoid.jav: New files. + +2006-02-07 David Gilbert + + * java/awt/BasicStroke.java: Updated API docs all over, + * java/awt/doc-files/capjoin.png: New file. + +2006-02-07 Lillian Angel + + * gnu/java/awt/peer/gtk/GtkComponentPeer.java + (handleEvent): Added check. Should not paint or update the + component if it's width and height are both 0. + +2006-02-07 Roman Kennke + + * javax/swing/text/AbstractDocument.java + (insertString): Enclose locking/unlocking in try-finally block + and also keep locked while notifying the listeners. + +2006-02-07 Roman Kennke + + * javax/swing/text/GlyphView.java + (GlyphView): Initialize startOffset and endOffset with -1 (indicating + element boundary). + (getStartOffset): Return element boundary if startOffset < 0. + (getEndOffset): Return element boundary if endOffset < 0. + (createFragment): Set startOffset and endOffset fields of fragment + if one of p0 or p1 is not at the element boundary. + +2006-02-07 Roman Kennke + + * javax/swing/CellRendererPane.java + (paintComponent): Enclosed painting in try finally to properly + clean up even when throwing an exception. + +2006-02-07 Roman Kennke + + * javax/swing/UIManager.java + (listeners): Made this an instance of + java.beans.PropertyChangeSupport instead of the obsoleted + SwingPropertyChangeSupport. + +2006-02-07 Robert Schuster + + * javax/swing/text/DefaultEditorToolkit.java: Changed behavior + of actions "delete-next" and "delete-previous", added new TextAction + implementations for "selection-begin", "selection-begin-line", + "selection-end" and "selection-end-line". + +2006-02-07 Roman Kennke + + * javax/swing/plaf/basic/BasicTextUI.java + (paint): Acquire read lock on the document before calling + paintSafely. + (paintSafely): Added comment about what this method does. + (paintBackground): Implemented to actually paint the background. + (update): Overridden to _not_ paint the background. This is done + in paintBackground in this UI. + +2006-02-07 Roman Kennke + + * javax/swing/text/View.java + (forwardUpdate): Don't notify newly added child views as specified. + +2006-02-07 Robert Schuster + + * gnu/java/beans/decoder/DefaultExceptionListener.java: Removed. + +2006-02-07 Roman Kennke + + * javax/swing/text/DefaultStyledDocument.java + (ElementBuffer.insert): Only register change when the element + actually changed. + +2006-02-07 Raif S. Naffah + + * gnu/java/security/key/KeyPairCodecFactory.java (getEncodingName): New + method. + (getEncodingShortName): Likewise. + * gnu/java/security/key/IKeyPairCodec.java (X509_FORMAT): New constant. + (PKCS8_FORMAT): Likewise. + (ASN1_FORMAT): Likewise. + * gnu/java/security/key/dss/DSSPublicKey.java (DSSPublicKey(4)): Call + constructor with 5 arguments. + (DSSPublicKey(5)): New constructor. + (valueOf): Handle ASN.1 encoding. + (getEncoded): Likewise. + * gnu/java/security/key/dss/DSSPrivateKey.java (DSSPrivateKey(4)): Call + constructor with 5 arguments. + (DSSPrivateKey(5)): New constructor. + (valueOf): Handle ASN.1 encoding. + (getEncoded): Likewise. + * gnu/java/security/key/dss/DSSKeyPairX509Codec.java: New file. + * gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java: Likewise. + * gnu/java/security/key/dss/DSSKeyPairGenerator.java + (PREFERRED_ENCODING_FORMAT): New constant. + (DEFAULT_ENCODING_FORMAT): Likewise. + (preferredFormat): New field. + (setup): Handle preferred format ID. + (generate): Use new ctors with 5 arguments. + * gnu/java/security/key/dss/DSSKey.java (DSSKey): Now accepts a format + ID as an additional argument. + (defaultFormat): new field. + (getFormat): Returns the preferred format as a short string. + * gnu/java/security/jce/sig/DSSKeyFactory.java: New file. + * gnu/java/security/jce/sig/EncodedKeyFactory.java (engineGetKeySpec): + Likewise + * gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java + (initialize(AlgorithmParameterSpec)): Set ASN.1 as the preferred + encoding format. + (initialize(int,boolean,SecureRandom)): Likewise. + * gnu/java/security/der/DERWriter.java (writeBitString): Use + writeLength() instead of write(). + return buf.length + 1 instead of buf.length. + +2006-02-07 Roman Kennke + + * javax/swing/plaf/basic/BasicTextUI.java + (RootView.preferenceChange): Changed view parameter to view so + that it doesn't hide a field of that class. + (RootView.getViewCount): Rewritten to clean up ECJ warning. + (RootView.modelToView): Removed unnecessary cast from View to View. + (PropertyChangeHandler): Made inner class private. + (updateHandler): Made field private. + (getVisibleEditorRect): Removed unneeded local variable that + shadowed a field with the same name and purpose. + +2006-02-07 Robert Schuster + + * javax/swing/text/JTextComponent.java: + (getSelectedText): Calculate offset and use that as + second argument. + +2006-02-07 Roman Kennke + + * javax/swing/JTextPane.java + (setCharacterAttributes): Replace input attributes when + replace==true. + +2006-02-07 Roman Kennke + + * java/awt/Component.java + (firePropertyChange(String,byte,byte)): Made method public. + (firePropertyChange(String,char,char)): Made method public. + (firePropertyChange(String,short,short)): Made method public. + (firePropertyChange(String,long,long)): Made method public. + (firePropertyChange(String,float,float)): Made method public. + (firePropertyChange(String,double,double)): Made method public. + +2006-02-06 Tom Tromey + + * gnu/CORBA/NamingService/NamingServiceTransient.java (main): Use + 2006. + * gnu/java/rmi/registry/RegistryImpl.java (version): Use 2006. + +2006-02-06 Anthony Green + + * gnu/xml/aelfred2/XmlParser.java: Add missing break;. + +2006-02-07 Raif S. Naffah + + * .settings/org.eclipse.jdt.core.prefs: + Force a line split on extends and implements. + Force a white-space after unary operators. + Don't force a new-line after @params. + Add new-line at end-of-file. + * scripts/eclipse-gnu.xml: Export version of the above named GNU. + +2006-02-07 Raif S. Naffah + + * gnu/java/security/provider/GnuDSAPublicKey.java (getEncoded): Use + Registry constant. + * gnu/java/security/provider/GnuDSAPrivateKey.java (getEncoded): + Likewise. + * gnu/java/security/provider/GnuRSAPrivateKey.java (getEncoded): + Likewise. + * gnu/java/security/provider/GnuRSAPublicKey.java (getEncoded): + Likewise. + * gnu/java/security/provider/EncodedKeyFactory.java + (ID_DSA): Redefined in terms of Registry constant. + (ID_DSA): Redefined in terms of Registry constant. + (ID_DH): Redefined in terms of Registry constant. + * gnu/java/security/Registry.java (X509_ENCODING): New constant. + (PKCS8_ENCODING): Likewise. + (ASN1_ENCODING): Likewise. + (RAW_ENCODING_SHORT_NAME): Likewise. + (X509_ENCODING_SORT_NAME): Likewise. + (PKCS8_ENCODING_SHORT_NAME): Likewise. + (ASN1_ENCODING_SHORT_NAME): Likewise. + (X509_ENCODING_ID): Likewise. + (PKCS8_ENCODING_ID): Likewise. + (ASN1_ENCODING_ID): Likewise. + (DSA_OID_STRING): Likewise. + (RSA_OID_STRING): Likewise. + (DH_OID_STRING): Likewise. + +2006-02-06 Roman Kennke + + * javax/swing/text/GlyphView.java: + (DefaultGlyphPainter.paint): Store/restore Graphics color setting. + Only fill background if there is a background set on the view. + Call Utilities.drawTabbedText with the baseline height, rather than + the upper left corner of the view rectangle. + (getBackground): Return null if no background is set. + * javax/swing/text/GlyphView.java: + (setPropertiesFromAttributes): Use null for background when no + background is set. StyleConstants.getBackground() doesn't work + for this, because it returns Color.BLACK in that case. + +2006-02-06 Roman Kennke + + * java/awt/Container.java + (changeSupport): Removed duplicate (from Component) field. + (addPropertyChangeListener): Call super. + +2006-02-06 Ito Kazumitsu + + * java/util/regex/Matcher.java(matches): + set RE.REG_TRY_ENTIRE_MATCH as an execution flag of getMatch. + +2006-02-06 Ito Kazumitsu + + Fixes bug #25812 + * gnu/regexp/CharIndexed.java(lookBehind),(length): New method. + * gnu/regexp/CharIndexedCharArray.java + (lookBehind),(length): Implemented. + * gnu/regexp/CharIndexedInputStream.java: Likewise. + * gnu/regexp/CharIndexedString.java: Likewise. + * gnu/regexp/CharIndexedStringBuffer.java: Likewise. + * gnu/regexp/REToken.java(getMaximumLength): New method. + * gnu/regexp/RE.java(internal constructor RE): Added new argument + maxLength. + (initialize): Parse (?<=X), (?X). + (getMaximumLength): Implemented. + * gnu/regexp/RETokenAny.java(getMaximumLength): Implemented. + * gnu/regexp/RETokenChar.java: Likewise. + * gnu/regexp/RETokenEnd.java: Likewise. + * gnu/regexp/RETokenEndSub.java: Likewise. + * gnu/regexp/RETokenLookAhead.java: Likewise. + * gnu/regexp/RETokenNamedProperty.java: Likewise. + * gnu/regexp/RETokenOneOf.java: Likewise. + * gnu/regexp/RETokenPOSIX.java: Likewise. + * gnu/regexp/RETokenRange.java: Likewise. + * gnu/regexp/RETokenRepeated.java: Likewise. + * gnu/regexp/RETokenStart.java: Likewise. + * gnu/regexp/RETokenWordBoundary.java: Likewise. + * gnu/regexp/RETokenIndependent.java: New file. + * gnu/regexp/RETokenLookBehind.java: New file. + +2006-02-06 Roman Kennke + + * java/awt/Component.java + (firePropertyChange(String,byte,byte)): New method. + (firePropertyChange(String,char,char)): New method. + (firePropertyChange(String,short,short)): New method. + (firePropertyChange(String,long,long)): New method. + (firePropertyChange(String,float,float)): New method. + (firePropertyChange(String,double,double)): New method. + +2006-02-06 Roman Kennke + + * javax/swing/JComponent.java + (AccessibleJComponent.changeSupport): Changed to be a + java.beans.PropertyChangeSupport rather than + SwingPropertyChangeSupport. + (AccessibleJComponent.AccesibleJComponent()): Change initialization + of above field. + (changeSupport): Removed unneeded field. + (removePropertyChangeListener): Removed unneeded methods. + (addPropertyChangeListener): Removed unneeded methods. + (getPropertyChangeListeners): Removed unneeded methods. + (firePropertyChange(String,boolean,boolean)): Changed to simply + call super. Added specnote. + (firePropertyChange(String,char,char)): Changed to simply + call super. Added specnote. + (firePropertyChange(String,int,int)): Changed to simply + call super. Added specnote. + (firePropertyChange(String,byte,byte)): Removed. + (firePropertyChange(String,Object,Object)): Removed. + (firePropertyChange(String,double,double)): Removed. + (firePropertyChange(String,float,float)): Removed. + (firePropertyChange(String,long,long)): Removed. + (firePropertyChange(String,short,short)): Removed. + +2006-02-06 Roman Kennke + + * javax/swing/event/SwingPropertyChangeSupport.java + (listeners): Removed field. + (propertyListeners): Removed field. + (source): Removed field. + (SwingPropertyChangeSupport()): Removed initialization of removed + fields. + (addPropertyChangeListener): Removed methods. + (removePropertyChangeListener): Removed methods. + (getPropertyChangeListeners): Removed methods. + (firePropertyChange): Removed methods. + (hasListeners): Removed methods. + +2006-02-06 Jeroen Frijters + + Fixes PR 25313 + * java/net/InetAddress.java + (readResolve): Implemented. + +2006-02-06 Jeroen Frijters + + Fixes PR 26121 + * java/io/ObjectInputStream.java + (readNextBlock()): Handle TC_RESET. + +2006-02-06 Wolfgang Baer + + * javax/print/attribute/standard/Compression.java, + * javax/print/attribute/standard/Finishings.java, + * javax/print/attribute/standard/JobMediaSheets.java, + * javax/print/attribute/standard/JobSheets.java, + * javax/print/attribute/standard/JobState.java, + * javax/print/attribute/standard/JobStateReason.java, + * javax/print/attribute/standard/ReferenceUriSchemesSupported.java, + * javax/print/attribute/standard/PrintQuality.java, + * javax/print/attribute/standard/Media.java, + * javax/print/attribute/standard/MultipleDocumentHandling.java, + * javax/print/attribute/standard/PrinterStateReason.java, + * javax/print/attribute/standard/PDLOverrideSupported.java: + (getName): Make method final. + (getCategory): Likewise. + * javax/print/attribute/standard/MediaSize.java: + (getName): Make method final. + (getCategory): Likewise. + (ISO): Added private default constructor. + (NA): Likewise. + (JIS): Likewise. + (Other): Likewise. + (Engineering): Likewise. + +2006-02-06 Wolfgang Baer + + * native/jni/java-net/javanet.c (_javanet_connect): + Throw ConnectException instead of IOException if connection failed. + * native/jni/java-net/javanet.h: + Add a define for java.net.ConnectException + +2006-02-05 Mark Wielaard + + Fixes bug #26101 + reported by Egon Willighagen + * javax/swing/DefaultListCellRenderer.java + (getListCellRendererComponent): Turn null value into empty string. + +2006-02-04 Ito Kazumitsu + + * gnu/regexp/RETokenNamedProperty.java(getHandler): Check for + a Unicode block if the name starts with "In". + (UnicodeBlockHandler): New inner class. + +2006-02-04 Roman Kennke + + * java/awt/Container.java + (getComponentZOrder): New method. + (setComponentZOrder): New method. + * javax/swing/JLayeredPane.java + (setPosition): Reimplemented to use setComponentZOrder(). + (getIndexOf): Reimplemented to use getComponentZOrder(). + (addImpl): Pass layerContraint to super call. Important for possibly + installed layout managers. + (swapComponents): Remove unneeded method. + +2006-02-04 Raif S. Naffah + + * gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java: Implement + DSAKeyPairGenerator. + (initialize(int,SecureRandom)): Call initialize(keysize, false, random). + (initialize(AlgorithmParameterSpec,SecureRandom)): More explicit error + message. + Surround call to adaptee in a try/catch. + (initialize((DSAParams,SecureRandom)): New method. + (initialize(int,boolean,SecureRandom)): New method. + * gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java: Extends + KeyPairGenerator rather than KeyPairGeneratorSpi. + (KeyPairGeneratorAdapter): Call super with algorithm name. + +2006-02-04 Raif S. Naffah + + * gnu/javax/crypto/sasl/srp/SRPServer.java (prng): New field. + (getDefaultPRNG): New method. + (parseO): Use method above. + * gnu/javax/crypto/sasl/srp/SRPClient.java (prng): New field. + (getDefaultPRNG): New method. + (createO): Use method above. + * gnu/javax/crypto/sasl/srp/KDF.java (prng): New class field. + (nextByte): Use above field. + * gnu/javax/crypto/pad/PKCS1_V1_5.java (selfTest): Use PRNG instance. + * gnu/java/security/sig/rsa/RSA.java: New class field. + (newR): Use above field + * gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java (prng): New field. + (encode): Use field.above. + * gnu/java/security/key/dss/FIPS186.java (prng): New field. + (getDefaultPRNG): new method. + (nextRandomBytes): Use above method. + * gnu/java/security/key/rsa/RSAKeyPairGenerator.java: Likewise. + * gnu/java/security/sig/BaseSignature.java: Likewise. + * gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java: Likewise. + * gnu/javax/crypto/key/dh/RFC2631.java: Likewise. + * gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java: Likewise. + * gnu/javax/crypto/key/BaseKeyAgreementParty.java: Likewise. + * gnu/java/security/key/dss/DSSKeyPairGenerator.java (prng): New field. + (getDefaultPRNG): new method. + (nextRandomBytes): Use above method. + (STRICT_DEFAULTS): new class field. + (USE_DEFAULTS): more documentation to clarify behavior. + (setup): amended to handle new attribute. + * gnu/java/security/util/PRNG.java: New file. + +2006-02-03 Lillian Angel + + * javax/swing/plaf/basic/BasicColorChooserUI.java: + chooser field should be protected, not package-private. + +2006-02-03 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (changeUpdate): Cleaned up code. + (split): Likewise. + (insertUpdate): Set offset to be equal to pos after + insertContentTag call. + (insertContentTag): If paragraph has no children, should use + replace instead of Edit. + (insertFracture): Moved around code to prevent any exception. Also, + left side of tree should not be recreated if it has already been + edited. In that case, we should only be creating a new right branch + when fracturing. + (getEditForParagraphAndIndex): No need to check index. We should + use the same edit for each paragraph. + +2006-02-03 Mark Wielaard + + * javax/swing/event/SwingPropertyChangeSupport.java + (propertyListeners): Change type to HashMap. + (SwingPropertyChangeSupport): Allocate HashMap. + +2006-02-03 Raif S. Naffah + + * java/security/KeyPairGenerator.java (getInstance): Test for + instanceof KeyPairGenerator before KeyPairGeneratorSpi. + +2006-02-02 Roman Kennke + + * javax/swing/RepaintManager.java + Made fields private. + (RepaintWorker.run): Enclosed work stuff in try finally block in + order to clean up correctly if invalidation or painting fails, + otherwise we would get no more RepaintWorkers onto the EventQueue. + Also, now the RepaintWorker is marked 'dead' only after it has + finished its work, avoid more than one RepaintWorker on the queue. + (ComponentComparator.compareTo): Compare dirty rectangle sizes + instead of hierarchy depths. + (workDirtyComponents): Removed unused field. + (repaintOrder): Removed unused field. + (workRepaintOrder): Removed unused field. + (workInvalidComponents): Removed unused field. + (RepaintManager()): Removed initialization of removed fields. + (addInvalidComponent): Fine tuned synchronization. + (removeInvalidComponent): Fine tune synchronization. + (addDirtyRegion): Short circuit invalid dirty regions. Fine tuned + synchronization. Don't manager repaintOrder here. + (insertRepaintOrder): Removed method. + (markCompletelyClean): Fine tuned synchronization. + (validateInvalidComponents): Dont use a working copy of the + invalidComponents list, instead fine tuned synchronization on this + list. Also, don't search validateRoot, this is already done in + addInvalidComponent(). + (paintDirtyRegions): Compute repaint order here, based on size of + damaged regions. Fine tuned synchronization. Avoid use of working + copies of dirtyComponent. + +2006-02-02 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (insertUpdate): JoinNextDirection should push the + 'next' paragraph on the stack. + +2006-02-02 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (insertUpdate): Rewrote code for Originate. This prevents + leaves being created multiple times. If it is on the last + ElementSpec, the leaves need to be created right then; + otherwise, only a branch is created. + (insertContentTag): Rewrote to add new leaf directly if + this is a branch with no children. Otherwise, it + recreates the remainder of the tree as before. + +2006-02-02 Ito Kazumitsu + + * gnu/regexp/REMatch.java(REMatchList): New inner utility class + for making a list of REMatch instances. + * gnu/regexp/RETokenOneOf.java(match): Rewritten using REMatchList. + * gnu/regexp/RETokenRepeated.java(findDoables): New method. + (match): Rewritten using REMatchList. + (matchRest): Rewritten using REMatchList. + +2006-02-02 Audrius Meskauskas + + * examples/gnu/classpath/examples/CORBA/swing/x5/PlayingDesk.java + (friendsMove): Call repaint() only after endOfGame is assigned. + +2006-02-02 Mark Wielaard + + Fixes bug #25769 reported by Artemus Harper + * java/util/AbstractCollection.java (toString): Only use Iterator, + check whether collection contains itself. + +2006-02-01 Casey Marshall + + Partial fix for PR classpath/25143. + * javax/crypto/EncryptedPrivateKeyInfo.java (algName): new field. + (): fill in `algName,' derive `algOid' from `algName.' + (getOid): new method. + (encode): embed NULL value for parameters if `params' is `null.' + +2006-02-01 Casey Marshall + + Tag check and OTHER_NAME fixes suggested by Rafael Teixeira + . + * gnu/java/security/x509/ext/GeneralNames.java (): fix tag + check; fix OTHER_NAME parsing; fix DIRECTORY_NAME parsing. + +2006-02-01 Casey Marshall + + toString fix suggested by Rafael Teixeira . + * gnu/java/security/der/DERValue.java + (getLength, getEncoded, getEncodedLength): throw an exception, + don't initialize `encoded' to a bogus value. + (toString): return a more helpful string. + + Partial fix for PR classpath/25144. + * gnu/java/security/der/DERWriter.java (write): if the value is + the pseudo-value used for CONSTRUCTED, write the encoded value + directly. + +2006-02-01 Tom Tromey + + * java/security/Security.java (loadProviders): Use system class + loader. + +2006-02-01 Mark Wielaard + + * gnu/regexp/RE.java (getRETokenNamedProperty): Chain exception. + * gnu/regexp/RETokenNamedProperty.java (LETTER, MARK, SEPARATOR, + SYMBOL, NUMBER, PUNCTUATION, OTHER): New final byte[] fields. + (getHandler): Check for grouped properties L, M, Z, S, N, P or C. + (UnicodeCategoriesHandler): New private static class. + +2006-02-01 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java: + Removed unneeded fields. + (insertUpdate): Removed field initialization. + (insertContentTag): Rewrote part of function. Still + not complete. + +2006-02-01 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (insertParagraph): Cleaned up code. + (insertFirstContentTag): Fixed call to recreateLeaves. + (insertContentTag): Added check to code to determine where + content should be inserted with respect to next element. + (createFracture): Removed check, recreateLeaves is called in + other places when needed. + (recreateLeaves): Added new parameter for paragraph instead + of checking the stack. Removed editing for newBranch, replaced + with a replace call. + +2006-02-01 Anthony Balkissoon + + * doc/unicode/Blocks-4.0.0.txt: New file. + * java/lang/Character.java: Regenerated inner class UnicodeBlock from + scripts/unicode-blocks.pl and doc/unicode/Blocks-4.0.0.txt. + * scripts/unicode-blocks.pl: Copied this over from the generics branch + but replaced some 1.5-only features (such as enum). + +2006-01-31 Roman Kennke + + * javax/swing/text/PasswordView.java + (drawSelectedText): Use drawEchoCharacter() method to draw echo + character. + (drawUnselectedText): Use drawEchoCharacter() method to draw echo + character. + +2006-01-31 Roman Kennke + + * javax/swing/JTextField.java + (getPreferredSize): Also include textfield's insets in width + calculation. + +2006-01-31 Roman Kennke + + * javax/swing/plaf/basic/BasicTextUI.java + (getPreferredSize): Include the textcomponent's insets in + preferredSize. + +2006-01-31 Roman Kennke + + * javax/swing/table/DefaultTableCellRenderer.java + (getTableCellRendererComponent): Moved setting of the value into + setValue(). Removed (bogus) special handling of JTextField values. + (setValue): Made ?: statement more clear by rewriting it + with if .. else. + +2006-01-31 Roman Kennke + + * javax/swing/JLayeredPane.java + (insertIndexForLayer): Fixed algorithm to correctly determine + inser index for positions >= 0. + (addImpl): Fixed API docs for the index parameter. + +2006-01-31 Mark Wielaard + + * java/net/URI.java (getURIGroup): Check for null to see whether + group actually exists. + +2006-01-31 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (changeUpdate): Fixed calls to split to incorporate + new parameter. + (insertParagraph): Likewise. Uses 0 as editIndex + because inserting into a new paragraph. + (insertContentTag): Fixed check to use + recreateLeaves. Added a FIXME comment. + (split): Added a new parameter for edits. + +2006-01-31 Roman Kennke + + * javax/swing/plaf/basic/BasicRootPaneUI.java + (installDefaults): Don't install a background color here. + +2006-01-31 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (insert): Removed comment. + (insertUpdate): Added comment. + (recreateLeaves): Removed call to push newBranch onto the + stack. This does not need to be done here. + +2006-01-31 Chris Burdess + + * gnu/xml/stream/SAXParser.java, + gnu/xml/stream/UnicodeReader.java, + gnu/xml/stream/XIncludeFilter.java, + gnu/xml/stream/XMLParser.java: Fix case where resolved InputSource + only resolved the system ID not the stream. Make some utility methods + public and static for use by other private XML APIs. + * java/lang/ClassNotFoundException.java: Ensure that initCause can be + called without throwing IllegalStateException. + * java/util/logging/SimpleFormatter.java: Write thrown exception if + provided. + +2006-01-31 Ito Kazumitsu + + Fixes bug #22873 + * gnu/regexp/REMatch(toString(int)): Throw IndexOutOfBoundsException + for an invalid index and return null for a skipped group. + +2006-01-31 Ito Kazumitsu + + Fixes bug #26002 + * gnu/regexp/gnu/regexp/RE.java(initialize): Parse /\p{prop}/. + (NamedProperty): New inner class. + (getNamedProperty): New method. + (getRETokenNamedProperty): New Method. + * gnu/regexp/RESyntax.java(RE_NAMED_PROPERTY): New syntax falg. + * gnu/regexp/RETokenNamedProperty.java: New file. + +2006-01-31 Roman Kennke + + * javax/swing/plaf/PlainView.java + (paint): Call drawLine with baseline coordinates. + (drawLine): Documented and indented this method. + (drawUnselecetedText): Documented and indented this method. + * javax/swing/plaf/text/Utilites.java + (drawTabbedText): The coordinates denote the baseline of the text + not the upper left corner. + +2006-01-31 Roman Kennke + + * javax/swing/plaf/basic/BasicTextUI.java + (createKeymap): Don't store KeyBindings[] as focusInputMap in + UIManager. Added FIXME regarding the implementation of this method. + +2006-01-30 David Gilbert + + * examples/gnu/classpath/examples/swing/ButtonDemo.java + (ButtonDemo): Move content initialisation to new method, + (initFrameContent): New method, + (main): Call initFrameContent(), + * examples/gnu/classpath/examples/swing/ComboBoxDemo.java: Likewise, + * examples/gnu/classpath/examples/swing/FileChooserDemo.java: Likewise, + * examples/gnu/classpath/examples/swing/ScrollBarDemo.java: Likewise, + * examples/gnu/classpath/examples/swing/SliderDemo.java: Likewise, + * examples/gnu/classpath/examples/swing/TextFieldDemo.java: Likewise. + +2006-01-30 David Gilbert + + * examples/gnu/classpath/examples/swing/Demo.java + (Demo): Set frame size, + (mkButtonBar): Removed stacked sub-panels. + +2006-01-30 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java: + Added new fields. + (insert): Initialized fields. Removed call to addEdit, + and created ElementEdit instead. + (insertUpdate): Added check for fracturing. If the + fracturing was not successful, we should push the + last element back on the stack. + (insertParagraph): Fixed call to getEditForParagraphAndIndex. + Also, changed replace calls to use Edit. + (insertFirstContentTag): Removed unneeded check and fixed call + to recreateLeaves. + (insertContent): Fixed check to use new fields. Added code in + to check if leaves overlap. + (createFracture): Fixed call to recreateLeaves. + (recreateLeaves): Fixed code and cleaned it up a bit. + (insertFracture): Set fracNotCreated field. + (addEdit): Removed, this method is not needed. + +2006-01-30 Roman Kennke + + * javax/swing/JRootPane.java + (RootLayout.prefSize): Removed caching for preferredSize. + (RootLayout.invalidateLayout): Likewise. + (RootLayout.preferredLayoutSize): Likewise. + +2006-01-30 Roman Kennke + + PR classpath/26035 + * javax/swing/JFrame.java + (frameInit): Handle the defaultLookAndFeelDecorated flag. + * javax/swing/plaf/metal/MetalRootPaneUI.java + (MetalFrameBorder): New inner class, provides the border for + top level containers with L&F decorations. + (MetalTitlePane): New inner class, provides the title pane for + top level containers with L&F decorations. + (MetalRootLayout): New inner class. Used to layout the root pane + when L&F window decorations are enabled. + (installUI): New method. Handles window decorations. + (uninstallUI): New method. Handles window decorations. + (propertyChange): Handles window decorations. + (installWindowDecorations): New method. Handles window + decorations. + (uninstallWindowDecorations): New method. Handles window + decorations. + * javax/swing/plaf/metal/MetalLookAndFeel.java + (getSupportsWindowDecorations): Overridden to return true. + +2006-01-30 Mark Wielaard + + * javax/swing/JProgressBar.java (JProgressBar(int)): Document + IllegalArgumentException when orientation is illegal. + (JProgressBar(int, int, int)): Likewise and throw exception. + (setOrientation): Likewise. + +2006-01-30 Roman Kennke + + * javax/swing/ViewportLayout.java + (minimumLayoutSize): Rewritten to unconditionally return (4,4). + +2006-01-30 Mark Wielaard + + * javax/swing/JProgressBar.java (orientation): Always set by + constructor. + (JProgressBar(int)): Document default on 'illegal' value. + (JProgressBar(int, int, int)): Likewise and set orientation to + HORIZONTAL when 'illegal'. + (setOrientation): Likewise. + +2006-01-30 Roman Kennke + + * javax/swing/plaf/basic/BasicListUI.java + (ListDataHandler.contentsChanged): Update the + updateLayoutStateNeeded flag. + (ListDataHandler.intervalAdded): Update the + updateLayoutStateNeeded flag. + (ListDataHandler.intervalRemoved): Update the + updateLayoutStateNeeded flag. + (PropertyChangeHandler.propertyChange): Correctly update the + listeners on new list model. + (maybeUpdateLayoutState): Don't consider the validation state + of the list. + +2006-01-30 Mark Wielaard + + * gnu/xml/transform/ApplyTemplatesNode.java (clone): Check whether + sortKeys is null. + +2006-01-30 Roman Kennke + + * javax/swing/JLayeredPane.java + (insertIndexForLayer): Fixed algorithm to correctly insert + components within different layers and -1 position. + +2006-01-30 Mark Wielaard + + * doc/api/Makefile.am (create_html): Add -validhtml. + +2006-01-30 Roman Kennke + + * javax/swing/JLayeredPane.java + (insertIndexForLayer): Fixed algorithm to correctly insert + components within same layer and -1 position. + +2006-01-30 Ito Kazumitsu + + Fixes bug #24876 + * gnu/regexp/gnu/regexp/RE.java(REG_TRY_ENTIRE_MATCH): + New execution flag. + (getMatchImpl): if REG_TRY_ENTIRE_MATCH is set, add an + implicit RETokenEnd at the end of the regexp chain. + Do not select the longest match, but select the first match. + (match): Do not take care of REMatch.empty. + * gnu/regexp/REMatch.java(empty): To be used only in RETokenRepeated. + * gnu/regexp/RETokenOneOf.java: Corrected a typo in a comment. + * gnu/regexp/RETokenBackRef.java: Do not take care of REMatch.empty. + * gnu/regexp/RETokenRepeated.java (match): Rewrote stingy matching. + Do not take care of REMatch.empty. Set and check REMatch.empty + when trying to match the single token. + +2006-01-30 Mark Wielaard + + * java/awt/Cursor.java (toString): Include name and type. + +2006-01-30 Raif S. Naffah + + * gnu/javax/crypto/mac/HMac.java (clone): Clone ipadHash, opadHash, and + the ipad buffer. + * gnu/javax/crypto/mac/BaseMac.java (clone): Clone underlyingHash. + +2006-01-30 Audrius Meskauskas + + PR 26027 + * javax/swing/plaf/basic/BasicListUI.java (maybeUpdateLayoutState): + Consider the validation state of the list. + +2006-01-29 Robert Schuster + + * gnu/java/beans/DefaultExceptionListener.java: Constant public field + INSTANCE added. + * java/beans/XMLDecoder.java: + (setExceptionListener): Use shared DefaultExceptionListener + instance. + * java/beans/Encoder.java: + (setExceptionListener): Use shared DefaultExceptionListener + instance. + +2006-01-29 Roman Kennke + + * javax/swing/ScrollPaneLayout.java + (minimumLayoutSize): Rewritten to match JDKs behaviour. + +2006-01-29 Mark Wielaard + + * java/net/SocketPermission.java (setActions): Trim and lower case + action. + +2006-01-29 Raif S. Naffah + + * gnu/java/security/util/Prime2.java (passEulerCriterion): Was + incorrectly failing primality test for some known primes. Fixed. + (passFermatLittleTheorem): Removed. + (passMillerRabin): Removed. + (isProbablePrime): Cache primes that pass the primality tests. + Use BigInteger.isProbablePrime(int) for primality tests. + (debugBI): New static debugging method. + +2006-01-28 Roman Kennke + + * javax/swing/plaf/basic/BasicListUI.java + (updateLayoutState): Removed unneeded special case for VERTICAL. + +2006-01-28 Roman Kennke + + * javax/swing/plaf/basic/BasicListUI.java + (getCellBounds): Determine correct list width when having a + layoutOrientation of VERTICAL. + (maybeUpdateLayoutState): Don't consider the validation state of + the list. + +2006-01-28 Mark Wielaard + + Reported by Dimitri Fontaine + * java/awt/print/NoPrinterJob.java: New (fake) class. + * java/awt/print/PrinterJob.java (getPrinterJob): Return NoPrinterJob. + +2006-01-28 Mark Wielaard + + * gnu/javax/crypto/mac/HMac.java (clone): Cast cloned ipad to byte[]. + +2006-01-28 Audrius Meskauskas + + * gnu/classpath/examples/swing/Demo.java (mkTree): Make a larger tree. + (addChildren): New method. + +2006-01-28 Raif S. Naffah + + * gnu/javax/crypto/jce/mac/MacAdapter.java (MacAdapter(IMac, Map)): New + constructor for cloning purposes. + (clone): New implementation that ensures cloning. + * gnu/javax/crypto/mac/HMac.java (clone): Implement Cloneable. + * gnu/java/security/Registry.java: Changed value of GNU_SECURITY to + "GNU". + +2006-01-27 Audrius Meskauskas + + * javax/swing/plaf/basic/BasicTreeUI.java (updateCachedPreferredSize): + Call updateCurrentVisiblePath. + +2006-01-27 Roman Kennke + + * examples/gnu/classpath/examples/swing/MiniDemo.java: New file. + +2006-01-27 Roman Kennke + + * examples/gnu/classpath/examples/swing/ButtonDemo.java + (createContent): Only create new content if we don't have one + already. + * examples/gnu/classpath/examples/swing/ComboBoxDemo.java + (createContent): Only create new content if we don't have one + already. + * examples/gnu/classpath/examples/swing/FileChooserDemo.java + (createContent): Only create new content if we don't have one + already. + * examples/gnu/classpath/examples/swing/ScrollBarDemo.java + (createContent): Only create new content if we don't have one + already. + * examples/gnu/classpath/examples/swing/SliderDemo.java + (createContent): Only create new content if we don't have one + already. + * examples/gnu/classpath/examples/swing/TableDemo.java + (createContent): Only create new content if we don't have one + already. + * examples/gnu/classpath/examples/swing/TextFieldDemo.java + (createContent): Only create new content if we don't have one + already. + +2006-01-27 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (insertFirstContentTag): Removed check, not needed. This + still needs to be fixed for some cases. Added call to + recreateLeaves. + (createFracture): Added call to recreateLeaves. + (recreateLeaves): New method used to recreate all the + leaves after the initial insertion. This still needs + more work. + (handleInsertAfterNewline): Removed else, not needed. + +2006-01-27 Roman Kennke + + * javax/swing/JLayeredPane.java + (inserIndexForLayer): Fixed direction of search. + +2006-01-27 Audrius Meskauskas + + * javax/swing/JTree.java (constructor): Put EXPANDED for the root + node into nodeStates. + +2006-01-27 Roman Kennke + + * javax/swing/JLayeredPane.java + (FRAME_CONTENT_LAYER): Made field final. + (componentToLayer): Made field private. + (rectCache): Removed field. + (layers): Removed field. + (JLayeredPane()): Removed initialization of removed fields. + (getLayer): Rewritten to make use of client properties in + JComponents and to be more straighforward. + (static getLayer): Rewritten to make use of client properties in + JComponents. + (layerToRange): Removed method. + (incrLayer): Removed method. + (decrLayer): Removed method. + (highestLayer): Rewritten to be more straightforward. + (lowestLayer): Rewritten to be more straightforward. + (getPosition): Rewritten to be more straightforward. + (getComponentsInLayer): Rewritten to be more straightforward. + (getComponentCountInLayer): Rewritten to be more straightforward. + (getIndexOf): Rewritten to be more straightforward. + (inserIndexForLayer): Rewritten to be more straightforward. + (remove): Rewritten to be more straightforward. + (setLayer): Rewritten to be more straightforward. + (addImpl): Rewritten to be more straightforward. + (putLayer): Rewritten to be more straightforward. + +2006-01-27 Anthony Balkissoon + + * java/lang/Character.java: + (offsetByCodePoints(CharSequence, int, int)): New API method. + (offsetByCodePoints(char[], int, int, int, int)): Likewise. + (toChars): Throw the Exception that the docs say we throw. + (codePointAt): Fixed an off-by-one error in the bounds of the if + statement. + * java/lang/String.java: + (String(int[], int, int)): New API constructor. + +2006-01-27 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (insert): Moved this loop to insertUpdate. + (insertUpdate): Likewise. Fixed variable + names. Incremented pos if new paragraph + is inserted. + (split): Changed edits to use replace instead. Prevents + assertion errors. + (insertFirstContentTag): Removed else. + (insertContentTag): Implemented else for JoinNextDirection. + (createFracture): Fixed up code, still not fully complete. + (insertFracture): Fixed to use return value from + recreateAfterFracture. + (recreateAfterFracture): Changed to return an array of the + elements to be added. This prevents an assertion error. + (contains): New function checks if an element is already in + the Vector. Vector's contain function was not enough to use. + (addAddedElement): Changed to use new contains function. + (addAddedElements): Likewise. + (addRemovedElement): Likewise. + (addRemovedElements): Likewise. + +2006-01-27 Audrius Meskauskas + + PR 25520 + * vm/reference/java/io/VMObjectInputStream.java (loaderAction.run): + If no user class loaders found on the stack, return the thread + context class loader. (currentClassLoader): Explained. + +2006-01-27 Roman Kennke + + * java/awt/Container.java + (swapComponents): Removed unspecified method. + * javax/swing/JLayeredPane.java + (setPosition): Reimplemented correctly. + (swapComponents): New helper method. + +2006-01-27 Mark Wielaard + + * configure.ac: Set version to 0.21-pre. + +2006-01-27 Roman Kennke + + PR classpath/25968 + * javax/swing/JComponent.java + (findOverlapFreeParent): Improved the algorithm to make better use + of the optimizedDrawingEnabled flag. + * javax/swing/JLayeredPane.java + (isOptimizedDrawingEnabled): Reimplemented to match the specs. + * javax/swing/JViewport.java + (computeBlit): Fixed check to decide if blitting is possible or not, + so that it doesn't blit if nothing was scrolled (in order to + update the buffer when the view updates itself). + +2006-01-27 Roman Kennke + + * javax/swing/plaf/metal/MetalFileChooserUI.java + (createList): Don't set scrollbar policy. + +2006-01-27 Roman Kennke + + * javax/swing/plaf/basic/BasicPopupMenuUI.java + (PopupMenuHandler.popupMenuWillBecomeInvisible): + Fixed to also handle non-Swing toplevel containers. + (PopupMenuHandler.popupMenuWillBecomeVisible): + Fixed to also handle non-Swing toplevel containers. + * javax/swing/Popup.java + (JWindowPopup.JWindowPopup()): Correctly set parent window on + popup. + +2006-01-27 Roman Kennke + + * javax/swing/plaf/basic/BasicInternalFrameUI.java + (InternalFramePropertyChangeListener): Don't implement + VetoableChangeListener. + (InternalFramePropertyChangeListener.vetoableChange): Removed. + (internalFrameVetoableChangeListener): Removed unneeded field. + (installListeners): Don't install vetoableChangeListener. + * javax/swing/event/DocumentEvent.java + (EventType): Made class final. + +2006-01-27 Roman Kennke + + * javax/swing/SwingUtilities.java + (calculateInsetArea): Removed unneeded method. The method + calculateInnerArea has the same purpose and is actually specified. + (calculateInnerArea): Rewritten to not use calculateInsetArea. + * javax/swing/plaf/basic/BasicMenuItemUI.java + (paintMenuItem): Use SwingUtilities.calculateInnerArea() instead + of SwingUtilities.calculateInsetArea(). + +2006-01-27 Roman Kennke + + * javax/swing/plaf/basic/BasicTreeUI.java + (installDefaults): Removed requestFocusInWindow() call. + * javax/swing/JComponent.java + (requestFocusInWindow(boolean)): Made method protected. + (printComponent): Made method protected. + (printChildren): Made method protected. + (printComponent): Made method protected. + (printBorder): Made method protected. + +2006-01-27 Roman Kennke + + * javax/swing/AbstractButton.java + (ButtonChangeListener.ButtonChangeListener()): Made constructor + package private. + * javax/swing/ImageIcon.java + (component): Made field final. + (tracker): Made field final. + * javax/swing/JApplet.java + (AccessibleJApplet.AccessibleJApplet): Made constructor protected. + * javax/swing/JCheckBox.java + (AccessibleJCheckBox.AccessibleJCheckBox): Made constructor + protected. + * javax/swing/JDialog.java + (AccessibleJDialog.AccessibleJDialog): Made constructor protected. + * javax/swing/JFrame.java + (AccessibleJFrame.AccessibleJFrame): Made constructor protected. + * javax/swing/JLayeredPane.java + (AccessibleJLayered.AccessibleJLayeredPane): Made constructor + protected. + (DEFAULT_LAYER): Made field final. + (PALETTE_LAYER): Made field final. + (MODAL_LAYER): Made field final. + (POPUP_LAYER): Made field final. + (DRAG_LAYER): Made field final. + * javax/swing/JMenu.java + (ActionChangeListener): Made class private. + * javax/swing/JOptionPane.java + (UNITITIALIZED_VALUE): Made field final. + * javax/swing/JPanel.java + (AccessibleJPanel.AccessibleJPanel): Made constructor protected. + * javax/swing/JPopupMenu.java + (ActionChangeListener): Made class private. + * javax/swing/JTree.java + (paramString): Made method protected. + * javax/swing/JViewport.java + (AccessibleJViewport.AccessibleJViewport): Made constructor protected. + * javax/swing/JWindow.java + (AccessibleJWindow.AccessibleJWindow): Made constructor protected. + * javax/swing/RepaintManager.java + (RepaintWorker): Made class private. + +2006-01-27 Roman Kennke + + * gnu/java/awt/peer/swing/SwingComponentPeer.java + (handleEvent): Removed debug statement. + +2006-01-27 Roman Kennke + + * java/awt/Component.java + (coalescePaintEvents): Don't try to optimize coalescing. This hurts + more than it helps. + +2006-01-26 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (createFracture): Commented out a known problem, + added FIXME tag. + +2006-01-26 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (ElementBuffer): Added fields. + (remove): Initialized pos. + (change): Likewise. + (insert): Likewise. + (insertUpdate): Incremented pos. Fixed check, createFracture should + be called on first tag if it is not ContentType. + (insertFirstContentTag): Reworked to use proper offsets and + set offset accordingly. This might need more work in the future. + (insertContentTag): Likewise. Fixed to use pos, instead of + offset. + (createFracture): Fixed to recreate other leaves. Still needs + more work. + (insertFracture): Reimplemented. + (recreateAfterFracture): New method. + (getParagraphElement): Reimplemented, more efficent. + +2006-01-26 Christian Thalinger + + * native/jni/java-lang/java_lang_VMDouble.c (doubleToLongBits) + (doubleToRawLongBits, longBitsToDouble): Swap the byte + ordering for little-endian arms without VFP. + +2006-01-26 Raif S. Naffah + + PR classpath/25981 + * gnu/javax/crypto/jce/GnuCrypto.java (run): Added KeyGenerator entries. + +2006-01-26 Mark Wielaard + + Fixes bug #25970 reported by Michael Kay + * java/math/BigDecimal.java (compareTo): Don't strip trailing zeros. + Add trailing zeros to the fraction of the decimal with the smallest + scale. + +2006-01-26 Roman Kennke + + * javax/swing/text/html/ObjectView.java: New file. + +2006-01-26 Audrius Meskauskas + + * javax/swing/plaf/basic/BasicTreeUI.java (MouseHandler.mousePressed): + Call startEditing when appropriate. + (WAIT_TILL_EDITING, EDIT, startEditTimer): New fields. + (startEditing): Always edit if directly ordered from + MouseHandler.mousePressed. + * javax/swing/tree/DefaultTreeCellEditor.java (CLICK_COUNT_TO_START): + New field. (createTreeCellEditor): Set click count to start. + (getTreeCellEditorComponent): Assing realEditor directly. + +2006-01-25 Casey Marshall + + Merging GNU Crypto and Jessie. + + * NEWS: mention the merge in the 0.21 notes. + * gnu/classpath/debug/Component.java (SSL_APPLICATION): removed. + (SSL_RECORD_LAYER): new constants. + * gnu/java/security/provider/Gnu.java (): add new algorithms + to provider. + * resource/java/security/classpath.security: add new providers. + * gnu/javax/crypto/assembly/Assembly.java, + gnu/javax/crypto/assembly/Cascade.java, + gnu/javax/crypto/assembly/CascadeStage.java, + gnu/javax/crypto/assembly/CascadeTransformer.java, + gnu/javax/crypto/assembly/DeflateTransformer.java, + gnu/javax/crypto/assembly/Direction.java, + gnu/javax/crypto/assembly/LoopbackTransformer.java, + gnu/javax/crypto/assembly/ModeStage.java, + gnu/javax/crypto/assembly/Operation.java, + gnu/javax/crypto/assembly/PaddingTransformer.java, + gnu/javax/crypto/assembly/Stage.java, + gnu/javax/crypto/assembly/Transformer.java, + gnu/javax/crypto/assembly/TransformerException.java, + gnu/javax/crypto/cipher/Anubis.java, + gnu/javax/crypto/cipher/BaseCipher.java, + gnu/javax/crypto/cipher/Blowfish.java, + gnu/javax/crypto/cipher/Cast5.java, + gnu/javax/crypto/cipher/CipherFactory.java, + gnu/javax/crypto/cipher/DES.java, + gnu/javax/crypto/cipher/IBlockCipher.java, + gnu/javax/crypto/cipher/IBlockCipherSpi.java, + gnu/javax/crypto/cipher/Khazad.java, + gnu/javax/crypto/cipher/NullCipher.java, + gnu/javax/crypto/cipher/Rijndael.java, + gnu/javax/crypto/cipher/Serpent.java, + gnu/javax/crypto/cipher/Square.java, + gnu/javax/crypto/cipher/TripleDES.java, + gnu/javax/crypto/cipher/Twofish.java, + gnu/javax/crypto/cipher/WeakKeyException.java, + gnu/javax/crypto/jce/GnuCrypto.java, + gnu/javax/crypto/jce/GnuSasl.java, + gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java, + gnu/javax/crypto/jce/cipher/AESSpi.java, + gnu/javax/crypto/jce/cipher/ARCFourSpi.java, + gnu/javax/crypto/jce/cipher/AnubisSpi.java, + gnu/javax/crypto/jce/cipher/BlowfishSpi.java, + gnu/javax/crypto/jce/cipher/Cast5Spi.java, + gnu/javax/crypto/jce/cipher/CipherAdapter.java, + gnu/javax/crypto/jce/cipher/DESSpi.java, + gnu/javax/crypto/jce/cipher/KhazadSpi.java, + gnu/javax/crypto/jce/cipher/NullCipherSpi.java, + gnu/javax/crypto/jce/cipher/PBES2.java, + gnu/javax/crypto/jce/cipher/RijndaelSpi.java, + gnu/javax/crypto/jce/cipher/SerpentSpi.java, + gnu/javax/crypto/jce/cipher/SquareSpi.java, + gnu/javax/crypto/jce/cipher/TripleDESSpi.java, + gnu/javax/crypto/jce/cipher/TwofishSpi.java, + gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java, + gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java, + gnu/javax/crypto/jce/keyring/GnuKeyring.java, + gnu/javax/crypto/jce/mac/HMacHavalSpi.java, + gnu/javax/crypto/jce/mac/HMacMD2Spi.java, + gnu/javax/crypto/jce/mac/HMacMD4Spi.java, + gnu/javax/crypto/jce/mac/HMacMD5Spi.java, + gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java, + gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java, + gnu/javax/crypto/jce/mac/HMacSHA160Spi.java, + gnu/javax/crypto/jce/mac/HMacSHA256Spi.java, + gnu/javax/crypto/jce/mac/HMacSHA384Spi.java, + gnu/javax/crypto/jce/mac/HMacSHA512Spi.java, + gnu/javax/crypto/jce/mac/HMacTigerSpi.java, + gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java, + gnu/javax/crypto/jce/mac/MacAdapter.java, + gnu/javax/crypto/jce/mac/OMacAnubisImpl.java, + gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java, + gnu/javax/crypto/jce/mac/OMacCast5Impl.java, + gnu/javax/crypto/jce/mac/OMacDESImpl.java, + gnu/javax/crypto/jce/mac/OMacImpl.java, + gnu/javax/crypto/jce/mac/OMacKhazadImpl.java, + gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java, + gnu/javax/crypto/jce/mac/OMacSerpentImpl.java, + gnu/javax/crypto/jce/mac/OMacSquareImpl.java, + gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java, + gnu/javax/crypto/jce/mac/OMacTwofishImpl.java, + gnu/javax/crypto/jce/mac/TMMH16Spi.java, + gnu/javax/crypto/jce/mac/UHash32Spi.java, + gnu/javax/crypto/jce/mac/UMac32Spi.java, + gnu/javax/crypto/jce/params/BlockCipherParameters.java, + gnu/javax/crypto/jce/params/DEREncodingException.java, + gnu/javax/crypto/jce/params/DERReader.java, + gnu/javax/crypto/jce/params/DERWriter.java, + gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java, + gnu/javax/crypto/jce/prng/CSPRNGSpi.java, + gnu/javax/crypto/jce/prng/FortunaImpl.java, + gnu/javax/crypto/jce/prng/ICMRandomSpi.java, + gnu/javax/crypto/jce/prng/UMacRandomSpi.java, + gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java, + gnu/javax/crypto/jce/spec/TMMHParameterSpec.java, + gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java, + gnu/javax/crypto/key/BaseKeyAgreementParty.java, + gnu/javax/crypto/key/GnuSecretKey.java, + gnu/javax/crypto/key/IKeyAgreementParty.java, + gnu/javax/crypto/key/IncomingMessage.java, + gnu/javax/crypto/key/KeyAgreementException.java, + gnu/javax/crypto/key/KeyAgreementFactory.java, + gnu/javax/crypto/key/OutgoingMessage.java, + gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java, + gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java, + gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java, + gnu/javax/crypto/key/dh/DiffieHellmanSender.java, + gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java, + gnu/javax/crypto/key/dh/ElGamalReceiver.java, + gnu/javax/crypto/key/dh/ElGamalSender.java, + gnu/javax/crypto/key/dh/GnuDHKey.java, + gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java, + gnu/javax/crypto/key/dh/GnuDHPrivateKey.java, + gnu/javax/crypto/key/dh/GnuDHPublicKey.java, + gnu/javax/crypto/key/dh/RFC2631.java, + gnu/javax/crypto/key/srp6/SRP6Host.java, + gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java, + gnu/javax/crypto/key/srp6/SRP6SaslClient.java, + gnu/javax/crypto/key/srp6/SRP6SaslServer.java, + gnu/javax/crypto/key/srp6/SRP6TLSClient.java, + gnu/javax/crypto/key/srp6/SRP6TLSServer.java, + gnu/javax/crypto/key/srp6/SRP6User.java, + gnu/javax/crypto/key/srp6/SRPAlgorithm.java, + gnu/javax/crypto/key/srp6/SRPKey.java, + gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java, + gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java, + gnu/javax/crypto/key/srp6/SRPPrivateKey.java, + gnu/javax/crypto/key/srp6/SRPPublicKey.java, + gnu/javax/crypto/keyring/AuthenticatedEntry.java, + gnu/javax/crypto/keyring/BaseKeyring.java, + gnu/javax/crypto/keyring/BinaryDataEntry.java, + gnu/javax/crypto/keyring/CertPathEntry.java, + gnu/javax/crypto/keyring/CertificateEntry.java, + gnu/javax/crypto/keyring/CompressedEntry.java, + gnu/javax/crypto/keyring/EncryptedEntry.java, + gnu/javax/crypto/keyring/Entry.java, + gnu/javax/crypto/keyring/EnvelopeEntry.java, + gnu/javax/crypto/keyring/GnuPrivateKeyring.java, + gnu/javax/crypto/keyring/GnuPublicKeyring.java, + gnu/javax/crypto/keyring/IKeyring.java, + gnu/javax/crypto/keyring/IPrivateKeyring.java, + gnu/javax/crypto/keyring/IPublicKeyring.java, + gnu/javax/crypto/keyring/MalformedKeyringException.java, + gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java, + gnu/javax/crypto/keyring/MeteredInputStream.java, + gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java, + gnu/javax/crypto/keyring/PasswordEncryptedEntry.java, + gnu/javax/crypto/keyring/PasswordProtectedEntry.java, + gnu/javax/crypto/keyring/PrimitiveEntry.java, + gnu/javax/crypto/keyring/PrivateKeyEntry.java, + gnu/javax/crypto/keyring/Properties.java, + gnu/javax/crypto/keyring/PublicKeyEntry.java, + gnu/javax/crypto/mac/BaseMac.java, + gnu/javax/crypto/mac/HMac.java, + gnu/javax/crypto/mac/HMacFactory.java, + gnu/javax/crypto/mac/IMac.java, + gnu/javax/crypto/mac/MacFactory.java, + gnu/javax/crypto/mac/MacInputStream.java, + gnu/javax/crypto/mac/MacOutputStream.java, + gnu/javax/crypto/mac/OMAC.java, + gnu/javax/crypto/mac/TMMH16.java, + gnu/javax/crypto/mac/UHash32.java, + gnu/javax/crypto/mac/UMac32.java, + gnu/javax/crypto/mode/BaseMode.java, + gnu/javax/crypto/mode/CBC.java, + gnu/javax/crypto/mode/CFB.java, + gnu/javax/crypto/mode/CTR.java, + gnu/javax/crypto/mode/EAX.java, + gnu/javax/crypto/mode/ECB.java, + gnu/javax/crypto/mode/IAuthenticatedMode.java, + gnu/javax/crypto/mode/ICM.java, + gnu/javax/crypto/mode/IMode.java, + gnu/javax/crypto/mode/ModeFactory.java, + gnu/javax/crypto/mode/OFB.java, + gnu/javax/crypto/pad/BasePad.java, + gnu/javax/crypto/pad/IPad.java, + gnu/javax/crypto/pad/PKCS1_V1_5.java, + gnu/javax/crypto/pad/PKCS7.java, + gnu/javax/crypto/pad/PadFactory.java, + gnu/javax/crypto/pad/SSL3.java, + gnu/javax/crypto/pad/TBC.java, + gnu/javax/crypto/pad/TLS1.java, + gnu/javax/crypto/pad/WrongPaddingException.java, + gnu/javax/crypto/prng/ARCFour.java, + gnu/javax/crypto/prng/CSPRNG.java, + gnu/javax/crypto/prng/Fortuna.java, + gnu/javax/crypto/prng/ICMGenerator.java, + gnu/javax/crypto/prng/IPBE.java, + gnu/javax/crypto/prng/PBKDF2.java, + gnu/javax/crypto/prng/PRNGFactory.java, + gnu/javax/crypto/prng/UMacGenerator.java, + gnu/javax/crypto/sasl/AuthInfo.java, + gnu/javax/crypto/sasl/AuthInfoProviderFactory.java, + gnu/javax/crypto/sasl/ClientFactory.java, + gnu/javax/crypto/sasl/ClientMechanism.java, + gnu/javax/crypto/sasl/ConfidentialityException.java, + gnu/javax/crypto/sasl/IAuthInfoProvider.java, + gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java, + gnu/javax/crypto/sasl/IllegalMechanismStateException.java, + gnu/javax/crypto/sasl/InputBuffer.java, + gnu/javax/crypto/sasl/IntegrityException.java, + gnu/javax/crypto/sasl/NoSuchMechanismException.java, + gnu/javax/crypto/sasl/NoSuchUserException.java, + gnu/javax/crypto/sasl/OutputBuffer.java, + gnu/javax/crypto/sasl/SaslEncodingException.java, + gnu/javax/crypto/sasl/SaslInputStream.java, + gnu/javax/crypto/sasl/SaslOutputStream.java, + gnu/javax/crypto/sasl/SaslUtil.java, + gnu/javax/crypto/sasl/ServerFactory.java, + gnu/javax/crypto/sasl/ServerMechanism.java, + gnu/javax/crypto/sasl/UserAlreadyExistsException.java, + gnu/javax/crypto/sasl/anonymous/AnonymousClient.java, + gnu/javax/crypto/sasl/anonymous/AnonymousServer.java, + gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java, + gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java, + gnu/javax/crypto/sasl/crammd5/CramMD5Client.java, + gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java, + gnu/javax/crypto/sasl/crammd5/CramMD5Server.java, + gnu/javax/crypto/sasl/crammd5/CramMD5Util.java, + gnu/javax/crypto/sasl/crammd5/PasswordFile.java, + gnu/javax/crypto/sasl/plain/PasswordFile.java, + gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java, + gnu/javax/crypto/sasl/plain/PlainClient.java, + gnu/javax/crypto/sasl/plain/PlainRegistry.java, + gnu/javax/crypto/sasl/plain/PlainServer.java, + gnu/javax/crypto/sasl/srp/CALG.java, + gnu/javax/crypto/sasl/srp/ClientStore.java, + gnu/javax/crypto/sasl/srp/IALG.java, + gnu/javax/crypto/sasl/srp/KDF.java, + gnu/javax/crypto/sasl/srp/PasswordFile.java, + gnu/javax/crypto/sasl/srp/SRP.java, + gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java, + gnu/javax/crypto/sasl/srp/SRPClient.java, + gnu/javax/crypto/sasl/srp/SRPRegistry.java, + gnu/javax/crypto/sasl/srp/SRPServer.java, + gnu/javax/crypto/sasl/srp/SecurityContext.java, + gnu/javax/crypto/sasl/srp/ServerStore.java, + gnu/javax/crypto/sasl/srp/StoreEntry.java, + gnu/javax/net/ssl/Base64.java, + gnu/javax/net/ssl/EntropySource.java, + gnu/javax/net/ssl/NullManagerParameters.java, + gnu/javax/net/ssl/PrivateCredentials.java, + gnu/javax/net/ssl/SRPManagerParameters.java, + gnu/javax/net/ssl/SRPTrustManager.java, + gnu/javax/net/ssl/StaticTrustAnchors.java, + gnu/javax/net/ssl/provider/Alert.java, + gnu/javax/net/ssl/provider/AlertException.java, + gnu/javax/net/ssl/provider/Certificate.java, + gnu/javax/net/ssl/provider/CertificateRequest.java, + gnu/javax/net/ssl/provider/CertificateType.java, + gnu/javax/net/ssl/provider/CertificateVerify.java, + gnu/javax/net/ssl/provider/CipherSuite.java, + gnu/javax/net/ssl/provider/ClientHello.java, + gnu/javax/net/ssl/provider/ClientKeyExchange.java, + gnu/javax/net/ssl/provider/CompressionMethod.java, + gnu/javax/net/ssl/provider/Constructed.java, + gnu/javax/net/ssl/provider/ContentType.java, + gnu/javax/net/ssl/provider/Context.java, + gnu/javax/net/ssl/provider/DiffieHellman.java, + gnu/javax/net/ssl/provider/DigestInputStream.java, + gnu/javax/net/ssl/provider/DigestOutputStream.java, + gnu/javax/net/ssl/provider/Enumerated.java, + gnu/javax/net/ssl/provider/Extension.java, + gnu/javax/net/ssl/provider/Extensions.java, + gnu/javax/net/ssl/provider/Finished.java, + gnu/javax/net/ssl/provider/GNUSecurityParameters.java, + gnu/javax/net/ssl/provider/Handshake.java, + gnu/javax/net/ssl/provider/JCESecurityParameters.java, + gnu/javax/net/ssl/provider/JDBCSessionContext.java, + gnu/javax/net/ssl/provider/Jessie.java, + gnu/javax/net/ssl/provider/JessieDHPrivateKey.java, + gnu/javax/net/ssl/provider/JessieDHPublicKey.java, + gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java, + gnu/javax/net/ssl/provider/JessieRSAPublicKey.java, + gnu/javax/net/ssl/provider/KeyPool.java, + gnu/javax/net/ssl/provider/MacException.java, + gnu/javax/net/ssl/provider/OverflowException.java, + gnu/javax/net/ssl/provider/PRNG.java, + gnu/javax/net/ssl/provider/ProtocolVersion.java, + gnu/javax/net/ssl/provider/Random.java, + gnu/javax/net/ssl/provider/RecordInput.java, + gnu/javax/net/ssl/provider/RecordInputStream.java, + gnu/javax/net/ssl/provider/RecordOutputStream.java, + gnu/javax/net/ssl/provider/RecordingInputStream.java, + gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java, + gnu/javax/net/ssl/provider/SSLHMac.java, + gnu/javax/net/ssl/provider/SSLRSASignature.java, + gnu/javax/net/ssl/provider/SSLRandom.java, + gnu/javax/net/ssl/provider/SSLServerSocket.java, + gnu/javax/net/ssl/provider/SSLServerSocketFactory.java, + gnu/javax/net/ssl/provider/SSLSocket.java, + gnu/javax/net/ssl/provider/SSLSocketFactory.java, + gnu/javax/net/ssl/provider/SSLSocketInputStream.java, + gnu/javax/net/ssl/provider/SSLSocketOutputStream.java, + gnu/javax/net/ssl/provider/SecurityParameters.java, + gnu/javax/net/ssl/provider/ServerHello.java, + gnu/javax/net/ssl/provider/ServerKeyExchange.java, + gnu/javax/net/ssl/provider/Session.java, + gnu/javax/net/ssl/provider/SessionContext.java, + gnu/javax/net/ssl/provider/Signature.java, + gnu/javax/net/ssl/provider/SynchronizedRandom.java, + gnu/javax/net/ssl/provider/TLSHMac.java, + gnu/javax/net/ssl/provider/TLSRandom.java, + gnu/javax/net/ssl/provider/Util.java, + gnu/javax/net/ssl/provider/X509KeyManagerFactory.java, + gnu/javax/net/ssl/provider/X509TrustManagerFactory.java, + gnu/javax/net/ssl/provider/XMLSessionContext.java, + gnu/javax/security/auth/Password.java, + gnu/javax/security/auth/callback/AWTCallbackHandler.java, + gnu/javax/security/auth/callback/AbstractCallbackHandler.java, + gnu/javax/security/auth/callback/ConsoleCallbackHandler.java, + gnu/javax/security/auth/callback/DefaultCallbackHandler.java, + gnu/javax/security/auth/callback/GnuCallbacks.java, + gnu/javax/security/auth/callback/SwingCallbackHandler.java, + gnu/java/security/Registry.java, + gnu/java/security/Properties.java, + gnu/java/security/hash/BaseHash.java, + gnu/java/security/hash/HashFactory.java, + gnu/java/security/hash/Haval.java, + gnu/java/security/hash/IMessageDigest.java, + gnu/java/security/hash/MD2.java, + gnu/java/security/hash/MD4.java, + gnu/java/security/hash/MD5.java, + gnu/java/security/hash/RipeMD128.java, + gnu/java/security/hash/RipeMD160.java, + gnu/java/security/hash/Sha160.java, + gnu/java/security/hash/Sha256.java, + gnu/java/security/hash/Sha384.java, + gnu/java/security/hash/Sha512.java, + gnu/java/security/hash/Tiger.java, + gnu/java/security/hash/Whirlpool.java, + gnu/java/security/jce/hash/HavalSpi.java, + gnu/java/security/jce/hash/MD2Spi.java, + gnu/java/security/jce/hash/MD4Spi.java, + gnu/java/security/jce/hash/MD5Spi.java, + gnu/java/security/jce/hash/MessageDigestAdapter.java, + gnu/java/security/jce/hash/RipeMD128Spi.java, + gnu/java/security/jce/hash/RipeMD160Spi.java, + gnu/java/security/jce/hash/Sha160Spi.java, + gnu/java/security/jce/hash/Sha256Spi.java, + gnu/java/security/jce/hash/Sha384Spi.java, + gnu/java/security/jce/hash/Sha512Spi.java, + gnu/java/security/jce/hash/TigerSpi.java, + gnu/java/security/jce/hash/WhirlpoolSpi.java, + gnu/java/security/jce/prng/HavalRandomSpi.java, + gnu/java/security/jce/prng/MD2RandomSpi.java, + gnu/java/security/jce/prng/MD4RandomSpi.java, + gnu/java/security/jce/prng/MD5RandomSpi.java, + gnu/java/security/jce/prng/RipeMD128RandomSpi.java, + gnu/java/security/jce/prng/RipeMD160RandomSpi.java, + gnu/java/security/jce/prng/SecureRandomAdapter.java, + gnu/java/security/jce/prng/Sha160RandomSpi.java, + gnu/java/security/jce/prng/Sha256RandomSpi.java, + gnu/java/security/jce/prng/Sha384RandomSpi.java, + gnu/java/security/jce/prng/Sha512RandomSpi.java, + gnu/java/security/jce/prng/TigerRandomSpi.java, + gnu/java/security/jce/prng/WhirlpoolRandomSpi.java, + gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java, + gnu/java/security/jce/sig/DSSRawSignatureSpi.java, + gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java, + gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java, + gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java, + gnu/java/security/jce/sig/SignatureAdapter.java, + gnu/java/security/key/IKeyPairCodec.java, + gnu/java/security/key/IKeyPairGenerator.java, + gnu/java/security/key/KeyPairCodecFactory.java, + gnu/java/security/key/KeyPairGeneratorFactory.java, + gnu/java/security/key/dss/DSSKey.java, + gnu/java/security/key/dss/DSSKeyPairGenerator.java, + gnu/java/security/key/dss/DSSKeyPairRawCodec.java, + gnu/java/security/key/dss/DSSPrivateKey.java, + gnu/java/security/key/dss/DSSPublicKey.java, + gnu/java/security/key/dss/FIPS186.java, + gnu/java/security/key/rsa/GnuRSAKey.java, + gnu/java/security/key/rsa/GnuRSAPrivateKey.java, + gnu/java/security/key/rsa/GnuRSAPublicKey.java, + gnu/java/security/key/rsa/RSAKeyPairGenerator.java, + gnu/java/security/key/rsa/RSAKeyPairRawCodec.java, + gnu/java/security/prng/BasePRNG.java, + gnu/java/security/prng/EntropySource.java, + gnu/java/security/prng/IRandom.java, + gnu/java/security/prng/LimitReachedException.java, + gnu/java/security/prng/MDGenerator.java, + gnu/java/security/prng/PRNGFactory.java, + gnu/java/security/prng/RandomEvent.java, + gnu/java/security/prng/RandomEventListener.java, + gnu/java/security/sig/BaseSignature.java, + gnu/java/security/sig/ISignature.java, + gnu/java/security/sig/ISignatureCodec.java, + gnu/java/security/sig/SignatureFactory.java, + gnu/java/security/sig/dss/DSSSignature.java, + gnu/java/security/sig/dss/DSSSignatureRawCodec.java, + gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java, + gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java, + gnu/java/security/sig/rsa/EMSA_PSS.java, + gnu/java/security/sig/rsa/RSA.java, + gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java, + gnu/java/security/sig/rsa/RSAPSSSignature.java, + gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java, + gnu/java/security/util/Base64.java, + gnu/java/security/util/ExpirableObject.java, + gnu/java/security/util/Prime2.java, + gnu/java/security/util/Sequence.java, + gnu/java/security/util/SimpleList.java, + gnu/java/security/util/Util.java, + resource/gnu/javax/security/auth/callback/MessagesBundle.properties: + new files imported from GNU Crypto and Jessie. + +2006-01-25 Tom Tromey + + * gnu/java/net/protocol/http/ChunkedInputStream.java (read): + Fixed calculation of number of bytes to read. + (size, count, meta, eof): Document. + +2006-01-25 Anthony Balkissoon + + * java/lang/Character.java: + (codePointCount(char[], int, int)): New API method. + (codePointCount(CharSequence, int, int)): Likewise. + +2006-01-25 Audrius Meskauskas + + PR 25205 + * javax/swing/DefaultCellEditor.java (getTreeCellEditorComponent): + Rewritten. + * javax/swing/JTree.java (stopEditing, cancelEditing): Return without + action if not editing. + * javax/swing/plaf/basic/BasicTreeUI.java + (CellEditorHandler.editingCancelled): Delegate to cancelEditing. + (CellEditorHandler.editingStopped): Delegate to stopEditing. + (EditorUpdateTimer): Removed. + (TreeAction.actionPerformed): Stop and not cancel the current editing + when starting editing another node. + (editorTimer, newVal): Removed. + (cancelEditing): Do not send the cancel message. + (completeEditing): Obtain the edited value from the editor. + (finish): New method. + (paintRow): Do not paint the editing component here. + (startEditing, stopEditing): Rewritten. + * javax/swing/tree/DefaultTreeCellEditor.java + (DefaultTextField): Added SVUID. + (EditorContainer): Rewritten. + (RealEditorListener): New inner class. + (ICON_TEXT_GAP, TREE_ICON_GAP: New constants). + (constructor): Add cell editor listener. Do not instantiate timer. + (actionPerformed): Return without action. + (cancelCellEditing): Rewritten. + (createTreeCellEditor): Add cell editor listener to the editor. + (getCellEditorValue): Request the value from the realEditor. + (isCellEditable): Removed timer management. + (prepareForEditing): Remove all components befor adding the + editingComponent. + (startEditingTimer): Start only if it is not null. + (stopCellEditing): Rewritten. + (stopEditingTimer): New method. + (valueChanged): Do not configure editing component here. + +2006-01-25 Roman Kennke + + * javax/swing/text/html/FormView.java: New file. + +2006-01-25 Roman Kennke + + * javax/swing/JSplitPane.java + (addImpl): Call resetToPreferredSizes() when no dividerLocation + has been set in order to set an initial layout. + * javax/swing/plaf/basic/BasicSplitPaneUI.java + (BasicHorizontalLayoutManager.layoutContainer): Fixed error for + layout of the right component. + (BasicHorizontalLayoutManager.resetToPreferredSizes): Set the + dividerLocation to the size of the left component. + (createDefaultNonContinuousLayoutDivider): Fetch the color from + the UIManager. + (setDividerLocation): Don't validate the location here. Sometimes + the divider needs to be set to an invalid location. + (startDragging): Don't revalidate and repaint here. + (finishDraggingTo): Don't repaint here. Also, don't call + dragDividerTo() here. + * javax/swing/plaf/basic/BasicLookAndFeel.java + (initComponentDefaults): Added SplitPaneDivider.draggingColor + default value. + +2006-01-25 Roman Kennke + + * javax/swing/JSplitPane.java + (addImpl): Removed invalidate() and layout() call. + * javax/swing/plaf/basic/BasicSplitPaneUI.java + (PropertyHandler.propertyChange): Remove layoutContainer() and + repaint() call. + +2006-01-25 Roman Kennke + + * configure.ac + * native/Makefile.am + * native/jni/classpath/Makefile.am + * native/jni/classpath/jcl.c + * native/jni/classpath/jcl.h + * native/jni/classpath/native_state.c + * native/jni/gtk-peer/Makefile.am + * native/jni/java-io/Makefile.am + * native/jni/java-io/java_io_VMFile.c + * native/jni/java-io/java_io_VMObjectStreamClass.c + * native/jni/java-lang/Makefile.am + * native/jni/java-net/Makefile.am + * native/jni/java-net/java_net_VMInetAddress.c + * native/jni/java-net/javanet.c + * native/jni/java-net/javanet.h + * native/jni/java-nio/Makefile.am + * native/jni/java-nio/gnu_java_nio_VMPipe.c + * native/jni/java-nio/gnu_java_nio_VMSelector.c + * native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c + * native/jni/java-nio/java_nio_MappedByteBufferImpl.c + * native/jni/java-nio/java_nio_VMDirectByteBuffer.c + * native/jni/java-util/Makefile.am + * native/jni/java-util/java_util_VMTimeZone.c + * native/jni/midi-dssi/Makefile.am + * native/jni/xmlj/Makefile.am + * native/target/Makefile.am + * native/target/Linux/target_native_math.h + * native/target/Linux/target_native_memory.h + * native/target/Linux/Makefile.am + * native/target/Linux/target_native_io.h + * native/target/Linux/target_native_math_float.h + * native/target/Linux/target_native_math_int.h + * native/target/generic/target_generic.c + * native/target/generic/target_generic_io.c + * native/target/generic/target_generic_math.h + * native/target/generic/target_generic_memory.h + * native/target/generic/target_generic_misc.c + * native/target/generic/target_generic_network.c + * native/target/generic/Makefile.am + * native/target/generic/target_generic.h + * native/target/generic/target_generic_file.h + * native/target/generic/target_generic_io.h + * native/target/generic/target_generic_math_float.h + * native/target/generic/target_generic_math_int.h + * native/target/generic/target_generic_misc.h + * native/target/generic/target_generic_network.h: + Reverted target native related changes back to the state of the + 0.20 release. + * native/target/MinGW/.cvsignore + * native/target/MinGW/Makefile.am + * native/target/MinGW/target_native.h + * native/target/MinGW/target_native_file.h + * native/target/MinGW/target_native_io.h + * native/target/MinGW/target_native_math.h + * native/target/MinGW/target_native_memory.h + * native/target/MinGW/target_native_misc.h + * native/target/MinGW/target_native_network.h + * native/target/RTEMS/.cvsignore + * native/target/RTEMS/Makefile.am + * native/target/RTEMS/target_native.h + * native/target/RTEMS/target_native_file.h + * native/target/RTEMS/target_native_io.h + * native/target/RTEMS/target_native_math.h + * native/target/RTEMS/target_native_memory.h + * native/target/RTEMS/target_native_misc.h + * native/target/RTEMS/target_native_network.h + * native/target/SunOS/.cvsignore + * native/target/SunOS/Makefile.am + * native/target/SunOS/target_native.h + * native/target/SunOS/target_native_file.h + * native/target/SunOS/target_native_io.h + * native/target/SunOS/target_native_math.h + * native/target/SunOS/target_native_memory.h + * native/target/SunOS/target_native_misc.h + * native/target/SunOS/target_native_network.h + * native/target/embOS/.cvsignore + * native/target/embOS/Makefile.am + * native/target/embOS/target_native.h + * native/target/embOS/target_native_file.h + * native/target/embOS/target_native_io.c + * native/target/embOS/target_native_io.h + * native/target/embOS/target_native_math.h + * native/target/embOS/target_native_memory.h + * native/target/embOS/target_native_misc.h + * native/target/embOS/target_native_network.h + * native/target/posix/.cvsignore + * native/target/posix/Makefile.am + * native/target/posix/target_posix.c + * native/target/posix/target_posix.h + * native/target/posix/target_posix_file.c + * native/target/posix/target_posix_file.h + * native/target/posix/target_posix_io.c + * native/target/posix/target_posix_io.h + * native/target/posix/target_posix_math.c + * native/target/posix/target_posix_math.h + * native/target/posix/target_posix_memory.c + * native/target/posix/target_posix_memory.h + * native/target/posix/target_posix_misc.c + * native/target/posix/target_posix_misc.h + * native/target/posix/target_posix_network.c + * native/target/posix/target_posix_network.h: + Removed. + +2006-01-24 Wolfgang Baer + + * javax/print/PrintService.java, + * javax/print/DocPrintJob.java, + * javax/print/CancelablePrintJob.java: + Added and enhanced api documentation for class and methods. + +2006-01-24 Wolfgang Baer + + * javax/print/SimpleDoc.java: Make class final. + * javax/print/attribute/standard/PrinterIsAcceptingJobs.java: Likewise. + * javax/print/attribute/DateTimeSyntax.java: + (toString): New overridden method. + * javax/print/attribute/standard/JobStateReasons.java: + (add): Use the super.add method to avoid recursion. + * javax/print/attribute/standard/PrinterStateReasons.java: + (put): Use the super.put method to avoid recursion. + +2006-01-24 Robert Schuster + + * java/beans/XMLEncoder.java: + (writeExpression): Added early return (fixes PR #25941). + (setExceptionListener, anonymous Class): Removed printStackTrace + call. + * java/beans/Encoder: Removed unused imports. + (setupDefaultPersistenceDelegates): Removed unneccessary + PersistenceDelegates for subclasses. + * java/beans/PersistenceDelegate: + (initialize): Use local variable as first argument as it was + intended once. + * java/beans/DefaultPersistenceDelegate: + (initialize): Added call to superclass' implementation, added + early return. + +2006-01-24 Tom Tromey + + * java/util/regex/PatternSyntaxException.java: Added @since. + * java/util/regex/Matcher.java (Matcher): Implements MatchResult. + * java/util/regex/MatchResult.java: New file. + +2006-01-24 David Gilbert + + * javax/swing/text/StringContent.java: Added API docs all over, plus + minor reformatting. + +2006-01-24 Gary Benson + + * java/net/SocketPermission.java: Implemented serialization. + +2006-01-24 David Gilbert + + * javax/swing/text/StringContent.java + (remove): Modified argument check to prevent removal of last character, + (getChars): Removed null argument check to allow NullPointerException, + added API docs, + (checkLocation): Added API docs and white space. + +2006-01-23 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (insertUpdate): Should only call createFracture with + StartTagType. Added check. + (insertContentTag): Should use the tags length for splitting. + Also, added a check to determine if current's start and end offset are + equal to the offset and endOffset. If so, only one leaf element + should be added. + (createFracture): Removed FIXME. This function is complete. + (split): Added calls to replace. Changed so the child is + added immediately to the paragraph. Prevents NPEs. + +2006-01-23 Mark Wielaard + + * examples/Makefile.am (EXAMPLE_ZIP): Group cd and commands. + +2006-01-23 Tom Tromey + + * gnu/java/security/x509/X509Certificate.java (parse): + Unconditionally read value; for version==1 case when reading + algorithm ID. + +2006-01-23 Roman Kennke + + * javax/swing/plaf/synth/ColorType.java, + * javax/swing/plaf/synth/Region.java, + * javax/swing/plaf/synth/SynthConstants.java, + * javax/swing/plaf/synth/SynthContext.java + * javax/swing/plaf/synth/SynthGraphicsUtils.java, + * javax/swing/plaf/synth/SynthLookAndFeel.java, + * javax/swing/plaf/synth/SynthPainter.java, + * javax/swing/plaf/synth/SynthStyle.java, + * javax/swing/plaf/synth/SynthStyleFactory.java, + * javax/swing/plaf/synth/package.html: + New files. Added the public API and framework classes for the + Synth look and feel. + +2006-01-23 David Gilbert + + * javax/swing/text/Segment.java: API docs all over. + +2006-01-23 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (split): Should not use createLeafElement and createBranchElement here. + We should just instaniate the LeafElements and BranchElements instead + to avoid the case where create*Element is overridden. + +2006-01-23 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (insertFirstContentTag): Moved check outside of if-statement. + This should be checked before creating the new leaf element. + (insertFracture): Fixed check to prevent an NPE. The previous + leaf should only be recreated if it has been created by + insertFirstContentTag. Also, fixed up code: if the endOffset is + greater than the offset, then we need to create a temp leaf + as a place holder. Otherwise, the leaf elements should be + created normally. + +2006-01-23 Gary Benson + + * java/net/SocketPermission.java: Almost completely rewritten. + +2006-01-23 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (insertFracture): Set temp leaf's attributes to prevent an NPE. + +2006-01-23 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java: + Formatted ElementBuffer and added new fields. + (remove): Added check to determine if length is 0. + (insertFirstContentTag): Initialized firstCreated to the element that is created + by the first tag encountered. Removed check in JoinPreviousDirection case, no + longer needed. In OriginateDirection case, added a loop to remove all old leafs + that have been recreated. + (insertContentTag): Cleaned up code. Removed checks that did not do anything. + (insertFracture): Fixed up code, removed unneeded objects and checks. Added + FIXME tags to the lines that need to be rewritten. + +2006-01-23 Mark Wielaard + + * examples/Makefile.am: Add support for fastjar. + +2006-01-23 Ito Kazumitsu + + * gnu/regexp/REToken.java(empty): Made Cloneable. + * gnu/regexp/RETokenOneOf.java(match): RE.java(match): + Use separate methods matchN and matchP depending on the + boolean negative. + (matchN): New method used when negative. Done as before. + (matchP): New method used when not negative. Each token is + tried not by itself but by a clone of it. + +2006-01-23 Chris Burdess + + Fixes bug #25906 + * gnu/xml/dom/DomCharacterData.java: Use a separate empty node list + class to avoid getLength method contention. + * gnu/xml/stream/SAXParser.java: Rethrow correct exception. + +2006-01-23 Chris Burdess + + * native/jni/java-util/Makefile.am: Include library required + explicitly by BSD systems. + * native/target/generic/target_generic_misc.h: Remove old commented + out code. + * native/target/generic/target_generic_network.h: Fallbacks (to + SO_NOSIGPIPE and then 0) for non-portable glibc MSG_NOSIGNAL. + +2006-01-22 Tom Tromey + + * native/target/posix/.cvsignore: Added .deps. + +2006-01-22 Mark Wielaard + + Fixes bug #25832, + reported by James Damour + * java/awt/Container.java (addImpl): Use empty string as name when + null constraints for LayoutManager.addLayoutComponent(). + +2006-01-22 Chris Burdess + + Fixes bug #25903 + * gnu/xml/dom/DomDocumentBuilder.java: Default to using file URL + representing current directory as base for relative URLs. + +2006-01-22 Ito Kazumitsu + + Fixes bug #25837 + * gnu/regexp/REMatch.java(empty): New boolean indicating + an empty string matched. + * gnu/regexp/RE.java(match): Sets empty flag when an empty + string matched. + (initialize): Support back reference \10, \11, and so on. + (parseInt): renamed from getEscapedChar and returns int. + * gnu/regexp/RETokenRepeated.java(match): Sets empty flag + when an empty string matched. Fixed a bug of the case where + an empty string matched. Added special handling of {0}. + * gnu/regexp/RETokenBackRef.java(match): Sets empty flag + when an empty string matched. Fixed the case insensitive matching. + +2006-01-21 Roman Kennke + + * javax/swing/plaf/metal/MetalSplitPaneDivider.java + (paint): Added painting of border if one is installed. + +2006-01-21 Roman Kennke + + PR classpath/25843: + * javax/swing/plaf/basic/BasicBorders.java + (getSplitPaneDividerBorder): Use new border constructor + without arguments. + (SplitPaneDividerBorder.highlight): Removed unneeded field. + (SplitPaneDividerBorder.shadow): Removed unneeded field. + (SplitPaneDividerBorder()): Changed constructor to do nothing. The + colors are fetched dynamically in the paintBorder method. + (SplitPaneDividerBorder.paintBorder): Fetch colors dynamically from + the look and feel. + (SplitPaneDividerBorder.isBorderOpaque): Returns true + unconditionally. + * javax/swing/plaf/basic/BasicLookAndFeel.java + (initComponentDefaults): Added default for SplitPaneDivider.border. + * javax/swing/plaf/basic/BasicSplitPaneDivider.java + (tmpBorder): Removed unneeded inner class. + (BasicSplitPaneDivider): Removed setting of border. + (setSplitPaneUI): Don't add the mouse handler to the splitpane + itself. + * javax/swing/plaf/basic/BasicSplitPaneUI.java + (BasicHorizontalLayoutManager.layoutContainer): Mostly rewritten + to get behaviour right. + (BasicHorizontalLayoutManager.distributeExtraSpace): Removed + implementation. This must be rewritten since the layout now works + slightly different (basically, it shouldn't modify the sizes[] + here but instead the dividerLocation. + (dividerLocation): New field. + (installDefaults): Initialize border on divider. + (uninstallDefaults): Only remove background color and border from + splitPane if they are instances of UIDefaults (== not set by + application). + (setDividerLocation): Set the dividerLocation field instead of + doing stunt acts here. + (getDividerLocation): Return dividerLocation field. + (getMinimumDividerLocation): Fixed calculation of minimum location. + +2006-01-21 Guilhem Lavaux + + * m4/acinclude.m4 + (CLASSPATH_WITH_GLIBJ): Add support for fastjar. + + * lib/Makefile.am: Likewise. + +2006-01-21 Roman Kennke + + * javax/swing/PopupFactory.java + (getPopup): If there is no Swing root found in any way, use a + heavyweight popup. This is useful for mixed Swing/AWT GUIs, or + for the Swing AWT peers. + +2006-01-20 Tom Tromey + + * gnu/java/net/protocol/http/HTTPURLConnection.java (connect): + Read response body for redirect. + +2006-01-20 Chris Burdess + + * gnu/java/net/protocol/http/HTTPURLConnection.java: Don't follow + redirects on 304. + +2006-01-20 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (pad): Removed, not needed. + (printElements): Likewise. + (printEdit): Likewise. + +2006-01-20 Roman Kennke + + * javax/swing/text/DefaultFormatter.java + (DefaultFormatter): Don't set a value class. + +2006-01-19 Audrius Meskauskas + + * javax/swing/DefaultCellEditor.java: Commented. + +2006-01-19 Roman Kennke + + * javax/swing/JOptionPane.java + Added cast to Frame for JDialog constructor. + +2006-01-19 Roman Kennke + + * javax/swing/JWindow.java + (JWindow(Window)): Fixed to accept null owner argument. + (JWindow(Window,GraphicsConfiguration)): Fixed to accept null + owner argument. + * javax/swing/SwingUtilities.java + (getOwnerFrame): Owner parameter and return value are fixed to + be of type Window for compatibity with the above JWindow + constructor. + * javax/swing/JDialog.java + (JDialog): Added cast to Frame to make sure the correct constructor + is called. + * javax/swing/JFileChooser.java + (createDialog): Added cast to Frame for JDialog constructor. + +2006-01-19 Audrius Meskauskas + + * javax/swing/JTable.java (rowAtPoint): Rewritten. + +2006-01-19 Roman Kennke + + * javax/swing/JWindow.java: Added API docs to the constructors. + +2006-01-19 Audrius Meskauskas + + * javax/swing/JTable.java: Commenting method headers. + (EditorUpdateTimer): Removed. + +2006-01-19 Roman Kennke + + * javax/swing/JDialog.java + (JDialog()): Call SwingUtilities.getOwnerFrame() with null. + (JDialog(Frame,String,boolean,GraphicsConfiguration)): Call + SwingUtilities.getOwnerFrame() with the owner argument. + * javax/swing/JFileChooser.java + (showOpenDialog(Component)): Call pack() on the dialog instead of + setting a fixed height. + (showSaveDialog()): Likewise. + (showDialog()): Likewise. + (createDialog): Call SwingUtilities.getOwnerFrame() with null. + * javax/swing/JOptionPane.java: Call SwingUtilities.getOwnerFrame() + with null. + * javax/swing/JWindow.java + (JWindow()): Call SwingUtilities.getOwnerFrame() with null. + (JWindow(Frame)): Call SwingUtilities.getOwnerFrame() with owner + argument. + * javax/swing/SwingUtilities.java + (getOwnerFrame): Changed to take a owner parameter that is returned + as owner frame when not null. + +2006-01-19 Roman Kennke + + * gnu/java/awt/peer/swing/SwingFramePeer.java + (handleMouseEvent): Fixed handling of mouse events. + (handleMouseMotionEvent): Fixed handling of mouse events. + +2006-01-19 Roman Kennke + + * native/target/generic/target_generic_misc.c: + (targetGenericMisc_formatString): Added missing method. + +2006-01-19 Wolfgang Baer + + * m4/acinclude.m4: Test also for ecj found before exiting configure + with no javac found error message. + +2006-01-19 Ito Kazumitsu + + Fixes bug #23212 + * gnu/regexp/RE.java(initialize): Support escaped characters such as + \0123, \x1B, \u1234. + (getEscapedChar): New method. + (CharExpression): New inner class. + (getCharExpression): New Method. + * gnu/regexp/RESyntax.java(RE_OCTAL_CHAR, RE_HEX_CHAR, + RE_UNICODE_CHAR): New syntax bits. + +2006-01-19 Roman Kennke + + * native/target/Makefile.am: Fixed so that posix stuff is really + only built when requested. + +2006-01-19 Audrius Meskauskas + + * javax/swing/JTable.java (editingStopped, editingCancelled): + Repaint the edited cell. + (setValueAt): Do not add the value object to this container. + (editorTimer, rowBeingEdited, columnBeingEdited, oldCellValue): Removed. + (editingStopped): Use editingRow, editingColumn and not + rowBeingEdited, columnBeingEdited. (editValueAt): rewritten. + (doLayout): Move the editor component, if present, into the new + location and call repaint(). (moveToCellBeingEdited): new method. + (TableTextField): new inner class. + (getDefaultEditor): Instantiante TableTextField, not JTextField. + (setValueAt): Repaint the changed segment. + (createDefaultEditors): Implemented. + (BooleanCellRenderer): Center the checkbox and use the default foreground + and background colors. + * javax/swing/plaf/basic/BasicTableUI.java + (paintCell): Do not paint the caret here. Do not accept unused parameters. + (paint): No need to allocate rectangle for each cell. + * javax/swing/DefaultCellEditor.java: Rewritten. + * examples/gnu/classpath/examples/swing/Demo.java (mkTable): + Use TableDemo.java table example. + * examples/gnu/classpath/examples/swing/TableDemo.java: New file. + +2006-01-19 Roman Kennke + + * configure.ac: Added/fixed --enable-posix-layer option to enable + build of posix layer. + * native/target/Makefile.am: Added build for posix layer. + +2006-01-19 Christian Thalinger + + * configure.ac: Set TARGET to Linux per default. + * native/target/Makefile.am (libtarget_la_LIBADD): Removed + libtargetos.la. + * native/target/Linux/Makefile.am: Don't build a libtargetos.la. + * native/target/generic/Makefile.am (INCLUDES): Renamed to + AM_CPPFLAGS. + +2006-01-19 Raif S. Naffah + + * java/security/interfaces/RSAMultiPrimePrivateCrtKey.java: Replaced + what looked like proprietary documentation with original or new one. + * java/security/spec/PSSParameterSpec.java: Likewise. + * java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java: Likewise. + * java/security/spec/RSAOtherPrimeInfo.java: Likewise. + * java/security/AlgorithmParameterGenerator.java: Likewise. + * java/security/AlgorithmParameters.java: Likewise. + * java/security/Identity.java: Likewise. + * java/security/IdentityScope.java: Likewise. + * java/security/KeyFactory.java: Likewise. + * java/security/KeyPairGenerator.java: Likewise. + * java/security/MessageDigest.java: Likewise. + * java/security/Policy.java: Likewise. + * java/security/ProtectionDomain.java: Likewise. + * java/security/Security.java: Likewise. + * java/security/Signature.java: Likewise. + * java/security/SignatureSpi.java: Likewise. + * java/security/SignedObject.java: Likewise. + * java/security/Signer.java: Likewise. + +2006-01-18 Roman Kennke + + * configure.ac: Added --enable-posix-layer option to enable + build of the posix target layer. + +2006-01-18 Roman Kennke + + * native/jni/java-net/java_net_VMInetAddress.c + (Java_java_net_VMInetAddress_lookupInaddrAny): Use target native macro + for INADDR_ANY. + +2006-01-18 Roman Kennke + + * native/jni/java-util/java_util_VMTimeZone.c: + (Java_java_util_VMTimeZone_getSystemTimeZoneId): Rewritten + to use target native layer. + (jint_to_charbuf): Removed unneeded helper function. + +2006-01-18 Roman Kennke + + * native/jni/java-nio/gnu_java_nio_VMPipe.c: + Removed unnecessary include. + * native/jni/java-nio/gnu_java_nio_VMSelector.c: + Reorganized includes to only include sys/* headers when available. + * native/jni/java-nio/java_nio_MappedByteBufferImpl.c: + (get_pagesize): Return 0 when nothing else works. + (Java_java_nio_MappedByteBufferImpl_unmapImpl): + Replaced munmap() and strerror() with corresponding target macros. + (Java_java_nio_MappedByteBufferImpl_isLoadedImpl): + Replaced strerror() with corresponding target macro. + (Java_java_nio_MappedByteBufferImpl_forceImpl): + Replaced strerror() with corresponding target macro. + * native/jni/java-nio/java_nio_VMDirectByteBuffer.c: + (Java_java_nio_VMDirectByteBuffer_allocate): + Replaced malloc() with the corresponding target macro. + (Java_java_nio_VMDirectByteBuffer_free): + Replaced free() with the corresponding target macro. + (Java_java_nio_VMDirectByteBuffer_put__Lgnu_classpath_Pointer_2IB): + Add index to pointer when assigning the value. + (Java_java_nio_VMDirectByteBuffer_get__Lgnu_classpath_Pointer_2I_3BII): + Replaced memcpy with corresponding target macro. Add index when + doing the memcpy, not when fetching the pointer. + (Java_java_nio_VMDirectByteBuffer_put__Lgnu_classpath_Pointer_2I_3BII): + Replaced memcpy with corresponding target macro. + (Java_java_nio_VMDirectByteBuffer_shiftDown): + Replaced memmove with the corresponding target macro. + +2006-01-17 Tom Tromey + + PR classpath/20198: + * java/net/URLClassLoader.java (FileURLLoader): Added argument. + (JarURLLoader): Likewise. + (addURLImpl): Canonicalize file URLs. + +2006-01-17 Christian Thalinger + + * configure.ac: Set TARGET. + * native/Makefile.am, native/jni/classpath/Makefile.am, + native/jni/gtk-peer/Makefile.am, native/jni/java-io/Makefile.am, + native/jni/java-lang/Makefile.am, native/jni/java-net/Makefile.am, + native/jni/java-nio/Makefile.am, native/jni/midi-dssi/Makefile.am, + native/jni/xmlj/Makefile.am, native/target/Makefile.am, + native/target/Linux/Makefile.am, + native/target/generic/Makefile.am, + native/target/posix/Makefile.am: Build libclasspath.so with jcl + and target stuff linked in and link it against lib*.so libraries. + +2006-01-17 Roman Kennke + + * native/jni/java-net/javanet.c: + (_javanet_connect): Changed type of some local variables to jint. + Fixed error handling to throw a SocketTimeoutException if the + connection attempt times out. + (_javanet_bind): Changed type of some local variables to jint. + (_javanet_accept): Likewise. + (_javanet_recvfrom): Likewise. + (_javanet_sendto): Fixed error handling to throw a + PortUnreachableException when connection is refused. + (_javanet_get_option): Changed type of some local variables to jint. + Implemented SOCKOPT_SO_BROADCAST. + (_javanet_shutdownInput): Replaced shutdown call with corresponding + target native macro. + (_javanet_shutdownOutput): Replaced shutdown call with corresponding + target native macro. + * native/jni/java-net/javanet.h: + Defined SOCKET_TIMEOUT_EXCEPTION, PORT_UNREACHABLE_EXCEPTION and + SOCKOPT_SO_BROADCAST. + +2006-01-17 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (insert): Cleaned up loop. No need to make so many calls + to getAddedElements and getRemovedElements. + (insertFracture): Removed unneeded array. + +2006-01-17 Lillian Angel + + * javax/swing/text/JTextComponent.java + (AccessibleJTextComponent): Implemented. + (getCaretPosition): Implemented. + (getSelectedText): Implemented. + (getSelectionStart): Implemented. + (getSelectionEnd): Implemented. + (getSelectionEnd): Implemented. + (getCharCount): Implemented. + (insertTextAtIndex): Implemented. + (getTextRange): Implemented. + (delete): Implemented. + (cut): Implemented. + (paste): Implemented. + (replaceText): Implemented. + (selectText): Implemented. + +2006-01-17 Anthony Balkissoon + + * javax/swing/text/DefaultStyledDocument.java: + (pad): New debugging method. + (printElements): Likewise. + (printPendingEdits): Likewise. + (printElement): Likewise. + (Edit): Improved docs, moved this class to be an inner class of + ElementBuffer since it only applies within that scope. Changed added + and removed to be Vectors instead of arrays because we need to be able + to add to them after construction. + (ElementBuffer): Updated docs with link to article that helped in this + classes implementation. + (ElementBuffer.Edit.getRemovedElements): New method. + (ElementBuffer.Edit.getAddedElements): Likewise. + (ElementBuffer.Edit.addRemovedElement): Likewise. + (ElementBuffer.Edit.addRemovedElements): Likewise. + (ElementBuffer.Edit.addAddedElement): Likewise. + (ElementBuffer.Edit.addAddedElements): Likewise. + (ElementBuffer.Edit): Improved docs, call addRemovedElements and + addAddedElements. + (ElementBuffer.getEditForParagraphAndIndex): New method. + (ElementBuffer.removeUpdate): Changed type of paragraph to + BranchElement. Corrected style of adding the edit to use the new Edit + facilities. + (ElementBuffer.changeUpdate): Changed style of adding the edit to use + the new Edit facilities. + (ElementBuffer.split): Likewise. + (ElementBuffer.insertParagraph): Likewise. + (ElementBuffer.insertContentTag): Likewise. + (ElementBuffer.insert): Push all BranchElements until the deepest one, + not just the root and the first one. Apply the structural changes to + the tree at the same time as updating the DocumentEvent. + (ElementBuffer.insertUpdate): Fixed docs. Removed the special case + handling of EndTags as the first ElementSpec. Instead have to handle + ContentTags as a special case if they are the first ElementSpec and if + not have to fracture the tree. + (ElementBuffer.createFracture): New method. May not be complete yet. + Added FIXME indicating what may remain to be done. + (ElementBuffer.insertFirstContentTag): New method. + (ElementBuffer.insertFracture): Added FIXME explaining what remains to + be done. Changed the adding of edits to use the new Edit facilities. + Removed the adding of edits for Elements that weren't in the tree prior + to the insertion. + (insertUpdate): Removed incorrect condition for setting a StartTag's + direction to JoinNextDirection. + * javax/swing/text/StyleContent.java: + (SmallAttributeSet.toString): Fixed an off-by-one error in the loop + that was causing an ArrayOutOfBoundsException. + +2006-01-17 Roman Kennke + + * native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c: + (Java_gnu_java_nio_channels_FileChannelImpl_init): Improved + exception messages a little. + (Java_gnu_java_nio_channels_FileChannelImpl_open): Provided + alternative implementation for systems without filesystems. + Replaced snprintf with the corresponding target native macro. + (Java_gnu_java_nio_channels_FileChannelImpl_implCloseChannel): + Only do something when we have a filesystem. + (Java_gnu_java_nio_channels_FileChannelImpl_available): Provided + alternative implementation for systems without filesystems. + (Java_gnu_java_nio_channels_FileChannelImpl_size): Provided + alternative implementation for systems without filesystems. + (Java_gnu_java_nio_channels_FileChannelImpl_implPosition): Provided + alternative implementation for systems without filesystems. + (Java_gnu_java_nio_channels_FileChannelImpl_seek): + Only do something when we have a filesystem. + (Java_gnu_java_nio_channels_FileChannelImpl_implTruncate): + Only do something when we have a filesystem. + (Java_gnu_java_nio_channels_FileChannelImpl_mapImpl): Provided + alternative implementation for systems without filesystems. + (Java_gnu_java_nio_channels_FileChannelImpl_read__): + Replaced ssize_t variables with jint. Provided + alternative implementation for systems without filesystems. + (Java_gnu_java_nio_channels_FileChannelImpl_read___3BII): + Replaced ssize_t variables with jint. Provided + alternative implementation for systems without filesystems. + (Java_gnu_java_nio_channels_FileChannelImpl_write__I): + Replaced ssize_t variables with jint. Provided + alternative implementation for systems without filesystems. + (Java_gnu_java_nio_channels_FileChannelImpl_force): + Only do something when we have a filesystem. + (Java_gnu_java_nio_channels_FileChannelImpl_write___3BII): + Replaced ssize_t variables with jint. Provided + alternative implementation for systems without filesystems. + (Java_gnu_java_nio_channels_FileChannelImpl_lock): Reimplemented + to use the corresponding target native macro. + (Java_gnu_java_nio_channels_FileChannelImpl_unlock): Reimplemented + to use the corresponding target native macro. + +2006-01-17 Lillian Angel + + * javax/swing/text/DefaultTextUI.java: + Added deprecated tag. + * javax/swing/text/JTextComponent.java + (AccessibleJTextComponent): Fixed API doc and + partially implemented. + (getCaretPosition): Fixed API doc and implemented. + (getSelectedText): Fixed API doc. + (getSelectionStart): Likewise. + (getSelectionEnd): Likewise. + (caretUpdate): Fixed API doc and + partially implemented. + (getAccessibleStateSet): Likewise. + (getAccessibleRole): Fixed API doc and implemented. + (getAccessibleEditableText): Implemented. + (getAccessibleText): Fixed API doc and implemented. + (insertUpdate): Fixed API doc. + (changedUpdate): Likewise. + (getIndexAtPoint): Likewise. + (getRootEditorRect): Removed. + (getCharacterBounds): Fixed API doc. + (getCharCount): Likewise. + (getCharacterAttribute): Likewise. + (getAtIndex): Likewise. + (getAfterIndex): Likewise. + (getBeforeIndex): Likewise. + (getAccessibleActionCount): Added function stub. + (getAccessibleActionDescription): Added function, + partially implemented. + (doAccessibleAction): Added function stub. + (setTextContents): Likewise. + (insertTextAtIndex): Likewise. + (delete): Likewise. + (cut): Likewise. + (paste): Likewise. + (replaceText): Likewise. + (selectText): Likewise. + (setAttributes): Likewise. + (getAccessibleContext): Implemented. + +2006-01-17 Ito Kazumitsu + + Fixes bug #25817 + * gnu/regexp/RETokenRange.java(constructor): + Keep lo and hi as they are. + (match): Changed the case insensitive comparison. + +2006-01-17 Ito Kazumitsu + + * gnu/regexp/RETokenChar.java(chain): + Do not concatenate tokens whose insens flags are diffent. + +2006-01-17 Roman Kennke + + * native/target/generic/target_generic_network.c: + (targetGenericNetwork_receive): Fixed signature to match the + corresponding .h file. + (targetGenericNetwork_receiveWithAddressPort): Fixed signature + to match the corresponding .h file. + +2006-01-17 Roman Kennke + + * native/jni/classpath/jcl.c: + (JCL_malloc): Replaced calls to malloc with the corresponding + target layer macro. + (JCL_free): Replaced calls to free with the corresponding + target layer macro. + * native/jni/classpath/native_state.c: + (cp_gtk_init_state_table_with_size): Replaced calls to malloc and + calloc with the corresponding target layer macro. + (remove_node): Replaced calls to free with the corresponding + target layer macro. + (add_node): Replaced calls to malloc with the corresponding + target layer macro. + +2006-01-17 Roman Kennke + + * native/jni/java-io/java_io_VMObjectStreamClass.c: + (getFieldReference): Use MALLOC/FREE macros for portability instead + of direct call to malloc() and free(). + +2006-01-17 Roman Kennke + + * native/jni/classpath/jcl.c: Added missing imports. + (JCL_realloc): Fixed signature to include oldsize. This is needed + for some targets. Make this function use the MEMORY_REALLOC macro + for portability. + * native/jni/classpath/jcl.h + (JCL_realloc): Adjusted signature. + * native/jni/java-io/java_io_VMFile.c: + (Java_java_io_VMFile_create): Use target layer macro for handling + errno, for portability. + (Java_java_io_VMFile_length): Release filename string in error cases + before returning. + (Java_java_io_VMFile_list): Initialize filename variable. Use new + version of JCL_realloc. + * native/jni/java-net/java_net_VMInetAddress.c: + (Java_java_net_VMInetAddress_getHostByName): Use renamed macro + TARGET_NATIVE_NETWORK_GET_HOSTADDRESS_BY_NAME. + * native/jni/java-net/javanet.c: + (_javanet_bind): Make errorstr variable const to avoid compiler + warning. + (_javanet_set_option): Fixed typo. + (_javanet_get_option): Fixed typo. + * native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c: + (Java_gnu_java_nio_channels_FileChannelImpl_open): Made + error_string variable const to avoid compiler warning. + * native/target/generic/target_generic_file.h: + Replaced // comments with /* */ comments to avoid compiler warnings. + Added some spaces to make code better readable. + * native/target/generic/target_generic_memory.h: + Replaced // comments with /* */ comments to avoid compiler warnings. + * native/target/generic/target_generic_misc.c: + Removed unused TARGET_NATIVE_MISC_FORMAT_STRING macro. This caused + compiler warnings due to use of varargs. + * native/target/generic/target_generic_misc.h: + Removed unused TARGET_NATIVE_MISC_FORMAT_STRING macro. This caused + compiler warnings due to use of varargs. + * native/target/generic/target_generic_network.h: + Replaced // comments with /* */ comments to avoid compiler warnings. + (targetGenericNetwork_receive): Fixed signature to use signed chars + for buffer parameter to avoid warning when passing a jbyte to the + function. + +2006-01-17 David Gilbert + + * javax/swing/text/StyleConstants.java + (getAlignment): Removed isDefined() check, so that resolving parent is + used for lookup, + (getBackground): Likewise, plus changed default value to Color.BLACK, + (getBidiLevel): Removed isDefined() check, + (getComponent): Likewise, + (getFirstLineIndent): Likewise, + (getFontFamily): Likewise, + (getFontSize): Likewise, + (getForeground): Likewise, + (getIcon): Likewise, + (getLeftIndent): Likewise, + (getLineSpacing): Likewise, + (getRightIndent): Likewise, + (getSpaceAbove): Likewise, + (getSpaceBelow): Likewise, + (getTabSet): Likewise, + (isBold): Likewise, + (isItalic): Likewise, + (isStrikeThrough): Likewise, + (isSubscript): Likewise, + (isSuperscript): Likewise, + (isUnderline): Likewise. + +2006-01-17 Gary Benson + + * java/lang/System.java (setSecurityManager): Catch + ClassNotFoundException not Throwable. + +2006-01-16 Anthony Green + + PR classpath/25803 + * gnu/java/net/protocol/http/Request.java + (createResponseBodyStream): Remove Content-Encoding for + compressed streams. + +2006-01-16 Chris Burdess + + * gnu/xml/stream/XMLParser.java, + gnu/xml/stream/XMLStreamWriterImpl.java: Thoroughly check + XMLStreamWriter arguments for conformance to the XML specifications. + * gnu/xml/transform/Stylesheet.java, + gnu/xml/transform/Template.java, + gnu/xml/transform/TransformerImpl.java, + gnu/xml/xpath/LangFunction.java, + gnu/xml/xpath/Selector.java: better handling of template priorities; + fix indents when pretty-printing; recursive tests for xml:lang. + * gnu/xml/util/XHTMLWriter.java, + gnu/xml/util/XMLWriter.java: Deprecate old serializer classes. + +2006-01-16 Roman Kennke + + * native/target/MinGW/.cvsignore: New file. + * native/target/RTEMS/.cvsignore: New file. + * native/target/SunOS/.cvsignore: New file. + * native/target/embOS/.cvsignore: New file. + * native/target/posix/.cvsignore: New file. + +2006-01-16 David Gilbert + + * javax/swing/text/StyleConstants.java: Updated API docs all over. + +2006-01-16 Roman Kennke + + * configure.ac: Include new target native directories in build. + +2006-01-16 Roman Kennke + + * native/target/generic/target_generic_file.h: Added missing + include. + * native/target/generic/target_generic_network.c: Fixed several + typos and includes. + * native/target/generic/target_generic_network.h: Likewise. + +2006-01-16 Roman Kennke + + * native/target/Makefile.am: Adjusted SUBDIRS and DIST_SUBDIRS + to include the new targets. + * native/target/posix/Makefile.am: Fixed filenames. + +2006-01-16 Roman Kennke + + * native/target/Makefile.am: Include new targets. + * native/target/Linux/Makefile.am: Include new memory layer. + * native/target/MinGW/Makefile.am: New file. Includes MinGW in dist. + * native/target/RTEMS/Makefile.am: New file. Includes RTEMS in dist. + * native/target/SunOS/Makefile.am: New file. Includes SunOS in dist. + * native/target/embOS/Makefile.am: New file. Includes embOS in dist. + * native/target/generic/Makefile.am: Include new memory and math + layer. + * native/target/posix/Makefile.am: New file. Includes posix in dist. + +2006-01-16 Ito Kazumitsu + + Fixes bug #22884 + * gnu/regexp/RE.java(initialize): Parse embedded flags. + * gnu/regexp/RESyntax.java(RE_EMBEDDED_FLAGS): New syntax bit. + +2006-01-16 Roman Kennke + + * native/target/generic/target_generic_network.c: Fixed typo. + * native/target/generic/target_generic_network.h: Fixed typo. + +2006-01-16 Nicolas Geoffray + + * doc/vmintegration.texinfo: Updated subsection of the + java.lang.InstrumentationImpl documentation. + +2006-01-16 Roman Kennke + + * native/target/RTEMS/target_native.h, + * native/target/RTEMS/target_native_file.h, + * native/target/RTEMS/target_native_io.h, + * native/target/RTEMS/target_native_math.h, + * native/target/RTEMS/target_native_memory.h, + * native/target/RTEMS/target_native_misc.h, + * native/target/RTEMS/target_native_network.h: + New files. Implement the target native layer for the RTEMS platform. + +2006-01-16 Roman Kennke + + * native/target/SunOS/target_native.h, + * native/target/SunOS/target_native_file.h, + * native/target/SunOS/target_native_io.h, + * native/target/SunOS/target_native_math.h, + * native/target/SunOS/target_native_memory.h, + * native/target/SunOS/target_native_misc.h, + * native/target/SunOS/target_native_network.h: + New files. Implement the target native layer for the SunOS platform. + +2006-01-16 Roman Kennke + + * native/target/MinGW/target_native.h, + * native/target/MinGW/target_native_file.h, + * native/target/MinGW/target_native_io.h, + * native/target/MinGW/target_native_math.h, + * native/target/MinGW/target_native_memory.h, + * native/target/MinGW/target_native_misc.h, + * native/target/MinGW/target_native_network.h: + New files. Implement the target native layer for the MinGW + platform. + +2006-01-16 Audrius Meskauskas + + PR 25770 + * javax/swing/DefaultCellEditor.java + (delegate): Assign new instance immediately. + (DefaultCellEditor(JTextField textfield)): Require 2 clicks. + (getTableCellEditorComponent): Rewritten. + (prepareAsJTextField):New method (add listener only once). + * javax/swing/JTable.java + (editingCanceled): Rewritten. + (editingStopped ): Rewritten. + (rowAtPoint): Mind row margin. + (getCellRect): Mind row margin. + (getDefaultEditor): Removing JTextComponent border. + (editCellAt): Rewritten. + * javax/swing/plaf/basic/BasicTableUI.java (MouseInputHandler): + Activate editing mode by the mouse clicks. + (getMaximumSize): Mind row margin. + (getPreferredSize): Mind row margin. + (TableAction): Added 'stop editing' command. + +2006-01-16 Roman Kennke + + * jni/java-io/java_io_VMFile.c + (Java_java_io_VMFile_list): Use new 4 argument version of + TARGET_NATIVE_FILE_READ_DIR macro. + * target/Linux/target_native_io.h: Fixed comment at #endif. + * target/Linux/target_native_memory.h: New file. Contains + portability macros for memory operations. + * target/generic/target_generic.c: New file. Contains some functions + for portability. + * target/generic/target_generic.h: Use posix target and shorter macro + names if CP_NEW is set. + * target/generic/target_generic_file.h: Use posix target and shorter + macro names if CP_NEW is set. + (TARGET_NATIVE_FILE_READ_DIR): New parameter for maxNameLength. + * target/generic/target_generic_io.c: New file. Contains some + functions for IO portability. + * target/generic/target_generic_io.h: Use posix target and shorter + macro names if CP_NEW is set. + * target/generic/target_generic_misc.c: New file. Contains some + functions for miscallaneaous portability issues. + * target/generic/target_generic_misc.h: Use posix target and shorter + macro names if CP_NEW is set. + * target/generic/target_generic_network.c: New file. Contains some + functions for networking portability. + * target/generic/target_generic_network.h: Use posix target and + shorter macro names if CP_NEW is set. + * target/posix/Makefile.am, + * target/posix/target_posix.c, + * target/posix/target_posix.h, + * target/posix/target_posix_file.c, + * target/posix/target_posix_file.h, + * target/posix/target_posix_io.c, + * target/posix/target_posix_io.h, + * target/posix/target_posix_math.c, + * target/posix/target_posix_math.h, + * target/posix/target_posix_memory.c, + * target/posix/target_posix_memory.h, + * target/posix/target_posix_misc.c, + * target/posix/target_posix_misc.h, + * target/posix/target_posix_network.c, + * target/posix/target_posix_network.h: + New files. This implements the target native layer macros for + Posix-like systems. + +2006-01-16 Gary Benson + + * java/net/SocketPermission.java (implies): Fix action checks. + +2006-01-16 Roman Kennke + + * native/target/generic/target_generic_math_float.h: Removed. This + file has been replaced by target_generic_math.h. + * native/target/generic/target_generic_math_int.h: Removed. This + file has been replaced by target_generic_math.h. + * native/target/generic/target_generic_math.h: New file. Replaces + the old _int and _float versions. + * native/target/Linux/target_native_math_float.h: Removed. This + file has been replaced by target_native_math.h. + * native/target/Linux/target_native_math_int.h: Removed. This + file has been replaced by target_native_math.h. + * native/target/Linux/target_native_math.h: New file. Replaces + the old _int and _float versions. + * native/target/Linux/Makefile.am: Adjusted for the changed + filenames. + * native/jni/java-io/java_io_VMFile.c: Include target_native_math.h + instead of target_native_math_int.h. + * native/jni/java-nio/gnu_java_nio_channels_FileChannelImpl.c: + Likewise. + * native/target/generic/target_generic_file.h: Likewise. + +2006-01-16 David Gilbert + + * javax/swing/text/MutableAttributeSet.java: Updated API docs all over. + +2006-01-16 David Gilbert + + * javax/swing/text/SimpleAttributeSet.java + (SimpleAttributeSet()): Initialise storage directly, + (SimpleAttributeSet(AttributeSet)): Removed null check and documented + NullPointerException, + (containsAttribute): If key is found locally, don't check resolving + parent if the value doesn't match, + (getAttribute): Removed redundant instanceof and cast. + +2006-01-16 Gary Benson + + * java/lang/System.java (setSecurityManager): Ensure policy + files are loaded before a security manager is put in place. + +2006-01-16 David Gilbert + + * javax/swing/text/SimpleAttributeSet.java: Updated API docs all over. + +2006-01-16 Wolfgang Baer + + * javax/print/attribute/standard/MediaSize.java: + (static_initializer): Added comment. + (MediaSize): Added javadoc to mention cache registration. + (MediaSize): Likewise. + (MediaSize): Likewise. + (MediaSize): Likewise. + +2006-01-16 Raif S. Naffah + + PR classpath/25202 + * gnu/javax/security/auth/login/ConfigFileTokenizer.java: New class. + * gnu/javax/security/auth/login/ConfigFileParser.java: New class. + * gnu/javax/security/auth/login/GnuConfiguration.java: New class. + * javax/security/auth/login/AppConfigurationEntry.java: Updated + copyright year. + (toString): Added method implementation. + (LoginModuleControlFlag.toString): Removed class name from result. + * javax/security/auth/login/Configuration.java: Updated copyright year. + (getConfig(): replaced calls to NullConfiguration with + GnuConfiguration. + 2006-01-15 Tom Tromey * javax/swing/text/html/HTMLDocument.java (parseBuffer): Genericized. @@ -125,6 +5600,178 @@ * javax/print/attribute/standard/PrinterStateReasons.java: (printerStateReasonSet): Genericize the return type. +2006-01-15 Audrius Meskauskas + + * javax/swing/table/DefaultTableCellRenderer.java + (getTableCellRendererComponent): Render null as the empty cell. + +2006-01-14 Anthony Green + + * java/net/ServerSocket.java (accept): Remove bogus + security check. + (implAccept): Add FIXME comment. + +2006-01-14 Wolfgang Baer + + Fixes bug #25387 + * javax/print/Doc.java: Added and enhanced documentation. + * javax/print/SimpleDoc.java: New file. + +2006-01-14 Wolfgang Baer + + * javax/print/attribute/standard/MediaSize.java: + (Other.TABLOID): New MediaSize added in 1.5 + +2006-01-14 Chris Burdess + + * gnu/xml/stream/SAXParser.java: Ensure that parser is reset + correctly when I/O and runtime exceptions occur during parsing. + +2006-01-13 Roman Kennke + + * gnu/java/awt/peer/swing/SwingButtonPeer.java, + * gnu/java/awt/peer/swing/SwingCanvasPeer.java, + * gnu/java/awt/peer/swing/SwingComponent.java, + * gnu/java/awt/peer/swing/SwingComponentPeer.java, + * gnu/java/awt/peer/swing/SwingContainerPeer.java, + * gnu/java/awt/peer/swing/SwingFramePeer.java, + * gnu/java/awt/peer/swing/SwingLabelPeer.java, + * gnu/java/awt/peer/swing/SwingMenuBarPeer.java, + * gnu/java/awt/peer/swing/SwingMenuItemPeer.java, + * gnu/java/awt/peer/swing/SwingMenuPeer.java, + * gnu/java/awt/peer/swing/SwingPanelPeer.java, + * gnu/java/awt/peer/swing/SwingTextFieldPeer.java, + * gnu/java/awt/peer/swing/SwingToolkit.java, + * gnu/java/awt/peer/swing/SwingWindowPeer.java, + * gnu/java/awt/peer/swing/package.html: + New files. Implemented some basic AWT peers based on Swing. + +2006-01-13 Roman Kennke + + * java/awt/peer/ComponentPeer.java: Added API docs all over. + +2006-01-13 Roman Kennke + + * java/awt/MenuComponent.java: Reformatted to better match our + coding style. + +2006-01-13 Roman Kennke + + * java/awt/Frame.java: Reformatted to better match our + coding style. + +2006-01-13 Roman Kennke + + * java/awt/MenuBar.java + (accessibleContext): Removed unnecessary field. This is already + defined in MenuComponent. + (setHelpMenu): Renamed the peer variable to myPeer because it was + hiding a field of MenuComponent. + (addNotify): Removed unnecessary cast. + +2006-01-13 Roman Kennke + + * java/awt/MenuBar.java: Reformatted to better match our + coding style. + +2006-01-13 Roman Kennke + + * java/awt/MenuBar.java + (frame): New field. + (removeNotify): Clear frame field when beeing removed from the + frame. + * java/awt/Frame.java + (setMenuBar): Store a reference of the frame in the MenuBar. + * java/awt/MenuComponent.java + (postEvent): Implemented to forward the call to the parent until + a parent can handle the event. + (dispatchEvent): Moved handling of old style events from + dispatchEventImpl() to here. + (dispatchEventImpl): Moved handling of old style events to + dispatchEvent(). + +2006-01-13 Roman Kennke + + * java/awt/Component.java + (dispatchEvent): Moved handling of old style events from + dispatchEventImpl() to this method. + (translateEvent): Removed unnecessary cast. + (dispatchEventImpl): Moved handling of old style events to + dispatchEvent(). + +2006-01-13 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (createDefaultRoot): Removed FIXME. + (setLogicalStyle): Added fireUndoableEditUpdate call and + removed FIXME. + +2006-01-13 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java + (Edit): New inner class. + (changeUpdate): Changed addEdit call to add a new + instance of Edit to the edits Vector, so addEdits can + be done later. + (split): Likewise. + (insertParagraph): Likewise. + (insertFracture): Likewise. + (insertContentTag): Likewise. + (insert): Added loop to go through edits Vector and perform + addEdit on each object. + +2006-01-13 Chris Burdess + + * gnu/xml/transform/AbstractNumberNode.java, + gnu/xml/transform/ApplyImportsNode.java, + gnu/xml/transform/ApplyTemplatesNode.java, + gnu/xml/transform/AttributeNode.java, + gnu/xml/transform/CallTemplateNode.java, + gnu/xml/transform/ChooseNode.java, + gnu/xml/transform/CommentNode.java, + gnu/xml/transform/CopyNode.java, + gnu/xml/transform/CopyOfNode.java, + gnu/xml/transform/DocumentFunction.java, + gnu/xml/transform/ElementNode.java, + gnu/xml/transform/ForEachNode.java, + gnu/xml/transform/IfNode.java, + gnu/xml/transform/LiteralNode.java, + gnu/xml/transform/MessageNode.java, + gnu/xml/transform/OtherwiseNode.java, + gnu/xml/transform/ParameterNode.java, + gnu/xml/transform/ProcessingInstructionNode.java, + gnu/xml/transform/Stylesheet.java, + gnu/xml/transform/Template.java, + gnu/xml/transform/TemplateNode.java, + gnu/xml/transform/TextNode.java, + gnu/xml/transform/TransformerImpl.java, + gnu/xml/transform/ValueOfNode.java, + gnu/xml/transform/WhenNode.java, + gnu/xml/xpath/NodeTypeTest.java, + gnu/xml/xpath/Selector.java: simplified debugging output; ignore + with-param parameters when template does not define parameters; apply + conflict resolution for templates; strip whitespace on documents + retrieved via document() function; allow node() to match document + nodes. + +2006-01-13 Mark Wielaard + + * doc/www.gnu.org/announce/20060113.wml: New file. + * doc/www.gnu.org/newsitems.txt: Add 0.20 release announcement. + * doc/www.gnu.org/downloads/downloads.wml: Add 0.20. + +2006-01-13 Lillian Angel + + * javax/swing/text/DefaultStyledDocument.java: + Removed unused fields. + (insert): Removed unused fields. + (endEdit): Removed, not needed. + (insertUpdate): Removed call to endEdit. + (prepareContentInsertion): Removed, not needed. + (insertContentTag): Removed call to prepareContentInsertion. + (printElements): Removed, not needed. + (attributeSetsAreSame): Removed, not needed. + 2005-01-13 Mark Wielaard * java/lang/reflect/Modifier.java (toString(int, StringBuffer)): diff --git a/LICENSE b/LICENSE index a01ea5086..44620dcef 100644 --- a/LICENSE +++ b/LICENSE @@ -312,3 +312,49 @@ maintained by Doug Lea and distributed under the following terms: CopyOnWriteArrayList.java has been reimplemented for GNU Classpath, and is distributed under the same terms as other GNU Classpath files, as specified at the top of this file. + +Directory external/relaxngDatatype +RELAX NG Pluggable Datatype Libraries. All files are distributed under +the following notice: + + Copyright (c) 2001, Thai Open Source Software Center Ltd, Sun + Microsystems. All rights reserved. + + Redistribution and use in source and binary forms, with or + without + modification, are permitted provided that the following + conditions are met: + + Redistributions of source code must retain the above + copyright + notice, this list of conditions and the following + disclaimer. + + Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided + with the distribution. + + Neither the names of the copyright holders nor the names of + its + contributors may be used to endorse or promote products + derived + from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/Makefile.am b/Makefile.am index 4a09172e1..b3df98ca1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,8 +1,8 @@ ## Input file for automake to generate the Makefile.in used by configure # lib first, to compile .class files before native code, last examples -SUBDIRS = lib doc external include native resource scripts $(EXAMPLESDIR) -DIST_SUBDIRS = lib doc external include native resource scripts examples +SUBDIRS = lib doc external include native resource scripts tools $(EXAMPLESDIR) +DIST_SUBDIRS = lib doc external include native resource scripts tools examples ACLOCAL_AMFLAGS = -I m4 diff --git a/NEWS b/NEWS index bbf1fdc11..d2d95a186 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,35 @@ +New in release 0.21 (to be released) + +* GNU Crypto and Jessie have been merged into Classpath; this will + provide Classpath with a wide array of cryptographic algorithms + (ciphers, message digests, etc.) and implementations of SSL version + 3 and TLS version 1. These roughly complement the public + `java.security.' `javax.crypto,' and `javax.net.ssl' packages, and + are service providers implementing the underlying algorithms. + +* The new folder tools includes GIOP and RMI stub and tie source code + generators, IOR parser and both transient and persistent GIOP naming services. + +* RELAX NG pluggable XML schema datatype library API and an implementation + for XML Schema Datatypes (http://www.w3.org/TR/xmlschema-2/). + +* JTable columns are rearrangeable and resizeable with mouse. + +* Added experimental support for dynamic creation of the RMI stubs using proxy + classes. The rmic compiler is no longer required (unless for research + and specific stubs). + +Runtime interface changes: + +* A new class, VMMath, is now available which separates the native + mathematical functions from java.lang.Math. The previous fdlibm + implementation now forms the reference material for this class. + +Generics branch changes: + +* Support for the new functionality in Java 1.5 was added to the +java.math classes, including the RoundingMode enumeration. + New in release 0.20 (Jan 13, 2006) * New StAX pull parser and SAX-over-StAX driver. Lots of DOM, SAX/StAX, diff --git a/configure.ac b/configure.ac index 42f608f01..bd3e407b2 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ dnl ----------------------------------------------------------- dnl define([AC_CACHE_LOAD], )dnl dnl define([AC_CACHE_SAVE], )dnl -AC_INIT([GNU Classpath],[0.20-generics],[classpath@gnu.org],[classpath]) +AC_INIT([GNU Classpath],[0.21-pre-generics],[classpath@gnu.org],[classpath]) AC_CONFIG_SRCDIR(java/lang/System.java) AC_CANONICAL_TARGET @@ -568,6 +568,7 @@ doc/api/Makefile external/Makefile external/sax/Makefile external/w3c_dom/Makefile +external/relaxngDatatype/Makefile gnu/classpath/Configuration.java include/Makefile native/Makefile @@ -594,6 +595,7 @@ scripts/classpath.spec lib/Makefile lib/gen-classlist.sh lib/copy-vmresources.sh +tools/Makefile examples/Makefile examples/Makefile.jawt]) AC_CONFIG_COMMANDS([gen-classlist],[chmod 755 lib/gen-classlist.sh]) diff --git a/doc/README.jaxp b/doc/README.jaxp index 55a1df52f..ec8813226 100644 --- a/doc/README.jaxp +++ b/doc/README.jaxp @@ -30,6 +30,7 @@ classes in the above packages. . org.xml.sax.* ... SAX2 interfaces . org.w3c.dom.* ... DOM Level 3 interfaces +. org.relaxng.datatype.* ... RELAX NG pluggable datatypes API CONFORMANCE @@ -175,3 +176,29 @@ using thread context variables. Update: thread context variables have been introduced. This is very untested though, libxmll therefore still has the single thread bottleneck. + + +Validation +=================================================== + +Pluggable datatypes +--------------------------------------------------- +Validators should use the RELAX NG pluggable datatypes API to retrieve +datatype (XML Schema simple type) implementations in a schema-neutral +fashion. The following code demonstrates looking up a W3C XML Schema +nonNegativeInteger datatype: + + DatatypeLibrary xsd = DatatypeLibraryLoader + .createDatatypeLibrary(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Datatype nonNegativeInteger = xsd.createDatatype("nonNegativeInteger"); + +It is also possible to create new types by derivation. For instance, +to create a datatype that will match a US ZIP code: + + DatatypeBuilder b = xsd.createDatatypeBuilder("string"); + b.addParameter("pattern", "(^[0-9]{5}$)|(^[0-9]{5}-[0-9]{4}$)"); + Datatype zipCode = b.createDatatype(); + +A datatype library implementation for XML Schema is provided; other +library implementations may be added. + diff --git a/doc/api/Makefile.am b/doc/api/Makefile.am index 9f7e808f2..96c586e07 100644 --- a/doc/api/Makefile.am +++ b/doc/api/Makefile.am @@ -44,6 +44,7 @@ create_html: -licensetext \ -linksource \ -splitindex \ + -validhtml \ -d html \ -doctitle "GNU Classpath $(VERSION)" \ -windowtitle "GNU Classpath $(VERSION) Documentation" \ diff --git a/doc/unicode/SpecialCasing-4.0.0.txt b/doc/unicode/SpecialCasing-4.0.0.txt new file mode 100644 index 000000000..34d1c61de --- /dev/null +++ b/doc/unicode/SpecialCasing-4.0.0.txt @@ -0,0 +1,256 @@ +# SpecialCasing-4.0.0.txt +# Date: 2003-03-14, 20:22:04 GMT [MD] +# +# Special Casing Properties +# +# This file is a supplement to the UnicodeData file. +# It contains additional information about the casing of Unicode characters. +# (For compatibility, the UnicodeData.txt file only contains case mappings for +# characters where they are 1-1, and does not have locale-specific mappings.) +# For more information, see the discussion of Case Mappings in the Unicode Standard. +# +# All code points not listed in this file that do not have a simple case mappings +# in UnicodeData.txt map to themselves. +# ================================================================================ +# Format +# ================================================================================ +# The entries in this file are in the following machine-readable format: +# +# ; ; ; <upper> ; (<condition_list> ;)? # <comment> +# +# <code>, <lower>, <title>, and <upper> provide character values in hex. If there is more than +# one character, they are separated by spaces. Other than as used to separate elements, +# spaces are to be ignored. +# +# The <condition_list> is optional. Where present, it consists of one or more locales or contexts, +# separated by spaces. In these conditions: +# - A condition list overrides the normal behavior if all of the listed conditions are true. +# - The context is always the context of the characters in the original string, +# NOT in the resulting string. +# - Case distinctions in the condition list are not significant. +# - Conditions preceded by "Not_" represent the negation of the condition. +# +# A locale is defined as: +# <locale> := <ISO_639_code> ( "_" <ISO_3166_code> ( "_" <variant> )? )? +# <ISO_3166_code> := 2-letter ISO country code, +# <ISO_639_code> := 2-letter ISO language code +# +# A context is one of the following, as defined in the Unicode Standard: +# Final_Sigma, After_Soft_Dotted, More_Above, Before_Dot, Not_Before_Dot, After_I +# +# Parsers of this file must be prepared to deal with future additions to this format: +# * Additional contexts +# * Additional fields +# ================================================================================ + +# ================================================================================ +# Unconditional mappings +# ================================================================================ + +# The German es-zed is special--the normal mapping is to SS. +# Note: the titlecase should never occur in practice. It is equal to titlecase(uppercase(<es-zed>)) + +00DF; 00DF; 0053 0073; 0053 0053; # LATIN SMALL LETTER SHARP S + +# Preserve canonical equivalence for I with dot. Turkic is handled below. + +0130; 0069 0307; 0130; 0130; # LATIN CAPITAL LETTER I WITH DOT ABOVE + +# Ligatures + +FB00; FB00; 0046 0066; 0046 0046; # LATIN SMALL LIGATURE FF +FB01; FB01; 0046 0069; 0046 0049; # LATIN SMALL LIGATURE FI +FB02; FB02; 0046 006C; 0046 004C; # LATIN SMALL LIGATURE FL +FB03; FB03; 0046 0066 0069; 0046 0046 0049; # LATIN SMALL LIGATURE FFI +FB04; FB04; 0046 0066 006C; 0046 0046 004C; # LATIN SMALL LIGATURE FFL +FB05; FB05; 0053 0074; 0053 0054; # LATIN SMALL LIGATURE LONG S T +FB06; FB06; 0053 0074; 0053 0054; # LATIN SMALL LIGATURE ST + +0587; 0587; 0535 0582; 0535 0552; # ARMENIAN SMALL LIGATURE ECH YIWN +FB13; FB13; 0544 0576; 0544 0546; # ARMENIAN SMALL LIGATURE MEN NOW +FB14; FB14; 0544 0565; 0544 0535; # ARMENIAN SMALL LIGATURE MEN ECH +FB15; FB15; 0544 056B; 0544 053B; # ARMENIAN SMALL LIGATURE MEN INI +FB16; FB16; 054E 0576; 054E 0546; # ARMENIAN SMALL LIGATURE VEW NOW +FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH + +# No corresponding uppercase precomposed character + +0149; 0149; 02BC 004E; 02BC 004E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +0390; 0390; 0399 0308 0301; 0399 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +03B0; 03B0; 03A5 0308 0301; 03A5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +01F0; 01F0; 004A 030C; 004A 030C; # LATIN SMALL LETTER J WITH CARON +1E96; 1E96; 0048 0331; 0048 0331; # LATIN SMALL LETTER H WITH LINE BELOW +1E97; 1E97; 0054 0308; 0054 0308; # LATIN SMALL LETTER T WITH DIAERESIS +1E98; 1E98; 0057 030A; 0057 030A; # LATIN SMALL LETTER W WITH RING ABOVE +1E99; 1E99; 0059 030A; 0059 030A; # LATIN SMALL LETTER Y WITH RING ABOVE +1E9A; 1E9A; 0041 02BE; 0041 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING +1F50; 1F50; 03A5 0313; 03A5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI +1F52; 1F52; 03A5 0313 0300; 03A5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA +1F54; 1F54; 03A5 0313 0301; 03A5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA +1F56; 1F56; 03A5 0313 0342; 03A5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI +1FB6; 1FB6; 0391 0342; 0391 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI +1FC6; 1FC6; 0397 0342; 0397 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI +1FD2; 1FD2; 0399 0308 0300; 0399 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA +1FD3; 1FD3; 0399 0308 0301; 0399 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD6; 1FD6; 0399 0342; 0399 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI +1FD7; 1FD7; 0399 0308 0342; 0399 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI +1FE2; 1FE2; 03A5 0308 0300; 03A5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA +1FE3; 1FE3; 03A5 0308 0301; 03A5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA +1FE4; 1FE4; 03A1 0313; 03A1 0313; # GREEK SMALL LETTER RHO WITH PSILI +1FE6; 1FE6; 03A5 0342; 03A5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI +1FE7; 1FE7; 03A5 0308 0342; 03A5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI +1FF6; 1FF6; 03A9 0342; 03A9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI + +# IMPORTANT-when capitalizing iota-subscript (0345) +# It MUST be in normalized form--moved to the end of any sequence of combining marks. +# This is because logically it represents a following base character! +# E.g. <iota_subscript> (<Mn> | <Mc> | <Me>)+ => (<Mn> | <Mc> | <Me>)+ <iota_subscript> +# It should never be the first character in a word, so in titlecasing it can be left as is. + +# The following cases are already in the UnicodeData file, so are only commented here. + +# 0345; 0345; 0345; 0399; # COMBINING GREEK YPOGEGRAMMENI + +# All letters with YPOGEGRAMMENI (iota-subscript) or PROSGEGRAMMENI (iota adscript) +# have special uppercases. +# Note: characters with PROSGEGRAMMENI are actually titlecase, not uppercase! + +1F80; 1F80; 1F88; 1F08 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI +1F81; 1F81; 1F89; 1F09 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI +1F82; 1F82; 1F8A; 1F0A 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F83; 1F83; 1F8B; 1F0B 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F84; 1F84; 1F8C; 1F0C 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F85; 1F85; 1F8D; 1F0D 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F86; 1F86; 1F8E; 1F0E 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F87; 1F87; 1F8F; 1F0F 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F88; 1F80; 1F88; 1F08 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F89; 1F81; 1F89; 1F09 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +1F8A; 1F82; 1F8A; 1F0A 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F8B; 1F83; 1F8B; 1F0B 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F8C; 1F84; 1F8C; 1F0C 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F8D; 1F85; 1F8D; 1F0D 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F8E; 1F86; 1F8E; 1F0E 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F8F; 1F87; 1F8F; 1F0F 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F90; 1F90; 1F98; 1F28 0399; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI +1F91; 1F91; 1F99; 1F29 0399; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI +1F92; 1F92; 1F9A; 1F2A 0399; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F93; 1F93; 1F9B; 1F2B 0399; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F94; 1F94; 1F9C; 1F2C 0399; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F95; 1F95; 1F9D; 1F2D 0399; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F96; 1F96; 1F9E; 1F2E 0399; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F97; 1F97; 1F9F; 1F2F 0399; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F98; 1F90; 1F98; 1F28 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F99; 1F91; 1F99; 1F29 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +1F9A; 1F92; 1F9A; 1F2A 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F9B; 1F93; 1F9B; 1F2B 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F9C; 1F94; 1F9C; 1F2C 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F9D; 1F95; 1F9D; 1F2D 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F9E; 1F96; 1F9E; 1F2E 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F9F; 1F97; 1F9F; 1F2F 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FA0; 1FA0; 1FA8; 1F68 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI +1FA1; 1FA1; 1FA9; 1F69 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI +1FA2; 1FA2; 1FAA; 1F6A 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1FA3; 1FA3; 1FAB; 1F6B 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1FA4; 1FA4; 1FAC; 1F6C 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1FA5; 1FA5; 1FAD; 1F6D 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1FA6; 1FA6; 1FAE; 1F6E 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1FA7; 1FA7; 1FAF; 1F6F 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1FA8; 1FA0; 1FA8; 1F68 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1FA9; 1FA1; 1FA9; 1F69 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +1FAA; 1FA2; 1FAA; 1F6A 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1FAB; 1FA3; 1FAB; 1F6B 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1FAC; 1FA4; 1FAC; 1F6C 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1FAD; 1FA5; 1FAD; 1F6D 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1FAE; 1FA6; 1FAE; 1F6E 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FAF; 1FA7; 1FAF; 1F6F 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FB3; 1FB3; 1FBC; 0391 0399; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI +1FBC; 1FB3; 1FBC; 0391 0399; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FC3; 1FC3; 1FCC; 0397 0399; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI +1FCC; 1FC3; 1FCC; 0397 0399; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FF3; 1FF3; 1FFC; 03A9 0399; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI +1FFC; 1FF3; 1FFC; 03A9 0399; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI + +# Some characters with YPOGEGRAMMENI are also have no corresponding titlecases + +1FB2; 1FB2; 1FBA 0345; 1FBA 0399; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI +1FB4; 1FB4; 0386 0345; 0386 0399; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FC2; 1FC2; 1FCA 0345; 1FCA 0399; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI +1FC4; 1FC4; 0389 0345; 0389 0399; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FF2; 1FF2; 1FFA 0345; 1FFA 0399; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI +1FF4; 1FF4; 038F 0345; 038F 0399; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI + +1FB7; 1FB7; 0391 0342 0345; 0391 0342 0399; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI +1FC7; 1FC7; 0397 0342 0345; 0397 0342 0399; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI +1FF7; 1FF7; 03A9 0342 0345; 03A9 0342 0399; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI + +# ================================================================================ +# Conditional mappings +# ================================================================================ + +# Special case for final form of sigma + +03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA + +# Note: the following cases for non-final are already in the UnicodeData file. + +# 03A3; 03C3; 03A3; 03A3; # GREEK CAPITAL LETTER SIGMA +# 03C3; 03C3; 03A3; 03A3; # GREEK SMALL LETTER SIGMA +# 03C2; 03C2; 03A3; 03A3; # GREEK SMALL LETTER FINAL SIGMA + +# Note: the following cases are not included, since they would case-fold in lowercasing + +# 03C3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK SMALL LETTER SIGMA +# 03C2; 03C3; 03A3; 03A3; Not_Final_Sigma; # GREEK SMALL LETTER FINAL SIGMA + +# ================================================================================ +# Locale-sensitive mappings +# ================================================================================ + +# Lithuanian + +# Lithuanian retains the dot in a lowercase i when followed by accents. + +# Remove DOT ABOVE after "i" with upper or titlecase + +0307; 0307; ; ; lt After_Soft_Dotted; # COMBINING DOT ABOVE + +# Introduce an explicit dot above when lowercasing capital I's and J's +# whenever there are more accents above. +# (of the accents used in Lithuanian: grave, acute, tilde above, and ogonek) + +0049; 0069 0307; 0049; 0049; lt More_Above; # LATIN CAPITAL LETTER I +004A; 006A 0307; 004A; 004A; lt More_Above; # LATIN CAPITAL LETTER J +012E; 012F 0307; 012E; 012E; lt More_Above; # LATIN CAPITAL LETTER I WITH OGONEK +00CC; 0069 0307 0300; 00CC; 00CC; lt; # LATIN CAPITAL LETTER I WITH GRAVE +00CD; 0069 0307 0301; 00CD; 00CD; lt; # LATIN CAPITAL LETTER I WITH ACUTE +0128; 0069 0307 0303; 0128; 0128; lt; # LATIN CAPITAL LETTER I WITH TILDE + +# ================================================================================ + +# Turkish and Azeri + +# I and i-dotless; I-dot and i are case pairs in Turkish and Azeri +# The following rules handle those cases. + +0130; 0069; 0130; 0130; tr; # LATIN CAPITAL LETTER I WITH DOT ABOVE +0130; 0069; 0130; 0130; az; # LATIN CAPITAL LETTER I WITH DOT ABOVE + +# When lowercasing, remove dot_above in the sequence I + dot_above, which will turn into i. +# This matches the behavior of the canonically equivalent I-dot_above + +0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE +0307; ; 0307; 0307; az After_I; # COMBINING DOT ABOVE + +# When lowercasing, unless an I is before a dot_above, it turns into a dotless i. + +0049; 0131; 0049; 0049; tr Not_Before_Dot; # LATIN CAPITAL LETTER I +0049; 0131; 0049; 0049; az Not_Before_Dot; # LATIN CAPITAL LETTER I + +# When uppercasing, i turns into a dotted capital I + +0069; 0069; 0130; 0130; tr; # LATIN SMALL LETTER I +0069; 0069; 0130; 0130; az; # LATIN SMALL LETTER I + +# Note: the following case is already in the UnicodeData file. + +# 0131; 0131; 0049; 0049; tr; # LATIN SMALL LETTER DOTLESS I diff --git a/doc/unicode/UnicodeData-4.0.0.txt b/doc/unicode/UnicodeData-4.0.0.txt new file mode 100644 index 000000000..86ea1cf9f --- /dev/null +++ b/doc/unicode/UnicodeData-4.0.0.txt @@ -0,0 +1,15100 @@ +0000;<control>;Cc;0;BN;;;;;N;NULL;;;; +0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; +0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; +0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; +0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; +0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; +0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; +0007;<control>;Cc;0;BN;;;;;N;BELL;;;; +0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;; +0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;; +000A;<control>;Cc;0;B;;;;;N;LINE FEED (LF);;;; +000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;; +000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;; +000D;<control>;Cc;0;B;;;;;N;CARRIAGE RETURN (CR);;;; +000E;<control>;Cc;0;BN;;;;;N;SHIFT OUT;;;; +000F;<control>;Cc;0;BN;;;;;N;SHIFT IN;;;; +0010;<control>;Cc;0;BN;;;;;N;DATA LINK ESCAPE;;;; +0011;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL ONE;;;; +0012;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL TWO;;;; +0013;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL THREE;;;; +0014;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL FOUR;;;; +0015;<control>;Cc;0;BN;;;;;N;NEGATIVE ACKNOWLEDGE;;;; +0016;<control>;Cc;0;BN;;;;;N;SYNCHRONOUS IDLE;;;; +0017;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION BLOCK;;;; +0018;<control>;Cc;0;BN;;;;;N;CANCEL;;;; +0019;<control>;Cc;0;BN;;;;;N;END OF MEDIUM;;;; +001A;<control>;Cc;0;BN;;;;;N;SUBSTITUTE;;;; +001B;<control>;Cc;0;BN;;;;;N;ESCAPE;;;; +001C;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR FOUR;;;; +001D;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR THREE;;;; +001E;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR TWO;;;; +001F;<control>;Cc;0;S;;;;;N;INFORMATION SEPARATOR ONE;;;; +0020;SPACE;Zs;0;WS;;;;;N;;;;; +0021;EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +0022;QUOTATION MARK;Po;0;ON;;;;;N;;;;; +0023;NUMBER SIGN;Po;0;ET;;;;;N;;;;; +0024;DOLLAR SIGN;Sc;0;ET;;;;;N;;;;; +0025;PERCENT SIGN;Po;0;ET;;;;;N;;;;; +0026;AMPERSAND;Po;0;ON;;;;;N;;;;; +0027;APOSTROPHE;Po;0;ON;;;;;N;APOSTROPHE-QUOTE;;;; +0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;; +0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;; +002A;ASTERISK;Po;0;ON;;;;;N;;;;; +002B;PLUS SIGN;Sm;0;ET;;;;;N;;;;; +002C;COMMA;Po;0;CS;;;;;N;;;;; +002D;HYPHEN-MINUS;Pd;0;ET;;;;;N;;;;; +002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;; +002F;SOLIDUS;Po;0;ES;;;;;N;SLASH;;;; +0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; +0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;; +0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;; +0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;; +0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;; +0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;; +0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;; +0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;; +0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;; +0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;; +003A;COLON;Po;0;CS;;;;;N;;;;; +003B;SEMICOLON;Po;0;ON;;;;;N;;;;; +003C;LESS-THAN SIGN;Sm;0;ON;;;;;Y;;;;; +003D;EQUALS SIGN;Sm;0;ON;;;;;N;;;;; +003E;GREATER-THAN SIGN;Sm;0;ON;;;;;Y;;;;; +003F;QUESTION MARK;Po;0;ON;;;;;N;;;;; +0040;COMMERCIAL AT;Po;0;ON;;;;;N;;;;; +0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061; +0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062; +0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063; +0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064; +0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065; +0046;LATIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;0066; +0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067; +0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068; +0049;LATIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;0069; +004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A; +004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B; +004C;LATIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;006C; +004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D; +004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E; +004F;LATIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;006F; +0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070; +0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071; +0052;LATIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;0072; +0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073; +0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074; +0055;LATIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0075; +0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076; +0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077; +0058;LATIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;0078; +0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079; +005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A; +005B;LEFT SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;; +005C;REVERSE SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;; +005D;RIGHT SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;; +005E;CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;; +005F;LOW LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;; +0060;GRAVE ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;; +0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041 +0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042 +0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043 +0064;LATIN SMALL LETTER D;Ll;0;L;;;;;N;;;0044;;0044 +0065;LATIN SMALL LETTER E;Ll;0;L;;;;;N;;;0045;;0045 +0066;LATIN SMALL LETTER F;Ll;0;L;;;;;N;;;0046;;0046 +0067;LATIN SMALL LETTER G;Ll;0;L;;;;;N;;;0047;;0047 +0068;LATIN SMALL LETTER H;Ll;0;L;;;;;N;;;0048;;0048 +0069;LATIN SMALL LETTER I;Ll;0;L;;;;;N;;;0049;;0049 +006A;LATIN SMALL LETTER J;Ll;0;L;;;;;N;;;004A;;004A +006B;LATIN SMALL LETTER K;Ll;0;L;;;;;N;;;004B;;004B +006C;LATIN SMALL LETTER L;Ll;0;L;;;;;N;;;004C;;004C +006D;LATIN SMALL LETTER M;Ll;0;L;;;;;N;;;004D;;004D +006E;LATIN SMALL LETTER N;Ll;0;L;;;;;N;;;004E;;004E +006F;LATIN SMALL LETTER O;Ll;0;L;;;;;N;;;004F;;004F +0070;LATIN SMALL LETTER P;Ll;0;L;;;;;N;;;0050;;0050 +0071;LATIN SMALL LETTER Q;Ll;0;L;;;;;N;;;0051;;0051 +0072;LATIN SMALL LETTER R;Ll;0;L;;;;;N;;;0052;;0052 +0073;LATIN SMALL LETTER S;Ll;0;L;;;;;N;;;0053;;0053 +0074;LATIN SMALL LETTER T;Ll;0;L;;;;;N;;;0054;;0054 +0075;LATIN SMALL LETTER U;Ll;0;L;;;;;N;;;0055;;0055 +0076;LATIN SMALL LETTER V;Ll;0;L;;;;;N;;;0056;;0056 +0077;LATIN SMALL LETTER W;Ll;0;L;;;;;N;;;0057;;0057 +0078;LATIN SMALL LETTER X;Ll;0;L;;;;;N;;;0058;;0058 +0079;LATIN SMALL LETTER Y;Ll;0;L;;;;;N;;;0059;;0059 +007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A +007B;LEFT CURLY BRACKET;Ps;0;ON;;;;;Y;OPENING CURLY BRACKET;;;; +007C;VERTICAL LINE;Sm;0;ON;;;;;N;VERTICAL BAR;;;; +007D;RIGHT CURLY BRACKET;Pe;0;ON;;;;;Y;CLOSING CURLY BRACKET;;;; +007E;TILDE;Sm;0;ON;;;;;N;;;;; +007F;<control>;Cc;0;BN;;;;;N;DELETE;;;; +0080;<control>;Cc;0;BN;;;;;N;;;;; +0081;<control>;Cc;0;BN;;;;;N;;;;; +0082;<control>;Cc;0;BN;;;;;N;BREAK PERMITTED HERE;;;; +0083;<control>;Cc;0;BN;;;;;N;NO BREAK HERE;;;; +0084;<control>;Cc;0;BN;;;;;N;;;;; +0085;<control>;Cc;0;B;;;;;N;NEXT LINE (NEL);;;; +0086;<control>;Cc;0;BN;;;;;N;START OF SELECTED AREA;;;; +0087;<control>;Cc;0;BN;;;;;N;END OF SELECTED AREA;;;; +0088;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION SET;;;; +0089;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION WITH JUSTIFICATION;;;; +008A;<control>;Cc;0;BN;;;;;N;LINE TABULATION SET;;;; +008B;<control>;Cc;0;BN;;;;;N;PARTIAL LINE FORWARD;;;; +008C;<control>;Cc;0;BN;;;;;N;PARTIAL LINE BACKWARD;;;; +008D;<control>;Cc;0;BN;;;;;N;REVERSE LINE FEED;;;; +008E;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT TWO;;;; +008F;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT THREE;;;; +0090;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL STRING;;;; +0091;<control>;Cc;0;BN;;;;;N;PRIVATE USE ONE;;;; +0092;<control>;Cc;0;BN;;;;;N;PRIVATE USE TWO;;;; +0093;<control>;Cc;0;BN;;;;;N;SET TRANSMIT STATE;;;; +0094;<control>;Cc;0;BN;;;;;N;CANCEL CHARACTER;;;; +0095;<control>;Cc;0;BN;;;;;N;MESSAGE WAITING;;;; +0096;<control>;Cc;0;BN;;;;;N;START OF GUARDED AREA;;;; +0097;<control>;Cc;0;BN;;;;;N;END OF GUARDED AREA;;;; +0098;<control>;Cc;0;BN;;;;;N;START OF STRING;;;; +0099;<control>;Cc;0;BN;;;;;N;;;;; +009A;<control>;Cc;0;BN;;;;;N;SINGLE CHARACTER INTRODUCER;;;; +009B;<control>;Cc;0;BN;;;;;N;CONTROL SEQUENCE INTRODUCER;;;; +009C;<control>;Cc;0;BN;;;;;N;STRING TERMINATOR;;;; +009D;<control>;Cc;0;BN;;;;;N;OPERATING SYSTEM COMMAND;;;; +009E;<control>;Cc;0;BN;;;;;N;PRIVACY MESSAGE;;;; +009F;<control>;Cc;0;BN;;;;;N;APPLICATION PROGRAM COMMAND;;;; +00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;; +00A1;INVERTED EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +00A2;CENT SIGN;Sc;0;ET;;;;;N;;;;; +00A3;POUND SIGN;Sc;0;ET;;;;;N;;;;; +00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; +00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;; +00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;; +00A7;SECTION SIGN;So;0;ON;;;;;N;;;;; +00A8;DIAERESIS;Sk;0;ON;<compat> 0020 0308;;;;N;SPACING DIAERESIS;;;; +00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;; +00AA;FEMININE ORDINAL INDICATOR;Ll;0;L;<super> 0061;;;;N;;;;; +00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;*;;; +00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;; +00AD;SOFT HYPHEN;Cf;0;ON;;;;;N;;;;; +00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;; +00AF;MACRON;Sk;0;ON;<compat> 0020 0304;;;;N;SPACING MACRON;;;; +00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;; +00B1;PLUS-MINUS SIGN;Sm;0;ET;;;;;N;PLUS-OR-MINUS SIGN;;;; +00B2;SUPERSCRIPT TWO;No;0;EN;<super> 0032;;2;2;N;SUPERSCRIPT DIGIT TWO;;;; +00B3;SUPERSCRIPT THREE;No;0;EN;<super> 0033;;3;3;N;SUPERSCRIPT DIGIT THREE;;;; +00B4;ACUTE ACCENT;Sk;0;ON;<compat> 0020 0301;;;;N;SPACING ACUTE;;;; +00B5;MICRO SIGN;Ll;0;L;<compat> 03BC;;;;N;;;039C;;039C +00B6;PILCROW SIGN;So;0;ON;;;;;N;PARAGRAPH SIGN;;;; +00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;; +00B8;CEDILLA;Sk;0;ON;<compat> 0020 0327;;;;N;SPACING CEDILLA;;;; +00B9;SUPERSCRIPT ONE;No;0;EN;<super> 0031;;1;1;N;SUPERSCRIPT DIGIT ONE;;;; +00BA;MASCULINE ORDINAL INDICATOR;Ll;0;L;<super> 006F;;;;N;;;;; +00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;*;;; +00BC;VULGAR FRACTION ONE QUARTER;No;0;ON;<fraction> 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;; +00BD;VULGAR FRACTION ONE HALF;No;0;ON;<fraction> 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;; +00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON;<fraction> 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;; +00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;; +00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0; +00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1; +00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2; +00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3; +00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4; +00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN CAPITAL LETTER A RING;;;00E5; +00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER A E;ash *;;00E6; +00C7;LATIN CAPITAL LETTER C WITH CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7; +00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL LETTER E GRAVE;;;00E8; +00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9; +00CA;LATIN CAPITAL LETTER E WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E CIRCUMFLEX;;;00EA; +00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB; +00CC;LATIN CAPITAL LETTER I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC; +00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL LETTER I ACUTE;;;00ED; +00CE;LATIN CAPITAL LETTER I WITH CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE; +00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN CAPITAL LETTER I DIAERESIS;;;00EF; +00D0;LATIN CAPITAL LETTER ETH;Lu;0;L;;;;;N;;Icelandic;;00F0; +00D1;LATIN CAPITAL LETTER N WITH TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1; +00D2;LATIN CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O GRAVE;;;00F2; +00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3; +00D4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O CIRCUMFLEX;;;00F4; +00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5; +00D6;LATIN CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6; +00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;; +00D8;LATIN CAPITAL LETTER O WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8; +00D9;LATIN CAPITAL LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U GRAVE;;;00F9; +00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA; +00DB;LATIN CAPITAL LETTER U WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U CIRCUMFLEX;;;00FB; +00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC; +00DD;LATIN CAPITAL LETTER Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD; +00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;Icelandic;;00FE; +00DF;LATIN SMALL LETTER SHARP S;Ll;0;L;;;;;N;;German;;; +00E0;LATIN SMALL LETTER A WITH GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0 +00E1;LATIN SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A ACUTE;;00C1;;00C1 +00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2 +00E3;LATIN SMALL LETTER A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3 +00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL LETTER A DIAERESIS;;00C4;;00C4 +00E5;LATIN SMALL LETTER A WITH RING ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5 +00E6;LATIN SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;ash *;00C6;;00C6 +00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL LETTER C CEDILLA;;00C7;;00C7 +00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8 +00E9;LATIN SMALL LETTER E WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9 +00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL LETTER E CIRCUMFLEX;;00CA;;00CA +00EB;LATIN SMALL LETTER E WITH DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB +00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER I GRAVE;;00CC;;00CC +00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD +00EE;LATIN SMALL LETTER I WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I CIRCUMFLEX;;00CE;;00CE +00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF +00F0;LATIN SMALL LETTER ETH;Ll;0;L;;;;;N;;Icelandic;00D0;;00D0 +00F1;LATIN SMALL LETTER N WITH TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1 +00F2;LATIN SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O GRAVE;;00D2;;00D2 +00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3 +00F4;LATIN SMALL LETTER O WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O CIRCUMFLEX;;00D4;;00D4 +00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5 +00F6;LATIN SMALL LETTER O WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O DIAERESIS;;00D6;;00D6 +00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;; +00F8;LATIN SMALL LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8 +00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER U GRAVE;;00D9;;00D9 +00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA +00FB;LATIN SMALL LETTER U WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U CIRCUMFLEX;;00DB;;00DB +00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC +00FD;LATIN SMALL LETTER Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD +00FE;LATIN SMALL LETTER THORN;Ll;0;L;;;;;N;;Icelandic;00DE;;00DE +00FF;LATIN SMALL LETTER Y WITH DIAERESIS;Ll;0;L;0079 0308;;;;N;LATIN SMALL LETTER Y DIAERESIS;;0178;;0178 +0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101; +0101;LATIN SMALL LETTER A WITH MACRON;Ll;0;L;0061 0304;;;;N;LATIN SMALL LETTER A MACRON;;0100;;0100 +0102;LATIN CAPITAL LETTER A WITH BREVE;Lu;0;L;0041 0306;;;;N;LATIN CAPITAL LETTER A BREVE;;;0103; +0103;LATIN SMALL LETTER A WITH BREVE;Ll;0;L;0061 0306;;;;N;LATIN SMALL LETTER A BREVE;;0102;;0102 +0104;LATIN CAPITAL LETTER A WITH OGONEK;Lu;0;L;0041 0328;;;;N;LATIN CAPITAL LETTER A OGONEK;;;0105; +0105;LATIN SMALL LETTER A WITH OGONEK;Ll;0;L;0061 0328;;;;N;LATIN SMALL LETTER A OGONEK;;0104;;0104 +0106;LATIN CAPITAL LETTER C WITH ACUTE;Lu;0;L;0043 0301;;;;N;LATIN CAPITAL LETTER C ACUTE;;;0107; +0107;LATIN SMALL LETTER C WITH ACUTE;Ll;0;L;0063 0301;;;;N;LATIN SMALL LETTER C ACUTE;;0106;;0106 +0108;LATIN CAPITAL LETTER C WITH CIRCUMFLEX;Lu;0;L;0043 0302;;;;N;LATIN CAPITAL LETTER C CIRCUMFLEX;;;0109; +0109;LATIN SMALL LETTER C WITH CIRCUMFLEX;Ll;0;L;0063 0302;;;;N;LATIN SMALL LETTER C CIRCUMFLEX;;0108;;0108 +010A;LATIN CAPITAL LETTER C WITH DOT ABOVE;Lu;0;L;0043 0307;;;;N;LATIN CAPITAL LETTER C DOT;;;010B; +010B;LATIN SMALL LETTER C WITH DOT ABOVE;Ll;0;L;0063 0307;;;;N;LATIN SMALL LETTER C DOT;;010A;;010A +010C;LATIN CAPITAL LETTER C WITH CARON;Lu;0;L;0043 030C;;;;N;LATIN CAPITAL LETTER C HACEK;;;010D; +010D;LATIN SMALL LETTER C WITH CARON;Ll;0;L;0063 030C;;;;N;LATIN SMALL LETTER C HACEK;;010C;;010C +010E;LATIN CAPITAL LETTER D WITH CARON;Lu;0;L;0044 030C;;;;N;LATIN CAPITAL LETTER D HACEK;;;010F; +010F;LATIN SMALL LETTER D WITH CARON;Ll;0;L;0064 030C;;;;N;LATIN SMALL LETTER D HACEK;;010E;;010E +0110;LATIN CAPITAL LETTER D WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D BAR;;;0111; +0111;LATIN SMALL LETTER D WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER D BAR;;0110;;0110 +0112;LATIN CAPITAL LETTER E WITH MACRON;Lu;0;L;0045 0304;;;;N;LATIN CAPITAL LETTER E MACRON;;;0113; +0113;LATIN SMALL LETTER E WITH MACRON;Ll;0;L;0065 0304;;;;N;LATIN SMALL LETTER E MACRON;;0112;;0112 +0114;LATIN CAPITAL LETTER E WITH BREVE;Lu;0;L;0045 0306;;;;N;LATIN CAPITAL LETTER E BREVE;;;0115; +0115;LATIN SMALL LETTER E WITH BREVE;Ll;0;L;0065 0306;;;;N;LATIN SMALL LETTER E BREVE;;0114;;0114 +0116;LATIN CAPITAL LETTER E WITH DOT ABOVE;Lu;0;L;0045 0307;;;;N;LATIN CAPITAL LETTER E DOT;;;0117; +0117;LATIN SMALL LETTER E WITH DOT ABOVE;Ll;0;L;0065 0307;;;;N;LATIN SMALL LETTER E DOT;;0116;;0116 +0118;LATIN CAPITAL LETTER E WITH OGONEK;Lu;0;L;0045 0328;;;;N;LATIN CAPITAL LETTER E OGONEK;;;0119; +0119;LATIN SMALL LETTER E WITH OGONEK;Ll;0;L;0065 0328;;;;N;LATIN SMALL LETTER E OGONEK;;0118;;0118 +011A;LATIN CAPITAL LETTER E WITH CARON;Lu;0;L;0045 030C;;;;N;LATIN CAPITAL LETTER E HACEK;;;011B; +011B;LATIN SMALL LETTER E WITH CARON;Ll;0;L;0065 030C;;;;N;LATIN SMALL LETTER E HACEK;;011A;;011A +011C;LATIN CAPITAL LETTER G WITH CIRCUMFLEX;Lu;0;L;0047 0302;;;;N;LATIN CAPITAL LETTER G CIRCUMFLEX;;;011D; +011D;LATIN SMALL LETTER G WITH CIRCUMFLEX;Ll;0;L;0067 0302;;;;N;LATIN SMALL LETTER G CIRCUMFLEX;;011C;;011C +011E;LATIN CAPITAL LETTER G WITH BREVE;Lu;0;L;0047 0306;;;;N;LATIN CAPITAL LETTER G BREVE;;;011F; +011F;LATIN SMALL LETTER G WITH BREVE;Ll;0;L;0067 0306;;;;N;LATIN SMALL LETTER G BREVE;;011E;;011E +0120;LATIN CAPITAL LETTER G WITH DOT ABOVE;Lu;0;L;0047 0307;;;;N;LATIN CAPITAL LETTER G DOT;;;0121; +0121;LATIN SMALL LETTER G WITH DOT ABOVE;Ll;0;L;0067 0307;;;;N;LATIN SMALL LETTER G DOT;;0120;;0120 +0122;LATIN CAPITAL LETTER G WITH CEDILLA;Lu;0;L;0047 0327;;;;N;LATIN CAPITAL LETTER G CEDILLA;;;0123; +0123;LATIN SMALL LETTER G WITH CEDILLA;Ll;0;L;0067 0327;;;;N;LATIN SMALL LETTER G CEDILLA;;0122;;0122 +0124;LATIN CAPITAL LETTER H WITH CIRCUMFLEX;Lu;0;L;0048 0302;;;;N;LATIN CAPITAL LETTER H CIRCUMFLEX;;;0125; +0125;LATIN SMALL LETTER H WITH CIRCUMFLEX;Ll;0;L;0068 0302;;;;N;LATIN SMALL LETTER H CIRCUMFLEX;;0124;;0124 +0126;LATIN CAPITAL LETTER H WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER H BAR;;;0127; +0127;LATIN SMALL LETTER H WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER H BAR;;0126;;0126 +0128;LATIN CAPITAL LETTER I WITH TILDE;Lu;0;L;0049 0303;;;;N;LATIN CAPITAL LETTER I TILDE;;;0129; +0129;LATIN SMALL LETTER I WITH TILDE;Ll;0;L;0069 0303;;;;N;LATIN SMALL LETTER I TILDE;;0128;;0128 +012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B; +012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A +012C;LATIN CAPITAL LETTER I WITH BREVE;Lu;0;L;0049 0306;;;;N;LATIN CAPITAL LETTER I BREVE;;;012D; +012D;LATIN SMALL LETTER I WITH BREVE;Ll;0;L;0069 0306;;;;N;LATIN SMALL LETTER I BREVE;;012C;;012C +012E;LATIN CAPITAL LETTER I WITH OGONEK;Lu;0;L;0049 0328;;;;N;LATIN CAPITAL LETTER I OGONEK;;;012F; +012F;LATIN SMALL LETTER I WITH OGONEK;Ll;0;L;0069 0328;;;;N;LATIN SMALL LETTER I OGONEK;;012E;;012E +0130;LATIN CAPITAL LETTER I WITH DOT ABOVE;Lu;0;L;0049 0307;;;;N;LATIN CAPITAL LETTER I DOT;;;0069; +0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049 +0132;LATIN CAPITAL LIGATURE IJ;Lu;0;L;<compat> 0049 004A;;;;N;LATIN CAPITAL LETTER I J;;;0133; +0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132 +0134;LATIN CAPITAL LETTER J WITH CIRCUMFLEX;Lu;0;L;004A 0302;;;;N;LATIN CAPITAL LETTER J CIRCUMFLEX;;;0135; +0135;LATIN SMALL LETTER J WITH CIRCUMFLEX;Ll;0;L;006A 0302;;;;N;LATIN SMALL LETTER J CIRCUMFLEX;;0134;;0134 +0136;LATIN CAPITAL LETTER K WITH CEDILLA;Lu;0;L;004B 0327;;;;N;LATIN CAPITAL LETTER K CEDILLA;;;0137; +0137;LATIN SMALL LETTER K WITH CEDILLA;Ll;0;L;006B 0327;;;;N;LATIN SMALL LETTER K CEDILLA;;0136;;0136 +0138;LATIN SMALL LETTER KRA;Ll;0;L;;;;;N;;Greenlandic;;; +0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A; +013A;LATIN SMALL LETTER L WITH ACUTE;Ll;0;L;006C 0301;;;;N;LATIN SMALL LETTER L ACUTE;;0139;;0139 +013B;LATIN CAPITAL LETTER L WITH CEDILLA;Lu;0;L;004C 0327;;;;N;LATIN CAPITAL LETTER L CEDILLA;;;013C; +013C;LATIN SMALL LETTER L WITH CEDILLA;Ll;0;L;006C 0327;;;;N;LATIN SMALL LETTER L CEDILLA;;013B;;013B +013D;LATIN CAPITAL LETTER L WITH CARON;Lu;0;L;004C 030C;;;;N;LATIN CAPITAL LETTER L HACEK;;;013E; +013E;LATIN SMALL LETTER L WITH CARON;Ll;0;L;006C 030C;;;;N;LATIN SMALL LETTER L HACEK;;013D;;013D +013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140; +0140;LATIN SMALL LETTER L WITH MIDDLE DOT;Ll;0;L;<compat> 006C 00B7;;;;N;;;013F;;013F +0141;LATIN CAPITAL LETTER L WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER L SLASH;;;0142; +0142;LATIN SMALL LETTER L WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER L SLASH;;0141;;0141 +0143;LATIN CAPITAL LETTER N WITH ACUTE;Lu;0;L;004E 0301;;;;N;LATIN CAPITAL LETTER N ACUTE;;;0144; +0144;LATIN SMALL LETTER N WITH ACUTE;Ll;0;L;006E 0301;;;;N;LATIN SMALL LETTER N ACUTE;;0143;;0143 +0145;LATIN CAPITAL LETTER N WITH CEDILLA;Lu;0;L;004E 0327;;;;N;LATIN CAPITAL LETTER N CEDILLA;;;0146; +0146;LATIN SMALL LETTER N WITH CEDILLA;Ll;0;L;006E 0327;;;;N;LATIN SMALL LETTER N CEDILLA;;0145;;0145 +0147;LATIN CAPITAL LETTER N WITH CARON;Lu;0;L;004E 030C;;;;N;LATIN CAPITAL LETTER N HACEK;;;0148; +0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147 +0149;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE;Ll;0;L;<compat> 02BC 006E;;;;N;LATIN SMALL LETTER APOSTROPHE N;;;; +014A;LATIN CAPITAL LETTER ENG;Lu;0;L;;;;;N;;Sami;;014B; +014B;LATIN SMALL LETTER ENG;Ll;0;L;;;;;N;;Sami;014A;;014A +014C;LATIN CAPITAL LETTER O WITH MACRON;Lu;0;L;004F 0304;;;;N;LATIN CAPITAL LETTER O MACRON;;;014D; +014D;LATIN SMALL LETTER O WITH MACRON;Ll;0;L;006F 0304;;;;N;LATIN SMALL LETTER O MACRON;;014C;;014C +014E;LATIN CAPITAL LETTER O WITH BREVE;Lu;0;L;004F 0306;;;;N;LATIN CAPITAL LETTER O BREVE;;;014F; +014F;LATIN SMALL LETTER O WITH BREVE;Ll;0;L;006F 0306;;;;N;LATIN SMALL LETTER O BREVE;;014E;;014E +0150;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE;Lu;0;L;004F 030B;;;;N;LATIN CAPITAL LETTER O DOUBLE ACUTE;;;0151; +0151;LATIN SMALL LETTER O WITH DOUBLE ACUTE;Ll;0;L;006F 030B;;;;N;LATIN SMALL LETTER O DOUBLE ACUTE;;0150;;0150 +0152;LATIN CAPITAL LIGATURE OE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O E;;;0153; +0153;LATIN SMALL LIGATURE OE;Ll;0;L;;;;;N;LATIN SMALL LETTER O E;;0152;;0152 +0154;LATIN CAPITAL LETTER R WITH ACUTE;Lu;0;L;0052 0301;;;;N;LATIN CAPITAL LETTER R ACUTE;;;0155; +0155;LATIN SMALL LETTER R WITH ACUTE;Ll;0;L;0072 0301;;;;N;LATIN SMALL LETTER R ACUTE;;0154;;0154 +0156;LATIN CAPITAL LETTER R WITH CEDILLA;Lu;0;L;0052 0327;;;;N;LATIN CAPITAL LETTER R CEDILLA;;;0157; +0157;LATIN SMALL LETTER R WITH CEDILLA;Ll;0;L;0072 0327;;;;N;LATIN SMALL LETTER R CEDILLA;;0156;;0156 +0158;LATIN CAPITAL LETTER R WITH CARON;Lu;0;L;0052 030C;;;;N;LATIN CAPITAL LETTER R HACEK;;;0159; +0159;LATIN SMALL LETTER R WITH CARON;Ll;0;L;0072 030C;;;;N;LATIN SMALL LETTER R HACEK;;0158;;0158 +015A;LATIN CAPITAL LETTER S WITH ACUTE;Lu;0;L;0053 0301;;;;N;LATIN CAPITAL LETTER S ACUTE;;;015B; +015B;LATIN SMALL LETTER S WITH ACUTE;Ll;0;L;0073 0301;;;;N;LATIN SMALL LETTER S ACUTE;;015A;;015A +015C;LATIN CAPITAL LETTER S WITH CIRCUMFLEX;Lu;0;L;0053 0302;;;;N;LATIN CAPITAL LETTER S CIRCUMFLEX;;;015D; +015D;LATIN SMALL LETTER S WITH CIRCUMFLEX;Ll;0;L;0073 0302;;;;N;LATIN SMALL LETTER S CIRCUMFLEX;;015C;;015C +015E;LATIN CAPITAL LETTER S WITH CEDILLA;Lu;0;L;0053 0327;;;;N;LATIN CAPITAL LETTER S CEDILLA;*;;015F; +015F;LATIN SMALL LETTER S WITH CEDILLA;Ll;0;L;0073 0327;;;;N;LATIN SMALL LETTER S CEDILLA;*;015E;;015E +0160;LATIN CAPITAL LETTER S WITH CARON;Lu;0;L;0053 030C;;;;N;LATIN CAPITAL LETTER S HACEK;;;0161; +0161;LATIN SMALL LETTER S WITH CARON;Ll;0;L;0073 030C;;;;N;LATIN SMALL LETTER S HACEK;;0160;;0160 +0162;LATIN CAPITAL LETTER T WITH CEDILLA;Lu;0;L;0054 0327;;;;N;LATIN CAPITAL LETTER T CEDILLA;*;;0163; +0163;LATIN SMALL LETTER T WITH CEDILLA;Ll;0;L;0074 0327;;;;N;LATIN SMALL LETTER T CEDILLA;*;0162;;0162 +0164;LATIN CAPITAL LETTER T WITH CARON;Lu;0;L;0054 030C;;;;N;LATIN CAPITAL LETTER T HACEK;;;0165; +0165;LATIN SMALL LETTER T WITH CARON;Ll;0;L;0074 030C;;;;N;LATIN SMALL LETTER T HACEK;;0164;;0164 +0166;LATIN CAPITAL LETTER T WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T BAR;;;0167; +0167;LATIN SMALL LETTER T WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER T BAR;;0166;;0166 +0168;LATIN CAPITAL LETTER U WITH TILDE;Lu;0;L;0055 0303;;;;N;LATIN CAPITAL LETTER U TILDE;;;0169; +0169;LATIN SMALL LETTER U WITH TILDE;Ll;0;L;0075 0303;;;;N;LATIN SMALL LETTER U TILDE;;0168;;0168 +016A;LATIN CAPITAL LETTER U WITH MACRON;Lu;0;L;0055 0304;;;;N;LATIN CAPITAL LETTER U MACRON;;;016B; +016B;LATIN SMALL LETTER U WITH MACRON;Ll;0;L;0075 0304;;;;N;LATIN SMALL LETTER U MACRON;;016A;;016A +016C;LATIN CAPITAL LETTER U WITH BREVE;Lu;0;L;0055 0306;;;;N;LATIN CAPITAL LETTER U BREVE;;;016D; +016D;LATIN SMALL LETTER U WITH BREVE;Ll;0;L;0075 0306;;;;N;LATIN SMALL LETTER U BREVE;;016C;;016C +016E;LATIN CAPITAL LETTER U WITH RING ABOVE;Lu;0;L;0055 030A;;;;N;LATIN CAPITAL LETTER U RING;;;016F; +016F;LATIN SMALL LETTER U WITH RING ABOVE;Ll;0;L;0075 030A;;;;N;LATIN SMALL LETTER U RING;;016E;;016E +0170;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0055 030B;;;;N;LATIN CAPITAL LETTER U DOUBLE ACUTE;;;0171; +0171;LATIN SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0075 030B;;;;N;LATIN SMALL LETTER U DOUBLE ACUTE;;0170;;0170 +0172;LATIN CAPITAL LETTER U WITH OGONEK;Lu;0;L;0055 0328;;;;N;LATIN CAPITAL LETTER U OGONEK;;;0173; +0173;LATIN SMALL LETTER U WITH OGONEK;Ll;0;L;0075 0328;;;;N;LATIN SMALL LETTER U OGONEK;;0172;;0172 +0174;LATIN CAPITAL LETTER W WITH CIRCUMFLEX;Lu;0;L;0057 0302;;;;N;LATIN CAPITAL LETTER W CIRCUMFLEX;;;0175; +0175;LATIN SMALL LETTER W WITH CIRCUMFLEX;Ll;0;L;0077 0302;;;;N;LATIN SMALL LETTER W CIRCUMFLEX;;0174;;0174 +0176;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX;Lu;0;L;0059 0302;;;;N;LATIN CAPITAL LETTER Y CIRCUMFLEX;;;0177; +0177;LATIN SMALL LETTER Y WITH CIRCUMFLEX;Ll;0;L;0079 0302;;;;N;LATIN SMALL LETTER Y CIRCUMFLEX;;0176;;0176 +0178;LATIN CAPITAL LETTER Y WITH DIAERESIS;Lu;0;L;0059 0308;;;;N;LATIN CAPITAL LETTER Y DIAERESIS;;;00FF; +0179;LATIN CAPITAL LETTER Z WITH ACUTE;Lu;0;L;005A 0301;;;;N;LATIN CAPITAL LETTER Z ACUTE;;;017A; +017A;LATIN SMALL LETTER Z WITH ACUTE;Ll;0;L;007A 0301;;;;N;LATIN SMALL LETTER Z ACUTE;;0179;;0179 +017B;LATIN CAPITAL LETTER Z WITH DOT ABOVE;Lu;0;L;005A 0307;;;;N;LATIN CAPITAL LETTER Z DOT;;;017C; +017C;LATIN SMALL LETTER Z WITH DOT ABOVE;Ll;0;L;007A 0307;;;;N;LATIN SMALL LETTER Z DOT;;017B;;017B +017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E; +017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D +017F;LATIN SMALL LETTER LONG S;Ll;0;L;<compat> 0073;;;;N;;;0053;;0053 +0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;;; +0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253; +0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183; +0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182 +0184;LATIN CAPITAL LETTER TONE SIX;Lu;0;L;;;;;N;;;;0185; +0185;LATIN SMALL LETTER TONE SIX;Ll;0;L;;;;;N;;;0184;;0184 +0186;LATIN CAPITAL LETTER OPEN O;Lu;0;L;;;;;N;;;;0254; +0187;LATIN CAPITAL LETTER C WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER C HOOK;;;0188; +0188;LATIN SMALL LETTER C WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER C HOOK;;0187;;0187 +0189;LATIN CAPITAL LETTER AFRICAN D;Lu;0;L;;;;;N;;*;;0256; +018A;LATIN CAPITAL LETTER D WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D HOOK;;;0257; +018B;LATIN CAPITAL LETTER D WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D TOPBAR;;;018C; +018C;LATIN SMALL LETTER D WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER D TOPBAR;;018B;;018B +018D;LATIN SMALL LETTER TURNED DELTA;Ll;0;L;;;;;N;;;;; +018E;LATIN CAPITAL LETTER REVERSED E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER TURNED E;;;01DD; +018F;LATIN CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;0259; +0190;LATIN CAPITAL LETTER OPEN E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER EPSILON;;;025B; +0191;LATIN CAPITAL LETTER F WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER F HOOK;;;0192; +0192;LATIN SMALL LETTER F WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT F;;0191;;0191 +0193;LATIN CAPITAL LETTER G WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G HOOK;;;0260; +0194;LATIN CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;0263; +0195;LATIN SMALL LETTER HV;Ll;0;L;;;;;N;LATIN SMALL LETTER H V;hwair;01F6;;01F6 +0196;LATIN CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;0269; +0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268; +0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199; +0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198 +019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;;; +019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;;; +019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F; +019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272; +019E;LATIN SMALL LETTER N WITH LONG RIGHT LEG;Ll;0;L;;;;;N;;;0220;;0220 +019F;LATIN CAPITAL LETTER O WITH MIDDLE TILDE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED O;*;;0275; +01A0;LATIN CAPITAL LETTER O WITH HORN;Lu;0;L;004F 031B;;;;N;LATIN CAPITAL LETTER O HORN;;;01A1; +01A1;LATIN SMALL LETTER O WITH HORN;Ll;0;L;006F 031B;;;;N;LATIN SMALL LETTER O HORN;;01A0;;01A0 +01A2;LATIN CAPITAL LETTER OI;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O I;gha;;01A3; +01A3;LATIN SMALL LETTER OI;Ll;0;L;;;;;N;LATIN SMALL LETTER O I;gha;01A2;;01A2 +01A4;LATIN CAPITAL LETTER P WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER P HOOK;;;01A5; +01A5;LATIN SMALL LETTER P WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER P HOOK;;01A4;;01A4 +01A6;LATIN LETTER YR;Lu;0;L;;;;;N;LATIN LETTER Y R;*;;0280; +01A7;LATIN CAPITAL LETTER TONE TWO;Lu;0;L;;;;;N;;;;01A8; +01A8;LATIN SMALL LETTER TONE TWO;Ll;0;L;;;;;N;;;01A7;;01A7 +01A9;LATIN CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;0283; +01AA;LATIN LETTER REVERSED ESH LOOP;Ll;0;L;;;;;N;;;;; +01AB;LATIN SMALL LETTER T WITH PALATAL HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T PALATAL HOOK;;;; +01AC;LATIN CAPITAL LETTER T WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T HOOK;;;01AD; +01AD;LATIN SMALL LETTER T WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T HOOK;;01AC;;01AC +01AE;LATIN CAPITAL LETTER T WITH RETROFLEX HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T RETROFLEX HOOK;;;0288; +01AF;LATIN CAPITAL LETTER U WITH HORN;Lu;0;L;0055 031B;;;;N;LATIN CAPITAL LETTER U HORN;;;01B0; +01B0;LATIN SMALL LETTER U WITH HORN;Ll;0;L;0075 031B;;;;N;LATIN SMALL LETTER U HORN;;01AF;;01AF +01B1;LATIN CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;028A; +01B2;LATIN CAPITAL LETTER V WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER SCRIPT V;;;028B; +01B3;LATIN CAPITAL LETTER Y WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Y HOOK;;;01B4; +01B4;LATIN SMALL LETTER Y WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Y HOOK;;01B3;;01B3 +01B5;LATIN CAPITAL LETTER Z WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Z BAR;;;01B6; +01B6;LATIN SMALL LETTER Z WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER Z BAR;;01B5;;01B5 +01B7;LATIN CAPITAL LETTER EZH;Lu;0;L;;;;;N;LATIN CAPITAL LETTER YOGH;;;0292; +01B8;LATIN CAPITAL LETTER EZH REVERSED;Lu;0;L;;;;;N;LATIN CAPITAL LETTER REVERSED YOGH;;;01B9; +01B9;LATIN SMALL LETTER EZH REVERSED;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED YOGH;;01B8;;01B8 +01BA;LATIN SMALL LETTER EZH WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH WITH TAIL;;;; +01BB;LATIN LETTER TWO WITH STROKE;Lo;0;L;;;;;N;LATIN LETTER TWO BAR;;;; +01BC;LATIN CAPITAL LETTER TONE FIVE;Lu;0;L;;;;;N;;;;01BD; +01BD;LATIN SMALL LETTER TONE FIVE;Ll;0;L;;;;;N;;;01BC;;01BC +01BE;LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER INVERTED GLOTTAL STOP BAR;;;; +01BF;LATIN LETTER WYNN;Ll;0;L;;;;;N;;;01F7;;01F7 +01C0;LATIN LETTER DENTAL CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE;;;; +01C1;LATIN LETTER LATERAL CLICK;Lo;0;L;;;;;N;LATIN LETTER DOUBLE PIPE;;;; +01C2;LATIN LETTER ALVEOLAR CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE DOUBLE BAR;;;; +01C3;LATIN LETTER RETROFLEX CLICK;Lo;0;L;;;;;N;LATIN LETTER EXCLAMATION MARK;;;; +01C4;LATIN CAPITAL LETTER DZ WITH CARON;Lu;0;L;<compat> 0044 017D;;;;N;LATIN CAPITAL LETTER D Z HACEK;;;01C6;01C5 +01C5;LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON;Lt;0;L;<compat> 0044 017E;;;;N;LATIN LETTER CAPITAL D SMALL Z HACEK;;01C4;01C6;01C5 +01C6;LATIN SMALL LETTER DZ WITH CARON;Ll;0;L;<compat> 0064 017E;;;;N;LATIN SMALL LETTER D Z HACEK;;01C4;;01C5 +01C7;LATIN CAPITAL LETTER LJ;Lu;0;L;<compat> 004C 004A;;;;N;LATIN CAPITAL LETTER L J;;;01C9;01C8 +01C8;LATIN CAPITAL LETTER L WITH SMALL LETTER J;Lt;0;L;<compat> 004C 006A;;;;N;LATIN LETTER CAPITAL L SMALL J;;01C7;01C9;01C8 +01C9;LATIN SMALL LETTER LJ;Ll;0;L;<compat> 006C 006A;;;;N;LATIN SMALL LETTER L J;;01C7;;01C8 +01CA;LATIN CAPITAL LETTER NJ;Lu;0;L;<compat> 004E 004A;;;;N;LATIN CAPITAL LETTER N J;;;01CC;01CB +01CB;LATIN CAPITAL LETTER N WITH SMALL LETTER J;Lt;0;L;<compat> 004E 006A;;;;N;LATIN LETTER CAPITAL N SMALL J;;01CA;01CC;01CB +01CC;LATIN SMALL LETTER NJ;Ll;0;L;<compat> 006E 006A;;;;N;LATIN SMALL LETTER N J;;01CA;;01CB +01CD;LATIN CAPITAL LETTER A WITH CARON;Lu;0;L;0041 030C;;;;N;LATIN CAPITAL LETTER A HACEK;;;01CE; +01CE;LATIN SMALL LETTER A WITH CARON;Ll;0;L;0061 030C;;;;N;LATIN SMALL LETTER A HACEK;;01CD;;01CD +01CF;LATIN CAPITAL LETTER I WITH CARON;Lu;0;L;0049 030C;;;;N;LATIN CAPITAL LETTER I HACEK;;;01D0; +01D0;LATIN SMALL LETTER I WITH CARON;Ll;0;L;0069 030C;;;;N;LATIN SMALL LETTER I HACEK;;01CF;;01CF +01D1;LATIN CAPITAL LETTER O WITH CARON;Lu;0;L;004F 030C;;;;N;LATIN CAPITAL LETTER O HACEK;;;01D2; +01D2;LATIN SMALL LETTER O WITH CARON;Ll;0;L;006F 030C;;;;N;LATIN SMALL LETTER O HACEK;;01D1;;01D1 +01D3;LATIN CAPITAL LETTER U WITH CARON;Lu;0;L;0055 030C;;;;N;LATIN CAPITAL LETTER U HACEK;;;01D4; +01D4;LATIN SMALL LETTER U WITH CARON;Ll;0;L;0075 030C;;;;N;LATIN SMALL LETTER U HACEK;;01D3;;01D3 +01D5;LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON;Lu;0;L;00DC 0304;;;;N;LATIN CAPITAL LETTER U DIAERESIS MACRON;;;01D6; +01D6;LATIN SMALL LETTER U WITH DIAERESIS AND MACRON;Ll;0;L;00FC 0304;;;;N;LATIN SMALL LETTER U DIAERESIS MACRON;;01D5;;01D5 +01D7;LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE;Lu;0;L;00DC 0301;;;;N;LATIN CAPITAL LETTER U DIAERESIS ACUTE;;;01D8; +01D8;LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE;Ll;0;L;00FC 0301;;;;N;LATIN SMALL LETTER U DIAERESIS ACUTE;;01D7;;01D7 +01D9;LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON;Lu;0;L;00DC 030C;;;;N;LATIN CAPITAL LETTER U DIAERESIS HACEK;;;01DA; +01DA;LATIN SMALL LETTER U WITH DIAERESIS AND CARON;Ll;0;L;00FC 030C;;;;N;LATIN SMALL LETTER U DIAERESIS HACEK;;01D9;;01D9 +01DB;LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE;Lu;0;L;00DC 0300;;;;N;LATIN CAPITAL LETTER U DIAERESIS GRAVE;;;01DC; +01DC;LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE;Ll;0;L;00FC 0300;;;;N;LATIN SMALL LETTER U DIAERESIS GRAVE;;01DB;;01DB +01DD;LATIN SMALL LETTER TURNED E;Ll;0;L;;;;;N;;;018E;;018E +01DE;LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON;Lu;0;L;00C4 0304;;;;N;LATIN CAPITAL LETTER A DIAERESIS MACRON;;;01DF; +01DF;LATIN SMALL LETTER A WITH DIAERESIS AND MACRON;Ll;0;L;00E4 0304;;;;N;LATIN SMALL LETTER A DIAERESIS MACRON;;01DE;;01DE +01E0;LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON;Lu;0;L;0226 0304;;;;N;LATIN CAPITAL LETTER A DOT MACRON;;;01E1; +01E1;LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON;Ll;0;L;0227 0304;;;;N;LATIN SMALL LETTER A DOT MACRON;;01E0;;01E0 +01E2;LATIN CAPITAL LETTER AE WITH MACRON;Lu;0;L;00C6 0304;;;;N;LATIN CAPITAL LETTER A E MACRON;ash *;;01E3; +01E3;LATIN SMALL LETTER AE WITH MACRON;Ll;0;L;00E6 0304;;;;N;LATIN SMALL LETTER A E MACRON;ash *;01E2;;01E2 +01E4;LATIN CAPITAL LETTER G WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G BAR;;;01E5; +01E5;LATIN SMALL LETTER G WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER G BAR;;01E4;;01E4 +01E6;LATIN CAPITAL LETTER G WITH CARON;Lu;0;L;0047 030C;;;;N;LATIN CAPITAL LETTER G HACEK;;;01E7; +01E7;LATIN SMALL LETTER G WITH CARON;Ll;0;L;0067 030C;;;;N;LATIN SMALL LETTER G HACEK;;01E6;;01E6 +01E8;LATIN CAPITAL LETTER K WITH CARON;Lu;0;L;004B 030C;;;;N;LATIN CAPITAL LETTER K HACEK;;;01E9; +01E9;LATIN SMALL LETTER K WITH CARON;Ll;0;L;006B 030C;;;;N;LATIN SMALL LETTER K HACEK;;01E8;;01E8 +01EA;LATIN CAPITAL LETTER O WITH OGONEK;Lu;0;L;004F 0328;;;;N;LATIN CAPITAL LETTER O OGONEK;;;01EB; +01EB;LATIN SMALL LETTER O WITH OGONEK;Ll;0;L;006F 0328;;;;N;LATIN SMALL LETTER O OGONEK;;01EA;;01EA +01EC;LATIN CAPITAL LETTER O WITH OGONEK AND MACRON;Lu;0;L;01EA 0304;;;;N;LATIN CAPITAL LETTER O OGONEK MACRON;;;01ED; +01ED;LATIN SMALL LETTER O WITH OGONEK AND MACRON;Ll;0;L;01EB 0304;;;;N;LATIN SMALL LETTER O OGONEK MACRON;;01EC;;01EC +01EE;LATIN CAPITAL LETTER EZH WITH CARON;Lu;0;L;01B7 030C;;;;N;LATIN CAPITAL LETTER YOGH HACEK;;;01EF; +01EF;LATIN SMALL LETTER EZH WITH CARON;Ll;0;L;0292 030C;;;;N;LATIN SMALL LETTER YOGH HACEK;;01EE;;01EE +01F0;LATIN SMALL LETTER J WITH CARON;Ll;0;L;006A 030C;;;;N;LATIN SMALL LETTER J HACEK;;;; +01F1;LATIN CAPITAL LETTER DZ;Lu;0;L;<compat> 0044 005A;;;;N;;;;01F3;01F2 +01F2;LATIN CAPITAL LETTER D WITH SMALL LETTER Z;Lt;0;L;<compat> 0044 007A;;;;N;;;01F1;01F3;01F2 +01F3;LATIN SMALL LETTER DZ;Ll;0;L;<compat> 0064 007A;;;;N;;;01F1;;01F2 +01F4;LATIN CAPITAL LETTER G WITH ACUTE;Lu;0;L;0047 0301;;;;N;;;;01F5; +01F5;LATIN SMALL LETTER G WITH ACUTE;Ll;0;L;0067 0301;;;;N;;;01F4;;01F4 +01F6;LATIN CAPITAL LETTER HWAIR;Lu;0;L;;;;;N;;;;0195; +01F7;LATIN CAPITAL LETTER WYNN;Lu;0;L;;;;;N;;;;01BF; +01F8;LATIN CAPITAL LETTER N WITH GRAVE;Lu;0;L;004E 0300;;;;N;;;;01F9; +01F9;LATIN SMALL LETTER N WITH GRAVE;Ll;0;L;006E 0300;;;;N;;;01F8;;01F8 +01FA;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE;Lu;0;L;00C5 0301;;;;N;;;;01FB; +01FB;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE;Ll;0;L;00E5 0301;;;;N;;;01FA;;01FA +01FC;LATIN CAPITAL LETTER AE WITH ACUTE;Lu;0;L;00C6 0301;;;;N;;ash *;;01FD; +01FD;LATIN SMALL LETTER AE WITH ACUTE;Ll;0;L;00E6 0301;;;;N;;ash *;01FC;;01FC +01FE;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE;Lu;0;L;00D8 0301;;;;N;;;;01FF; +01FF;LATIN SMALL LETTER O WITH STROKE AND ACUTE;Ll;0;L;00F8 0301;;;;N;;;01FE;;01FE +0200;LATIN CAPITAL LETTER A WITH DOUBLE GRAVE;Lu;0;L;0041 030F;;;;N;;;;0201; +0201;LATIN SMALL LETTER A WITH DOUBLE GRAVE;Ll;0;L;0061 030F;;;;N;;;0200;;0200 +0202;LATIN CAPITAL LETTER A WITH INVERTED BREVE;Lu;0;L;0041 0311;;;;N;;;;0203; +0203;LATIN SMALL LETTER A WITH INVERTED BREVE;Ll;0;L;0061 0311;;;;N;;;0202;;0202 +0204;LATIN CAPITAL LETTER E WITH DOUBLE GRAVE;Lu;0;L;0045 030F;;;;N;;;;0205; +0205;LATIN SMALL LETTER E WITH DOUBLE GRAVE;Ll;0;L;0065 030F;;;;N;;;0204;;0204 +0206;LATIN CAPITAL LETTER E WITH INVERTED BREVE;Lu;0;L;0045 0311;;;;N;;;;0207; +0207;LATIN SMALL LETTER E WITH INVERTED BREVE;Ll;0;L;0065 0311;;;;N;;;0206;;0206 +0208;LATIN CAPITAL LETTER I WITH DOUBLE GRAVE;Lu;0;L;0049 030F;;;;N;;;;0209; +0209;LATIN SMALL LETTER I WITH DOUBLE GRAVE;Ll;0;L;0069 030F;;;;N;;;0208;;0208 +020A;LATIN CAPITAL LETTER I WITH INVERTED BREVE;Lu;0;L;0049 0311;;;;N;;;;020B; +020B;LATIN SMALL LETTER I WITH INVERTED BREVE;Ll;0;L;0069 0311;;;;N;;;020A;;020A +020C;LATIN CAPITAL LETTER O WITH DOUBLE GRAVE;Lu;0;L;004F 030F;;;;N;;;;020D; +020D;LATIN SMALL LETTER O WITH DOUBLE GRAVE;Ll;0;L;006F 030F;;;;N;;;020C;;020C +020E;LATIN CAPITAL LETTER O WITH INVERTED BREVE;Lu;0;L;004F 0311;;;;N;;;;020F; +020F;LATIN SMALL LETTER O WITH INVERTED BREVE;Ll;0;L;006F 0311;;;;N;;;020E;;020E +0210;LATIN CAPITAL LETTER R WITH DOUBLE GRAVE;Lu;0;L;0052 030F;;;;N;;;;0211; +0211;LATIN SMALL LETTER R WITH DOUBLE GRAVE;Ll;0;L;0072 030F;;;;N;;;0210;;0210 +0212;LATIN CAPITAL LETTER R WITH INVERTED BREVE;Lu;0;L;0052 0311;;;;N;;;;0213; +0213;LATIN SMALL LETTER R WITH INVERTED BREVE;Ll;0;L;0072 0311;;;;N;;;0212;;0212 +0214;LATIN CAPITAL LETTER U WITH DOUBLE GRAVE;Lu;0;L;0055 030F;;;;N;;;;0215; +0215;LATIN SMALL LETTER U WITH DOUBLE GRAVE;Ll;0;L;0075 030F;;;;N;;;0214;;0214 +0216;LATIN CAPITAL LETTER U WITH INVERTED BREVE;Lu;0;L;0055 0311;;;;N;;;;0217; +0217;LATIN SMALL LETTER U WITH INVERTED BREVE;Ll;0;L;0075 0311;;;;N;;;0216;;0216 +0218;LATIN CAPITAL LETTER S WITH COMMA BELOW;Lu;0;L;0053 0326;;;;N;;*;;0219; +0219;LATIN SMALL LETTER S WITH COMMA BELOW;Ll;0;L;0073 0326;;;;N;;*;0218;;0218 +021A;LATIN CAPITAL LETTER T WITH COMMA BELOW;Lu;0;L;0054 0326;;;;N;;*;;021B; +021B;LATIN SMALL LETTER T WITH COMMA BELOW;Ll;0;L;0074 0326;;;;N;;*;021A;;021A +021C;LATIN CAPITAL LETTER YOGH;Lu;0;L;;;;;N;;;;021D; +021D;LATIN SMALL LETTER YOGH;Ll;0;L;;;;;N;;;021C;;021C +021E;LATIN CAPITAL LETTER H WITH CARON;Lu;0;L;0048 030C;;;;N;;;;021F; +021F;LATIN SMALL LETTER H WITH CARON;Ll;0;L;0068 030C;;;;N;;;021E;;021E +0220;LATIN CAPITAL LETTER N WITH LONG RIGHT LEG;Lu;0;L;;;;;N;;;;019E; +0221;LATIN SMALL LETTER D WITH CURL;Ll;0;L;;;;;N;;;;; +0222;LATIN CAPITAL LETTER OU;Lu;0;L;;;;;N;;;;0223; +0223;LATIN SMALL LETTER OU;Ll;0;L;;;;;N;;;0222;;0222 +0224;LATIN CAPITAL LETTER Z WITH HOOK;Lu;0;L;;;;;N;;;;0225; +0225;LATIN SMALL LETTER Z WITH HOOK;Ll;0;L;;;;;N;;;0224;;0224 +0226;LATIN CAPITAL LETTER A WITH DOT ABOVE;Lu;0;L;0041 0307;;;;N;;;;0227; +0227;LATIN SMALL LETTER A WITH DOT ABOVE;Ll;0;L;0061 0307;;;;N;;;0226;;0226 +0228;LATIN CAPITAL LETTER E WITH CEDILLA;Lu;0;L;0045 0327;;;;N;;;;0229; +0229;LATIN SMALL LETTER E WITH CEDILLA;Ll;0;L;0065 0327;;;;N;;;0228;;0228 +022A;LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON;Lu;0;L;00D6 0304;;;;N;;;;022B; +022B;LATIN SMALL LETTER O WITH DIAERESIS AND MACRON;Ll;0;L;00F6 0304;;;;N;;;022A;;022A +022C;LATIN CAPITAL LETTER O WITH TILDE AND MACRON;Lu;0;L;00D5 0304;;;;N;;;;022D; +022D;LATIN SMALL LETTER O WITH TILDE AND MACRON;Ll;0;L;00F5 0304;;;;N;;;022C;;022C +022E;LATIN CAPITAL LETTER O WITH DOT ABOVE;Lu;0;L;004F 0307;;;;N;;;;022F; +022F;LATIN SMALL LETTER O WITH DOT ABOVE;Ll;0;L;006F 0307;;;;N;;;022E;;022E +0230;LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON;Lu;0;L;022E 0304;;;;N;;;;0231; +0231;LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON;Ll;0;L;022F 0304;;;;N;;;0230;;0230 +0232;LATIN CAPITAL LETTER Y WITH MACRON;Lu;0;L;0059 0304;;;;N;;;;0233; +0233;LATIN SMALL LETTER Y WITH MACRON;Ll;0;L;0079 0304;;;;N;;;0232;;0232 +0234;LATIN SMALL LETTER L WITH CURL;Ll;0;L;;;;;N;;;;; +0235;LATIN SMALL LETTER N WITH CURL;Ll;0;L;;;;;N;;;;; +0236;LATIN SMALL LETTER T WITH CURL;Ll;0;L;;;;;N;;;;; +0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;;; +0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;;; +0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;;; +0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181 +0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186 +0255;LATIN SMALL LETTER C WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER C CURL;;;; +0256;LATIN SMALL LETTER D WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER D RETROFLEX HOOK;;0189;;0189 +0257;LATIN SMALL LETTER D WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER D HOOK;;018A;;018A +0258;LATIN SMALL LETTER REVERSED E;Ll;0;L;;;;;N;;;;; +0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F +025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;; +025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190 +025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;;; +025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;; +025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;; +025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;; +0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193 +0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;;; +0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;; +0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194 +0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;; +0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;;; +0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;;; +0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;; +0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197 +0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196 +026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;;; +026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;;; +026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;; +026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;; +026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C +0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;; +0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;;; +0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D +0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;; +0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;; +0275;LATIN SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;019F;;019F +0276;LATIN LETTER SMALL CAPITAL OE;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL O E;;;; +0277;LATIN SMALL LETTER CLOSED OMEGA;Ll;0;L;;;;;N;;;;; +0278;LATIN SMALL LETTER PHI;Ll;0;L;;;;;N;;;;; +0279;LATIN SMALL LETTER TURNED R;Ll;0;L;;;;;N;;;;; +027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;; +027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;; +027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;; +027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;;; +027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;; +027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;; +0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;*;01A6;;01A6 +0281;LATIN LETTER SMALL CAPITAL INVERTED R;Ll;0;L;;;;;N;;;;; +0282;LATIN SMALL LETTER S WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER S HOOK;;;; +0283;LATIN SMALL LETTER ESH;Ll;0;L;;;;;N;;;01A9;;01A9 +0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;; +0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;; +0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;; +0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;;; +0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE +0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;;; +028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1 +028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2 +028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;;; +028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;; +028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;; +028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;; +0290;LATIN SMALL LETTER Z WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Z RETROFLEX HOOK;;;; +0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;; +0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7 +0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;; +0294;LATIN LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;;; +0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;; +0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;; +0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;; +0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;; +0299;LATIN LETTER SMALL CAPITAL B;Ll;0;L;;;;;N;;;;; +029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;; +029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;; +029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;; +029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;;; +029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;;; +029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;; +02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;; +02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;; +02A2;LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP BAR;;;; +02A3;LATIN SMALL LETTER DZ DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z;;;; +02A4;LATIN SMALL LETTER DEZH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D YOGH;;;; +02A5;LATIN SMALL LETTER DZ DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z CURL;;;; +02A6;LATIN SMALL LETTER TS DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T S;;;; +02A7;LATIN SMALL LETTER TESH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T ESH;;;; +02A8;LATIN SMALL LETTER TC DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER T C CURL;;;; +02A9;LATIN SMALL LETTER FENG DIGRAPH;Ll;0;L;;;;;N;;;;; +02AA;LATIN SMALL LETTER LS DIGRAPH;Ll;0;L;;;;;N;;;;; +02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;; +02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; +02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; +02AE;LATIN SMALL LETTER TURNED H WITH FISHHOOK ;Ll;0;L;;;;;N;;;;; +02AF;LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL;Ll;0;L;;;;;N;;;;; +02B0;MODIFIER LETTER SMALL H;Lm;0;L;<super> 0068;;;;N;;;;; +02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L;<super> 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;; +02B2;MODIFIER LETTER SMALL J;Lm;0;L;<super> 006A;;;;N;;;;; +02B3;MODIFIER LETTER SMALL R;Lm;0;L;<super> 0072;;;;N;;;;; +02B4;MODIFIER LETTER SMALL TURNED R;Lm;0;L;<super> 0279;;;;N;;;;; +02B5;MODIFIER LETTER SMALL TURNED R WITH HOOK;Lm;0;L;<super> 027B;;;;N;MODIFIER LETTER SMALL TURNED R HOOK;;;; +02B6;MODIFIER LETTER SMALL CAPITAL INVERTED R;Lm;0;L;<super> 0281;;;;N;;;;; +02B7;MODIFIER LETTER SMALL W;Lm;0;L;<super> 0077;;;;N;;;;; +02B8;MODIFIER LETTER SMALL Y;Lm;0;L;<super> 0079;;;;N;;;;; +02B9;MODIFIER LETTER PRIME;Lm;0;ON;;;;;N;;;;; +02BA;MODIFIER LETTER DOUBLE PRIME;Lm;0;ON;;;;;N;;;;; +02BB;MODIFIER LETTER TURNED COMMA;Lm;0;L;;;;;N;;;;; +02BC;MODIFIER LETTER APOSTROPHE;Lm;0;L;;;;;N;;;;; +02BD;MODIFIER LETTER REVERSED COMMA;Lm;0;L;;;;;N;;;;; +02BE;MODIFIER LETTER RIGHT HALF RING;Lm;0;L;;;;;N;;;;; +02BF;MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;; +02C0;MODIFIER LETTER GLOTTAL STOP;Lm;0;L;;;;;N;;;;; +02C1;MODIFIER LETTER REVERSED GLOTTAL STOP;Lm;0;L;;;;;N;;;;; +02C2;MODIFIER LETTER LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C3;MODIFIER LETTER RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C4;MODIFIER LETTER UP ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C5;MODIFIER LETTER DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C6;MODIFIER LETTER CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER CIRCUMFLEX;;;; +02C7;CARON;Lm;0;ON;;;;;N;MODIFIER LETTER HACEK;Mandarin Chinese third tone;;; +02C8;MODIFIER LETTER VERTICAL LINE;Lm;0;ON;;;;;N;;;;; +02C9;MODIFIER LETTER MACRON;Lm;0;ON;;;;;N;;Mandarin Chinese first tone;;; +02CA;MODIFIER LETTER ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER ACUTE;Mandarin Chinese second tone;;; +02CB;MODIFIER LETTER GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER GRAVE;Mandarin Chinese fourth tone;;; +02CC;MODIFIER LETTER LOW VERTICAL LINE;Lm;0;ON;;;;;N;;;;; +02CD;MODIFIER LETTER LOW MACRON;Lm;0;ON;;;;;N;;;;; +02CE;MODIFIER LETTER LOW GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW GRAVE;;;; +02CF;MODIFIER LETTER LOW ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW ACUTE;;;; +02D0;MODIFIER LETTER TRIANGULAR COLON;Lm;0;L;;;;;N;;;;; +02D1;MODIFIER LETTER HALF TRIANGULAR COLON;Lm;0;L;;;;;N;;;;; +02D2;MODIFIER LETTER CENTRED RIGHT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED RIGHT HALF RING;;;; +02D3;MODIFIER LETTER CENTRED LEFT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED LEFT HALF RING;;;; +02D4;MODIFIER LETTER UP TACK;Sk;0;ON;;;;;N;;;;; +02D5;MODIFIER LETTER DOWN TACK;Sk;0;ON;;;;;N;;;;; +02D6;MODIFIER LETTER PLUS SIGN;Sk;0;ON;;;;;N;;;;; +02D7;MODIFIER LETTER MINUS SIGN;Sk;0;ON;;;;;N;;;;; +02D8;BREVE;Sk;0;ON;<compat> 0020 0306;;;;N;SPACING BREVE;;;; +02D9;DOT ABOVE;Sk;0;ON;<compat> 0020 0307;;;;N;SPACING DOT ABOVE;Mandarin Chinese light tone;;; +02DA;RING ABOVE;Sk;0;ON;<compat> 0020 030A;;;;N;SPACING RING ABOVE;;;; +02DB;OGONEK;Sk;0;ON;<compat> 0020 0328;;;;N;SPACING OGONEK;;;; +02DC;SMALL TILDE;Sk;0;ON;<compat> 0020 0303;;;;N;SPACING TILDE;;;; +02DD;DOUBLE ACUTE ACCENT;Sk;0;ON;<compat> 0020 030B;;;;N;SPACING DOUBLE ACUTE;;;; +02DE;MODIFIER LETTER RHOTIC HOOK;Sk;0;ON;;;;;N;;;;; +02DF;MODIFIER LETTER CROSS ACCENT;Sk;0;ON;;;;;N;;;;; +02E0;MODIFIER LETTER SMALL GAMMA;Lm;0;L;<super> 0263;;;;N;;;;; +02E1;MODIFIER LETTER SMALL L;Lm;0;L;<super> 006C;;;;N;;;;; +02E2;MODIFIER LETTER SMALL S;Lm;0;L;<super> 0073;;;;N;;;;; +02E3;MODIFIER LETTER SMALL X;Lm;0;L;<super> 0078;;;;N;;;;; +02E4;MODIFIER LETTER SMALL REVERSED GLOTTAL STOP;Lm;0;L;<super> 0295;;;;N;;;;; +02E5;MODIFIER LETTER EXTRA-HIGH TONE BAR;Sk;0;ON;;;;;N;;;;; +02E6;MODIFIER LETTER HIGH TONE BAR;Sk;0;ON;;;;;N;;;;; +02E7;MODIFIER LETTER MID TONE BAR;Sk;0;ON;;;;;N;;;;; +02E8;MODIFIER LETTER LOW TONE BAR;Sk;0;ON;;;;;N;;;;; +02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;; +02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; +02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; +02EC;MODIFIER LETTER VOICING;Sk;0;ON;;;;;N;;;;; +02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;; +02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;; +02EF;MODIFIER LETTER LOW DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02F0;MODIFIER LETTER LOW UP ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02F1;MODIFIER LETTER LOW LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02F2;MODIFIER LETTER LOW RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02F3;MODIFIER LETTER LOW RING;Sk;0;ON;;;;;N;;;;; +02F4;MODIFIER LETTER MIDDLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;; +02F5;MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;; +02F6;MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT;Sk;0;ON;;;;;N;;;;; +02F7;MODIFIER LETTER LOW TILDE;Sk;0;ON;;;;;N;;;;; +02F8;MODIFIER LETTER RAISED COLON;Sk;0;ON;;;;;N;;;;; +02F9;MODIFIER LETTER BEGIN HIGH TONE;Sk;0;ON;;;;;N;;;;; +02FA;MODIFIER LETTER END HIGH TONE;Sk;0;ON;;;;;N;;;;; +02FB;MODIFIER LETTER BEGIN LOW TONE;Sk;0;ON;;;;;N;;;;; +02FC;MODIFIER LETTER END LOW TONE;Sk;0;ON;;;;;N;;;;; +02FD;MODIFIER LETTER SHELF;Sk;0;ON;;;;;N;;;;; +02FE;MODIFIER LETTER OPEN SHELF;Sk;0;ON;;;;;N;;;;; +02FF;MODIFIER LETTER LOW LEFT ARROW;Sk;0;ON;;;;;N;;;;; +0300;COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;Varia;;; +0301;COMBINING ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING ACUTE;Oxia, Tonos;;; +0302;COMBINING CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;NON-SPACING CIRCUMFLEX;;;; +0303;COMBINING TILDE;Mn;230;NSM;;;;;N;NON-SPACING TILDE;;;; +0304;COMBINING MACRON;Mn;230;NSM;;;;;N;NON-SPACING MACRON;;;; +0305;COMBINING OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING OVERSCORE;;;; +0306;COMBINING BREVE;Mn;230;NSM;;;;;N;NON-SPACING BREVE;Vrachy;;; +0307;COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOT ABOVE;;;; +0308;COMBINING DIAERESIS;Mn;230;NSM;;;;;N;NON-SPACING DIAERESIS;Dialytika;;; +0309;COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;NON-SPACING HOOK ABOVE;;;; +030A;COMBINING RING ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RING ABOVE;;;; +030B;COMBINING DOUBLE ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE ACUTE;;;; +030C;COMBINING CARON;Mn;230;NSM;;;;;N;NON-SPACING HACEK;;;; +030D;COMBINING VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL LINE ABOVE;;;; +030E;COMBINING DOUBLE VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE VERTICAL LINE ABOVE;;;; +030F;COMBINING DOUBLE GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE GRAVE;;;; +0310;COMBINING CANDRABINDU;Mn;230;NSM;;;;;N;NON-SPACING CANDRABINDU;;;; +0311;COMBINING INVERTED BREVE;Mn;230;NSM;;;;;N;NON-SPACING INVERTED BREVE;;;; +0312;COMBINING TURNED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING TURNED COMMA ABOVE;;;; +0313;COMBINING COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING COMMA ABOVE;Psili;;; +0314;COMBINING REVERSED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING REVERSED COMMA ABOVE;Dasia;;; +0315;COMBINING COMMA ABOVE RIGHT;Mn;232;NSM;;;;;N;NON-SPACING COMMA ABOVE RIGHT;;;; +0316;COMBINING GRAVE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING GRAVE BELOW;;;; +0317;COMBINING ACUTE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING ACUTE BELOW;;;; +0318;COMBINING LEFT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT TACK BELOW;;;; +0319;COMBINING RIGHT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT TACK BELOW;;;; +031A;COMBINING LEFT ANGLE ABOVE;Mn;232;NSM;;;;;N;NON-SPACING LEFT ANGLE ABOVE;;;; +031B;COMBINING HORN;Mn;216;NSM;;;;;N;NON-SPACING HORN;;;; +031C;COMBINING LEFT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT HALF RING BELOW;;;; +031D;COMBINING UP TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING UP TACK BELOW;;;; +031E;COMBINING DOWN TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOWN TACK BELOW;;;; +031F;COMBINING PLUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING PLUS SIGN BELOW;;;; +0320;COMBINING MINUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING MINUS SIGN BELOW;;;; +0321;COMBINING PALATALIZED HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING PALATALIZED HOOK BELOW;;;; +0322;COMBINING RETROFLEX HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING RETROFLEX HOOK BELOW;;;; +0323;COMBINING DOT BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOT BELOW;;;; +0324;COMBINING DIAERESIS BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE DOT BELOW;;;; +0325;COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;; +0326;COMBINING COMMA BELOW;Mn;220;NSM;;;;;N;NON-SPACING COMMA BELOW;;;; +0327;COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;; +0328;COMBINING OGONEK;Mn;202;NSM;;;;;N;NON-SPACING OGONEK;;;; +0329;COMBINING VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;NON-SPACING VERTICAL LINE BELOW;;;; +032A;COMBINING BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BRIDGE BELOW;;;; +032B;COMBINING INVERTED DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED DOUBLE ARCH BELOW;;;; +032C;COMBINING CARON BELOW;Mn;220;NSM;;;;;N;NON-SPACING HACEK BELOW;;;; +032D;COMBINING CIRCUMFLEX ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING CIRCUMFLEX BELOW;;;; +032E;COMBINING BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BREVE BELOW;;;; +032F;COMBINING INVERTED BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BREVE BELOW;;;; +0330;COMBINING TILDE BELOW;Mn;220;NSM;;;;;N;NON-SPACING TILDE BELOW;;;; +0331;COMBINING MACRON BELOW;Mn;220;NSM;;;;;N;NON-SPACING MACRON BELOW;;;; +0332;COMBINING LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING UNDERSCORE;;;; +0333;COMBINING DOUBLE LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE UNDERSCORE;;;; +0334;COMBINING TILDE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING TILDE OVERLAY;;;; +0335;COMBINING SHORT STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT BAR OVERLAY;;;; +0336;COMBINING LONG STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG BAR OVERLAY;;;; +0337;COMBINING SHORT SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT SLASH OVERLAY;;;; +0338;COMBINING LONG SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG SLASH OVERLAY;;;; +0339;COMBINING RIGHT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT HALF RING BELOW;;;; +033A;COMBINING INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BRIDGE BELOW;;;; +033B;COMBINING SQUARE BELOW;Mn;220;NSM;;;;;N;NON-SPACING SQUARE BELOW;;;; +033C;COMBINING SEAGULL BELOW;Mn;220;NSM;;;;;N;NON-SPACING SEAGULL BELOW;;;; +033D;COMBINING X ABOVE;Mn;230;NSM;;;;;N;NON-SPACING X ABOVE;;;; +033E;COMBINING VERTICAL TILDE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL TILDE;;;; +033F;COMBINING DOUBLE OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE OVERSCORE;;;; +0340;COMBINING GRAVE TONE MARK;Mn;230;NSM;0300;;;;N;NON-SPACING GRAVE TONE MARK;Vietnamese;;; +0341;COMBINING ACUTE TONE MARK;Mn;230;NSM;0301;;;;N;NON-SPACING ACUTE TONE MARK;Vietnamese;;; +0342;COMBINING GREEK PERISPOMENI;Mn;230;NSM;;;;;N;;;;; +0343;COMBINING GREEK KORONIS;Mn;230;NSM;0313;;;;N;;;;; +0344;COMBINING GREEK DIALYTIKA TONOS;Mn;230;NSM;0308 0301;;;;N;GREEK NON-SPACING DIAERESIS TONOS;;;; +0345;COMBINING GREEK YPOGEGRAMMENI;Mn;240;NSM;;;;;N;GREEK NON-SPACING IOTA BELOW;;0399;;0399 +0346;COMBINING BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; +0347;COMBINING EQUALS SIGN BELOW;Mn;220;NSM;;;;;N;;;;; +0348;COMBINING DOUBLE VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;;;;; +0349;COMBINING LEFT ANGLE BELOW;Mn;220;NSM;;;;;N;;;;; +034A;COMBINING NOT TILDE ABOVE;Mn;230;NSM;;;;;N;;;;; +034B;COMBINING HOMOTHETIC ABOVE;Mn;230;NSM;;;;;N;;;;; +034C;COMBINING ALMOST EQUAL TO ABOVE;Mn;230;NSM;;;;;N;;;;; +034D;COMBINING LEFT RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; +034E;COMBINING UPWARDS ARROW BELOW;Mn;220;NSM;;;;;N;;;;; +034F;COMBINING GRAPHEME JOINER;Mn;0;NSM;;;;;N;;;;; +0350;COMBINING RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; +0351;COMBINING LEFT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;; +0352;COMBINING FERMATA;Mn;230;NSM;;;;;N;;;;; +0353;COMBINING X BELOW;Mn;220;NSM;;;;;N;;;;; +0354;COMBINING LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +0355;COMBINING RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +0356;COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;; +0357;COMBINING RIGHT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;; +035D;COMBINING DOUBLE BREVE;Mn;234;NSM;;;;;N;;;;; +035E;COMBINING DOUBLE MACRON;Mn;234;NSM;;;;;N;;;;; +035F;COMBINING DOUBLE MACRON BELOW;Mn;233;NSM;;;;;N;;;;; +0360;COMBINING DOUBLE TILDE;Mn;234;NSM;;;;;N;;;;; +0361;COMBINING DOUBLE INVERTED BREVE;Mn;234;NSM;;;;;N;;;;; +0362;COMBINING DOUBLE RIGHTWARDS ARROW BELOW;Mn;233;NSM;;;;;N;;;;; +0363;COMBINING LATIN SMALL LETTER A;Mn;230;NSM;;;;;N;;;;; +0364;COMBINING LATIN SMALL LETTER E;Mn;230;NSM;;;;;N;;;;; +0365;COMBINING LATIN SMALL LETTER I;Mn;230;NSM;;;;;N;;;;; +0366;COMBINING LATIN SMALL LETTER O;Mn;230;NSM;;;;;N;;;;; +0367;COMBINING LATIN SMALL LETTER U;Mn;230;NSM;;;;;N;;;;; +0368;COMBINING LATIN SMALL LETTER C;Mn;230;NSM;;;;;N;;;;; +0369;COMBINING LATIN SMALL LETTER D;Mn;230;NSM;;;;;N;;;;; +036A;COMBINING LATIN SMALL LETTER H;Mn;230;NSM;;;;;N;;;;; +036B;COMBINING LATIN SMALL LETTER M;Mn;230;NSM;;;;;N;;;;; +036C;COMBINING LATIN SMALL LETTER R;Mn;230;NSM;;;;;N;;;;; +036D;COMBINING LATIN SMALL LETTER T;Mn;230;NSM;;;;;N;;;;; +036E;COMBINING LATIN SMALL LETTER V;Mn;230;NSM;;;;;N;;;;; +036F;COMBINING LATIN SMALL LETTER X;Mn;230;NSM;;;;;N;;;;; +0374;GREEK NUMERAL SIGN;Sk;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;Dexia keraia;;; +0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;Aristeri keraia;;; +037A;GREEK YPOGEGRAMMENI;Lm;0;L;<compat> 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;; +037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;Erotimatiko;;; +0384;GREEK TONOS;Sk;0;ON;<compat> 0020 0301;;;;N;GREEK SPACING TONOS;;;; +0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;; +0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC; +0387;GREEK ANO TELEIA;Po;0;ON;00B7;;;;N;;;;; +0388;GREEK CAPITAL LETTER EPSILON WITH TONOS;Lu;0;L;0395 0301;;;;N;GREEK CAPITAL LETTER EPSILON TONOS;;;03AD; +0389;GREEK CAPITAL LETTER ETA WITH TONOS;Lu;0;L;0397 0301;;;;N;GREEK CAPITAL LETTER ETA TONOS;;;03AE; +038A;GREEK CAPITAL LETTER IOTA WITH TONOS;Lu;0;L;0399 0301;;;;N;GREEK CAPITAL LETTER IOTA TONOS;;;03AF; +038C;GREEK CAPITAL LETTER OMICRON WITH TONOS;Lu;0;L;039F 0301;;;;N;GREEK CAPITAL LETTER OMICRON TONOS;;;03CC; +038E;GREEK CAPITAL LETTER UPSILON WITH TONOS;Lu;0;L;03A5 0301;;;;N;GREEK CAPITAL LETTER UPSILON TONOS;;;03CD; +038F;GREEK CAPITAL LETTER OMEGA WITH TONOS;Lu;0;L;03A9 0301;;;;N;GREEK CAPITAL LETTER OMEGA TONOS;;;03CE; +0390;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS;Ll;0;L;03CA 0301;;;;N;GREEK SMALL LETTER IOTA DIAERESIS TONOS;;;; +0391;GREEK CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;03B1; +0392;GREEK CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;03B2; +0393;GREEK CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;03B3; +0394;GREEK CAPITAL LETTER DELTA;Lu;0;L;;;;;N;;;;03B4; +0395;GREEK CAPITAL LETTER EPSILON;Lu;0;L;;;;;N;;;;03B5; +0396;GREEK CAPITAL LETTER ZETA;Lu;0;L;;;;;N;;;;03B6; +0397;GREEK CAPITAL LETTER ETA;Lu;0;L;;;;;N;;;;03B7; +0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8; +0399;GREEK CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;03B9; +039A;GREEK CAPITAL LETTER KAPPA;Lu;0;L;;;;;N;;;;03BA; +039B;GREEK CAPITAL LETTER LAMDA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER LAMBDA;;;03BB; +039C;GREEK CAPITAL LETTER MU;Lu;0;L;;;;;N;;;;03BC; +039D;GREEK CAPITAL LETTER NU;Lu;0;L;;;;;N;;;;03BD; +039E;GREEK CAPITAL LETTER XI;Lu;0;L;;;;;N;;;;03BE; +039F;GREEK CAPITAL LETTER OMICRON;Lu;0;L;;;;;N;;;;03BF; +03A0;GREEK CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;03C0; +03A1;GREEK CAPITAL LETTER RHO;Lu;0;L;;;;;N;;;;03C1; +03A3;GREEK CAPITAL LETTER SIGMA;Lu;0;L;;;;;N;;;;03C3; +03A4;GREEK CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;03C4; +03A5;GREEK CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;03C5; +03A6;GREEK CAPITAL LETTER PHI;Lu;0;L;;;;;N;;;;03C6; +03A7;GREEK CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;03C7; +03A8;GREEK CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;03C8; +03A9;GREEK CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;03C9; +03AA;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA;Lu;0;L;0399 0308;;;;N;GREEK CAPITAL LETTER IOTA DIAERESIS;;;03CA; +03AB;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA;Lu;0;L;03A5 0308;;;;N;GREEK CAPITAL LETTER UPSILON DIAERESIS;;;03CB; +03AC;GREEK SMALL LETTER ALPHA WITH TONOS;Ll;0;L;03B1 0301;;;;N;GREEK SMALL LETTER ALPHA TONOS;;0386;;0386 +03AD;GREEK SMALL LETTER EPSILON WITH TONOS;Ll;0;L;03B5 0301;;;;N;GREEK SMALL LETTER EPSILON TONOS;;0388;;0388 +03AE;GREEK SMALL LETTER ETA WITH TONOS;Ll;0;L;03B7 0301;;;;N;GREEK SMALL LETTER ETA TONOS;;0389;;0389 +03AF;GREEK SMALL LETTER IOTA WITH TONOS;Ll;0;L;03B9 0301;;;;N;GREEK SMALL LETTER IOTA TONOS;;038A;;038A +03B0;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS;Ll;0;L;03CB 0301;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS TONOS;;;; +03B1;GREEK SMALL LETTER ALPHA;Ll;0;L;;;;;N;;;0391;;0391 +03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392 +03B3;GREEK SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0393;;0393 +03B4;GREEK SMALL LETTER DELTA;Ll;0;L;;;;;N;;;0394;;0394 +03B5;GREEK SMALL LETTER EPSILON;Ll;0;L;;;;;N;;;0395;;0395 +03B6;GREEK SMALL LETTER ZETA;Ll;0;L;;;;;N;;;0396;;0396 +03B7;GREEK SMALL LETTER ETA;Ll;0;L;;;;;N;;;0397;;0397 +03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398 +03B9;GREEK SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0399;;0399 +03BA;GREEK SMALL LETTER KAPPA;Ll;0;L;;;;;N;;;039A;;039A +03BB;GREEK SMALL LETTER LAMDA;Ll;0;L;;;;;N;GREEK SMALL LETTER LAMBDA;;039B;;039B +03BC;GREEK SMALL LETTER MU;Ll;0;L;;;;;N;;;039C;;039C +03BD;GREEK SMALL LETTER NU;Ll;0;L;;;;;N;;;039D;;039D +03BE;GREEK SMALL LETTER XI;Ll;0;L;;;;;N;;;039E;;039E +03BF;GREEK SMALL LETTER OMICRON;Ll;0;L;;;;;N;;;039F;;039F +03C0;GREEK SMALL LETTER PI;Ll;0;L;;;;;N;;;03A0;;03A0 +03C1;GREEK SMALL LETTER RHO;Ll;0;L;;;;;N;;;03A1;;03A1 +03C2;GREEK SMALL LETTER FINAL SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3 +03C3;GREEK SMALL LETTER SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3 +03C4;GREEK SMALL LETTER TAU;Ll;0;L;;;;;N;;;03A4;;03A4 +03C5;GREEK SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;03A5;;03A5 +03C6;GREEK SMALL LETTER PHI;Ll;0;L;;;;;N;;;03A6;;03A6 +03C7;GREEK SMALL LETTER CHI;Ll;0;L;;;;;N;;;03A7;;03A7 +03C8;GREEK SMALL LETTER PSI;Ll;0;L;;;;;N;;;03A8;;03A8 +03C9;GREEK SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;03A9;;03A9 +03CA;GREEK SMALL LETTER IOTA WITH DIALYTIKA;Ll;0;L;03B9 0308;;;;N;GREEK SMALL LETTER IOTA DIAERESIS;;03AA;;03AA +03CB;GREEK SMALL LETTER UPSILON WITH DIALYTIKA;Ll;0;L;03C5 0308;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS;;03AB;;03AB +03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C +03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E +03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F +03D0;GREEK BETA SYMBOL;Ll;0;L;<compat> 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392 +03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398 +03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L;<compat> 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;; +03D3;GREEK UPSILON WITH ACUTE AND HOOK SYMBOL;Lu;0;L;03D2 0301;;;;N;GREEK CAPITAL LETTER UPSILON HOOK TONOS;;;; +03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;; +03D5;GREEK PHI SYMBOL;Ll;0;L;<compat> 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6 +03D6;GREEK PI SYMBOL;Ll;0;L;<compat> 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0 +03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;;; +03D8;GREEK LETTER ARCHAIC KOPPA;Lu;0;L;;;;;N;;*;;03D9; +03D9;GREEK SMALL LETTER ARCHAIC KOPPA;Ll;0;L;;;;;N;;*;03D8;;03D8 +03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB; +03DB;GREEK SMALL LETTER STIGMA;Ll;0;L;;;;;N;;;03DA;;03DA +03DC;GREEK LETTER DIGAMMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DIGAMMA;;;03DD; +03DD;GREEK SMALL LETTER DIGAMMA;Ll;0;L;;;;;N;;;03DC;;03DC +03DE;GREEK LETTER KOPPA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KOPPA;;;03DF; +03DF;GREEK SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;03DE;;03DE +03E0;GREEK LETTER SAMPI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SAMPI;;;03E1; +03E1;GREEK SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;03E0;;03E0 +03E2;COPTIC CAPITAL LETTER SHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHEI;;;03E3; +03E3;COPTIC SMALL LETTER SHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER SHEI;;03E2;;03E2 +03E4;COPTIC CAPITAL LETTER FEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER FEI;;;03E5; +03E5;COPTIC SMALL LETTER FEI;Ll;0;L;;;;;N;GREEK SMALL LETTER FEI;;03E4;;03E4 +03E6;COPTIC CAPITAL LETTER KHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KHEI;;;03E7; +03E7;COPTIC SMALL LETTER KHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER KHEI;;03E6;;03E6 +03E8;COPTIC CAPITAL LETTER HORI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER HORI;;;03E9; +03E9;COPTIC SMALL LETTER HORI;Ll;0;L;;;;;N;GREEK SMALL LETTER HORI;;03E8;;03E8 +03EA;COPTIC CAPITAL LETTER GANGIA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER GANGIA;;;03EB; +03EB;COPTIC SMALL LETTER GANGIA;Ll;0;L;;;;;N;GREEK SMALL LETTER GANGIA;;03EA;;03EA +03EC;COPTIC CAPITAL LETTER SHIMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHIMA;;;03ED; +03ED;COPTIC SMALL LETTER SHIMA;Ll;0;L;;;;;N;GREEK SMALL LETTER SHIMA;;03EC;;03EC +03EE;COPTIC CAPITAL LETTER DEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DEI;;;03EF; +03EF;COPTIC SMALL LETTER DEI;Ll;0;L;;;;;N;GREEK SMALL LETTER DEI;;03EE;;03EE +03F0;GREEK KAPPA SYMBOL;Ll;0;L;<compat> 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A +03F1;GREEK RHO SYMBOL;Ll;0;L;<compat> 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1 +03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L;<compat> 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03F9;;03F9 +03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;;; +03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8; +03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L;<compat> 03B5;;;;N;;;0395;;0395 +03F6;GREEK REVERSED LUNATE EPSILON SYMBOL;Sm;0;ON;;;;;N;;;;; +03F7;GREEK CAPITAL LETTER SHO;Lu;0;L;;;;;N;;;;03F8; +03F8;GREEK SMALL LETTER SHO;Ll;0;L;;;;;N;;;03F7;;03F7 +03F9;GREEK CAPITAL LUNATE SIGMA SYMBOL;Lu;0;L;<compat> 03A3;;;;N;;;;03F2; +03FA;GREEK CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;03FB; +03FB;GREEK SMALL LETTER SAN;Ll;0;L;;;;;N;;;03FA;;03FA +0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450; +0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451; +0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;Serbocroatian;;0452; +0403;CYRILLIC CAPITAL LETTER GJE;Lu;0;L;0413 0301;;;;N;;;;0453; +0404;CYRILLIC CAPITAL LETTER UKRAINIAN IE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER E;;;0454; +0405;CYRILLIC CAPITAL LETTER DZE;Lu;0;L;;;;;N;;;;0455; +0406;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER I;;;0456; +0407;CYRILLIC CAPITAL LETTER YI;Lu;0;L;0406 0308;;;;N;;Ukrainian;;0457; +0408;CYRILLIC CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;0458; +0409;CYRILLIC CAPITAL LETTER LJE;Lu;0;L;;;;;N;;;;0459; +040A;CYRILLIC CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;045A; +040B;CYRILLIC CAPITAL LETTER TSHE;Lu;0;L;;;;;N;;Serbocroatian;;045B; +040C;CYRILLIC CAPITAL LETTER KJE;Lu;0;L;041A 0301;;;;N;;;;045C; +040D;CYRILLIC CAPITAL LETTER I WITH GRAVE;Lu;0;L;0418 0300;;;;N;;;;045D; +040E;CYRILLIC CAPITAL LETTER SHORT U;Lu;0;L;0423 0306;;;;N;;Byelorussian;;045E; +040F;CYRILLIC CAPITAL LETTER DZHE;Lu;0;L;;;;;N;;;;045F; +0410;CYRILLIC CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0430; +0411;CYRILLIC CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;0431; +0412;CYRILLIC CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;0432; +0413;CYRILLIC CAPITAL LETTER GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE;;;0433; +0414;CYRILLIC CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;0434; +0415;CYRILLIC CAPITAL LETTER IE;Lu;0;L;;;;;N;;;;0435; +0416;CYRILLIC CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;0436; +0417;CYRILLIC CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;0437; +0418;CYRILLIC CAPITAL LETTER I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER II;;;0438; +0419;CYRILLIC CAPITAL LETTER SHORT I;Lu;0;L;0418 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT II;;;0439; +041A;CYRILLIC CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;043A; +041B;CYRILLIC CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;043B; +041C;CYRILLIC CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;043C; +041D;CYRILLIC CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;043D; +041E;CYRILLIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;043E; +041F;CYRILLIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;043F; +0420;CYRILLIC CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;0440; +0421;CYRILLIC CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;0441; +0422;CYRILLIC CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;0442; +0423;CYRILLIC CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0443; +0424;CYRILLIC CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;0444; +0425;CYRILLIC CAPITAL LETTER HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA;;;0445; +0426;CYRILLIC CAPITAL LETTER TSE;Lu;0;L;;;;;N;;;;0446; +0427;CYRILLIC CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;0447; +0428;CYRILLIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0448; +0429;CYRILLIC CAPITAL LETTER SHCHA;Lu;0;L;;;;;N;;;;0449; +042A;CYRILLIC CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;044A; +042B;CYRILLIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER YERI;;;044B; +042C;CYRILLIC CAPITAL LETTER SOFT SIGN;Lu;0;L;;;;;N;;;;044C; +042D;CYRILLIC CAPITAL LETTER E;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED E;;;044D; +042E;CYRILLIC CAPITAL LETTER YU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IU;;;044E; +042F;CYRILLIC CAPITAL LETTER YA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IA;;;044F; +0430;CYRILLIC SMALL LETTER A;Ll;0;L;;;;;N;;;0410;;0410 +0431;CYRILLIC SMALL LETTER BE;Ll;0;L;;;;;N;;;0411;;0411 +0432;CYRILLIC SMALL LETTER VE;Ll;0;L;;;;;N;;;0412;;0412 +0433;CYRILLIC SMALL LETTER GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE;;0413;;0413 +0434;CYRILLIC SMALL LETTER DE;Ll;0;L;;;;;N;;;0414;;0414 +0435;CYRILLIC SMALL LETTER IE;Ll;0;L;;;;;N;;;0415;;0415 +0436;CYRILLIC SMALL LETTER ZHE;Ll;0;L;;;;;N;;;0416;;0416 +0437;CYRILLIC SMALL LETTER ZE;Ll;0;L;;;;;N;;;0417;;0417 +0438;CYRILLIC SMALL LETTER I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER II;;0418;;0418 +0439;CYRILLIC SMALL LETTER SHORT I;Ll;0;L;0438 0306;;;;N;CYRILLIC SMALL LETTER SHORT II;;0419;;0419 +043A;CYRILLIC SMALL LETTER KA;Ll;0;L;;;;;N;;;041A;;041A +043B;CYRILLIC SMALL LETTER EL;Ll;0;L;;;;;N;;;041B;;041B +043C;CYRILLIC SMALL LETTER EM;Ll;0;L;;;;;N;;;041C;;041C +043D;CYRILLIC SMALL LETTER EN;Ll;0;L;;;;;N;;;041D;;041D +043E;CYRILLIC SMALL LETTER O;Ll;0;L;;;;;N;;;041E;;041E +043F;CYRILLIC SMALL LETTER PE;Ll;0;L;;;;;N;;;041F;;041F +0440;CYRILLIC SMALL LETTER ER;Ll;0;L;;;;;N;;;0420;;0420 +0441;CYRILLIC SMALL LETTER ES;Ll;0;L;;;;;N;;;0421;;0421 +0442;CYRILLIC SMALL LETTER TE;Ll;0;L;;;;;N;;;0422;;0422 +0443;CYRILLIC SMALL LETTER U;Ll;0;L;;;;;N;;;0423;;0423 +0444;CYRILLIC SMALL LETTER EF;Ll;0;L;;;;;N;;;0424;;0424 +0445;CYRILLIC SMALL LETTER HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA;;0425;;0425 +0446;CYRILLIC SMALL LETTER TSE;Ll;0;L;;;;;N;;;0426;;0426 +0447;CYRILLIC SMALL LETTER CHE;Ll;0;L;;;;;N;;;0427;;0427 +0448;CYRILLIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;0428;;0428 +0449;CYRILLIC SMALL LETTER SHCHA;Ll;0;L;;;;;N;;;0429;;0429 +044A;CYRILLIC SMALL LETTER HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A +044B;CYRILLIC SMALL LETTER YERU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER YERI;;042B;;042B +044C;CYRILLIC SMALL LETTER SOFT SIGN;Ll;0;L;;;;;N;;;042C;;042C +044D;CYRILLIC SMALL LETTER E;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED E;;042D;;042D +044E;CYRILLIC SMALL LETTER YU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IU;;042E;;042E +044F;CYRILLIC SMALL LETTER YA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IA;;042F;;042F +0450;CYRILLIC SMALL LETTER IE WITH GRAVE;Ll;0;L;0435 0300;;;;N;;;0400;;0400 +0451;CYRILLIC SMALL LETTER IO;Ll;0;L;0435 0308;;;;N;;;0401;;0401 +0452;CYRILLIC SMALL LETTER DJE;Ll;0;L;;;;;N;;Serbocroatian;0402;;0402 +0453;CYRILLIC SMALL LETTER GJE;Ll;0;L;0433 0301;;;;N;;;0403;;0403 +0454;CYRILLIC SMALL LETTER UKRAINIAN IE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER E;;0404;;0404 +0455;CYRILLIC SMALL LETTER DZE;Ll;0;L;;;;;N;;;0405;;0405 +0456;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER I;;0406;;0406 +0457;CYRILLIC SMALL LETTER YI;Ll;0;L;0456 0308;;;;N;;Ukrainian;0407;;0407 +0458;CYRILLIC SMALL LETTER JE;Ll;0;L;;;;;N;;;0408;;0408 +0459;CYRILLIC SMALL LETTER LJE;Ll;0;L;;;;;N;;;0409;;0409 +045A;CYRILLIC SMALL LETTER NJE;Ll;0;L;;;;;N;;;040A;;040A +045B;CYRILLIC SMALL LETTER TSHE;Ll;0;L;;;;;N;;Serbocroatian;040B;;040B +045C;CYRILLIC SMALL LETTER KJE;Ll;0;L;043A 0301;;;;N;;;040C;;040C +045D;CYRILLIC SMALL LETTER I WITH GRAVE;Ll;0;L;0438 0300;;;;N;;;040D;;040D +045E;CYRILLIC SMALL LETTER SHORT U;Ll;0;L;0443 0306;;;;N;;Byelorussian;040E;;040E +045F;CYRILLIC SMALL LETTER DZHE;Ll;0;L;;;;;N;;;040F;;040F +0460;CYRILLIC CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;0461; +0461;CYRILLIC SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;0460;;0460 +0462;CYRILLIC CAPITAL LETTER YAT;Lu;0;L;;;;;N;;;;0463; +0463;CYRILLIC SMALL LETTER YAT;Ll;0;L;;;;;N;;;0462;;0462 +0464;CYRILLIC CAPITAL LETTER IOTIFIED E;Lu;0;L;;;;;N;;;;0465; +0465;CYRILLIC SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;0464;;0464 +0466;CYRILLIC CAPITAL LETTER LITTLE YUS;Lu;0;L;;;;;N;;;;0467; +0467;CYRILLIC SMALL LETTER LITTLE YUS;Ll;0;L;;;;;N;;;0466;;0466 +0468;CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS;Lu;0;L;;;;;N;;;;0469; +0469;CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS;Ll;0;L;;;;;N;;;0468;;0468 +046A;CYRILLIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;046B; +046B;CYRILLIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;046A;;046A +046C;CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS;Lu;0;L;;;;;N;;;;046D; +046D;CYRILLIC SMALL LETTER IOTIFIED BIG YUS;Ll;0;L;;;;;N;;;046C;;046C +046E;CYRILLIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;046F; +046F;CYRILLIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;046E;;046E +0470;CYRILLIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;0471; +0471;CYRILLIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;0470;;0470 +0472;CYRILLIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;0473; +0473;CYRILLIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;0472;;0472 +0474;CYRILLIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;0475; +0475;CYRILLIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;0474;;0474 +0476;CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Lu;0;L;0474 030F;;;;N;CYRILLIC CAPITAL LETTER IZHITSA DOUBLE GRAVE;;;0477; +0477;CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Ll;0;L;0475 030F;;;;N;CYRILLIC SMALL LETTER IZHITSA DOUBLE GRAVE;;0476;;0476 +0478;CYRILLIC CAPITAL LETTER UK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER UK DIGRAPH;;;0479; +0479;CYRILLIC SMALL LETTER UK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER UK DIGRAPH;;0478;;0478 +047A;CYRILLIC CAPITAL LETTER ROUND OMEGA;Lu;0;L;;;;;N;;;;047B; +047B;CYRILLIC SMALL LETTER ROUND OMEGA;Ll;0;L;;;;;N;;;047A;;047A +047C;CYRILLIC CAPITAL LETTER OMEGA WITH TITLO;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER OMEGA TITLO;;;047D; +047D;CYRILLIC SMALL LETTER OMEGA WITH TITLO;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER OMEGA TITLO;;047C;;047C +047E;CYRILLIC CAPITAL LETTER OT;Lu;0;L;;;;;N;;;;047F; +047F;CYRILLIC SMALL LETTER OT;Ll;0;L;;;;;N;;;047E;;047E +0480;CYRILLIC CAPITAL LETTER KOPPA;Lu;0;L;;;;;N;;;;0481; +0481;CYRILLIC SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;0480;;0480 +0482;CYRILLIC THOUSANDS SIGN;So;0;L;;;;;N;;;;; +0483;COMBINING CYRILLIC TITLO;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING TITLO;;;; +0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;; +0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;; +0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;; +0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;; +0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; +048A;CYRILLIC CAPITAL LETTER SHORT I WITH TAIL;Lu;0;L;;;;;N;;;;048B; +048B;CYRILLIC SMALL LETTER SHORT I WITH TAIL;Ll;0;L;;;;;N;;;048A;;048A +048C;CYRILLIC CAPITAL LETTER SEMISOFT SIGN;Lu;0;L;;;;;N;;;;048D; +048D;CYRILLIC SMALL LETTER SEMISOFT SIGN;Ll;0;L;;;;;N;;;048C;;048C +048E;CYRILLIC CAPITAL LETTER ER WITH TICK;Lu;0;L;;;;;N;;;;048F; +048F;CYRILLIC SMALL LETTER ER WITH TICK;Ll;0;L;;;;;N;;;048E;;048E +0490;CYRILLIC CAPITAL LETTER GHE WITH UPTURN;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE WITH UPTURN;;;0491; +0491;CYRILLIC SMALL LETTER GHE WITH UPTURN;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE WITH UPTURN;;0490;;0490 +0492;CYRILLIC CAPITAL LETTER GHE WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE BAR;;;0493; +0493;CYRILLIC SMALL LETTER GHE WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE BAR;;0492;;0492 +0494;CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE HOOK;;;0495; +0495;CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE HOOK;;0494;;0494 +0496;CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZHE WITH RIGHT DESCENDER;;;0497; +0497;CYRILLIC SMALL LETTER ZHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZHE WITH RIGHT DESCENDER;;0496;;0496 +0498;CYRILLIC CAPITAL LETTER ZE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZE CEDILLA;;;0499; +0499;CYRILLIC SMALL LETTER ZE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZE CEDILLA;;0498;;0498 +049A;CYRILLIC CAPITAL LETTER KA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA WITH RIGHT DESCENDER;;;049B; +049B;CYRILLIC SMALL LETTER KA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA WITH RIGHT DESCENDER;;049A;;049A +049C;CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA VERTICAL BAR;;;049D; +049D;CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA VERTICAL BAR;;049C;;049C +049E;CYRILLIC CAPITAL LETTER KA WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA BAR;;;049F; +049F;CYRILLIC SMALL LETTER KA WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA BAR;;049E;;049E +04A0;CYRILLIC CAPITAL LETTER BASHKIR KA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED GE KA;;;04A1; +04A1;CYRILLIC SMALL LETTER BASHKIR KA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED GE KA;;04A0;;04A0 +04A2;CYRILLIC CAPITAL LETTER EN WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN WITH RIGHT DESCENDER;;;04A3; +04A3;CYRILLIC SMALL LETTER EN WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN WITH RIGHT DESCENDER;;04A2;;04A2 +04A4;CYRILLIC CAPITAL LIGATURE EN GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN GE;;;04A5; +04A5;CYRILLIC SMALL LIGATURE EN GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN GE;;04A4;;04A4 +04A6;CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER PE HOOK;Abkhasian;;04A7; +04A7;CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER PE HOOK;Abkhasian;04A6;;04A6 +04A8;CYRILLIC CAPITAL LETTER ABKHASIAN HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER O HOOK;;;04A9; +04A9;CYRILLIC SMALL LETTER ABKHASIAN HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER O HOOK;;04A8;;04A8 +04AA;CYRILLIC CAPITAL LETTER ES WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ES CEDILLA;;;04AB; +04AB;CYRILLIC SMALL LETTER ES WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ES CEDILLA;;04AA;;04AA +04AC;CYRILLIC CAPITAL LETTER TE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE WITH RIGHT DESCENDER;;;04AD; +04AD;CYRILLIC SMALL LETTER TE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE WITH RIGHT DESCENDER;;04AC;;04AC +04AE;CYRILLIC CAPITAL LETTER STRAIGHT U;Lu;0;L;;;;;N;;;;04AF; +04AF;CYRILLIC SMALL LETTER STRAIGHT U;Ll;0;L;;;;;N;;;04AE;;04AE +04B0;CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER STRAIGHT U BAR;;;04B1; +04B1;CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER STRAIGHT U BAR;;04B0;;04B0 +04B2;CYRILLIC CAPITAL LETTER HA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA WITH RIGHT DESCENDER;;;04B3; +04B3;CYRILLIC SMALL LETTER HA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA WITH RIGHT DESCENDER;;04B2;;04B2 +04B4;CYRILLIC CAPITAL LIGATURE TE TSE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE TSE;Abkhasian;;04B5; +04B5;CYRILLIC SMALL LIGATURE TE TSE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE TSE;Abkhasian;04B4;;04B4 +04B6;CYRILLIC CAPITAL LETTER CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH RIGHT DESCENDER;;;04B7; +04B7;CYRILLIC SMALL LETTER CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH RIGHT DESCENDER;;04B6;;04B6 +04B8;CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE VERTICAL BAR;;;04B9; +04B9;CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE VERTICAL BAR;;04B8;;04B8 +04BA;CYRILLIC CAPITAL LETTER SHHA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER H;;;04BB; +04BB;CYRILLIC SMALL LETTER SHHA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER H;;04BA;;04BA +04BC;CYRILLIC CAPITAL LETTER ABKHASIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK;;;04BD; +04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC +04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF; +04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE +04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;; +04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2; +04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1 +04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4; +04C4;CYRILLIC SMALL LETTER KA WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA HOOK;;04C3;;04C3 +04C5;CYRILLIC CAPITAL LETTER EL WITH TAIL;Lu;0;L;;;;;N;;;;04C6; +04C6;CYRILLIC SMALL LETTER EL WITH TAIL;Ll;0;L;;;;;N;;;04C5;;04C5 +04C7;CYRILLIC CAPITAL LETTER EN WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN HOOK;;;04C8; +04C8;CYRILLIC SMALL LETTER EN WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN HOOK;;04C7;;04C7 +04C9;CYRILLIC CAPITAL LETTER EN WITH TAIL;Lu;0;L;;;;;N;;;;04CA; +04CA;CYRILLIC SMALL LETTER EN WITH TAIL;Ll;0;L;;;;;N;;;04C9;;04C9 +04CB;CYRILLIC CAPITAL LETTER KHAKASSIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH LEFT DESCENDER;;;04CC; +04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB +04CD;CYRILLIC CAPITAL LETTER EM WITH TAIL;Lu;0;L;;;;;N;;;;04CE; +04CE;CYRILLIC SMALL LETTER EM WITH TAIL;Ll;0;L;;;;;N;;;04CD;;04CD +04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1; +04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0 +04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3; +04D3;CYRILLIC SMALL LETTER A WITH DIAERESIS;Ll;0;L;0430 0308;;;;N;;;04D2;;04D2 +04D4;CYRILLIC CAPITAL LIGATURE A IE;Lu;0;L;;;;;N;;;;04D5; +04D5;CYRILLIC SMALL LIGATURE A IE;Ll;0;L;;;;;N;;;04D4;;04D4 +04D6;CYRILLIC CAPITAL LETTER IE WITH BREVE;Lu;0;L;0415 0306;;;;N;;;;04D7; +04D7;CYRILLIC SMALL LETTER IE WITH BREVE;Ll;0;L;0435 0306;;;;N;;;04D6;;04D6 +04D8;CYRILLIC CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;04D9; +04D9;CYRILLIC SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;04D8;;04D8 +04DA;CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS;Lu;0;L;04D8 0308;;;;N;;;;04DB; +04DB;CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS;Ll;0;L;04D9 0308;;;;N;;;04DA;;04DA +04DC;CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS;Lu;0;L;0416 0308;;;;N;;;;04DD; +04DD;CYRILLIC SMALL LETTER ZHE WITH DIAERESIS;Ll;0;L;0436 0308;;;;N;;;04DC;;04DC +04DE;CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS;Lu;0;L;0417 0308;;;;N;;;;04DF; +04DF;CYRILLIC SMALL LETTER ZE WITH DIAERESIS;Ll;0;L;0437 0308;;;;N;;;04DE;;04DE +04E0;CYRILLIC CAPITAL LETTER ABKHASIAN DZE;Lu;0;L;;;;;N;;;;04E1; +04E1;CYRILLIC SMALL LETTER ABKHASIAN DZE;Ll;0;L;;;;;N;;;04E0;;04E0 +04E2;CYRILLIC CAPITAL LETTER I WITH MACRON;Lu;0;L;0418 0304;;;;N;;;;04E3; +04E3;CYRILLIC SMALL LETTER I WITH MACRON;Ll;0;L;0438 0304;;;;N;;;04E2;;04E2 +04E4;CYRILLIC CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0418 0308;;;;N;;;;04E5; +04E5;CYRILLIC SMALL LETTER I WITH DIAERESIS;Ll;0;L;0438 0308;;;;N;;;04E4;;04E4 +04E6;CYRILLIC CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;041E 0308;;;;N;;;;04E7; +04E7;CYRILLIC SMALL LETTER O WITH DIAERESIS;Ll;0;L;043E 0308;;;;N;;;04E6;;04E6 +04E8;CYRILLIC CAPITAL LETTER BARRED O;Lu;0;L;;;;;N;;;;04E9; +04E9;CYRILLIC SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;04E8;;04E8 +04EA;CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS;Lu;0;L;04E8 0308;;;;N;;;;04EB; +04EB;CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS;Ll;0;L;04E9 0308;;;;N;;;04EA;;04EA +04EC;CYRILLIC CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;042D 0308;;;;N;;;;04ED; +04ED;CYRILLIC SMALL LETTER E WITH DIAERESIS;Ll;0;L;044D 0308;;;;N;;;04EC;;04EC +04EE;CYRILLIC CAPITAL LETTER U WITH MACRON;Lu;0;L;0423 0304;;;;N;;;;04EF; +04EF;CYRILLIC SMALL LETTER U WITH MACRON;Ll;0;L;0443 0304;;;;N;;;04EE;;04EE +04F0;CYRILLIC CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0423 0308;;;;N;;;;04F1; +04F1;CYRILLIC SMALL LETTER U WITH DIAERESIS;Ll;0;L;0443 0308;;;;N;;;04F0;;04F0 +04F2;CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0423 030B;;;;N;;;;04F3; +04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2 +04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5; +04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4 +04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9; +04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8 +0500;CYRILLIC CAPITAL LETTER KOMI DE;Lu;0;L;;;;;N;;;;0501; +0501;CYRILLIC SMALL LETTER KOMI DE;Ll;0;L;;;;;N;;;0500;;0500 +0502;CYRILLIC CAPITAL LETTER KOMI DJE;Lu;0;L;;;;;N;;;;0503; +0503;CYRILLIC SMALL LETTER KOMI DJE;Ll;0;L;;;;;N;;;0502;;0502 +0504;CYRILLIC CAPITAL LETTER KOMI ZJE;Lu;0;L;;;;;N;;;;0505; +0505;CYRILLIC SMALL LETTER KOMI ZJE;Ll;0;L;;;;;N;;;0504;;0504 +0506;CYRILLIC CAPITAL LETTER KOMI DZJE;Lu;0;L;;;;;N;;;;0507; +0507;CYRILLIC SMALL LETTER KOMI DZJE;Ll;0;L;;;;;N;;;0506;;0506 +0508;CYRILLIC CAPITAL LETTER KOMI LJE;Lu;0;L;;;;;N;;;;0509; +0509;CYRILLIC SMALL LETTER KOMI LJE;Ll;0;L;;;;;N;;;0508;;0508 +050A;CYRILLIC CAPITAL LETTER KOMI NJE;Lu;0;L;;;;;N;;;;050B; +050B;CYRILLIC SMALL LETTER KOMI NJE;Ll;0;L;;;;;N;;;050A;;050A +050C;CYRILLIC CAPITAL LETTER KOMI SJE;Lu;0;L;;;;;N;;;;050D; +050D;CYRILLIC SMALL LETTER KOMI SJE;Ll;0;L;;;;;N;;;050C;;050C +050E;CYRILLIC CAPITAL LETTER KOMI TJE;Lu;0;L;;;;;N;;;;050F; +050F;CYRILLIC SMALL LETTER KOMI TJE;Ll;0;L;;;;;N;;;050E;;050E +0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561; +0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562; +0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563; +0534;ARMENIAN CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;0564; +0535;ARMENIAN CAPITAL LETTER ECH;Lu;0;L;;;;;N;;;;0565; +0536;ARMENIAN CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;0566; +0537;ARMENIAN CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;0567; +0538;ARMENIAN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;0568; +0539;ARMENIAN CAPITAL LETTER TO;Lu;0;L;;;;;N;;;;0569; +053A;ARMENIAN CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;056A; +053B;ARMENIAN CAPITAL LETTER INI;Lu;0;L;;;;;N;;;;056B; +053C;ARMENIAN CAPITAL LETTER LIWN;Lu;0;L;;;;;N;;;;056C; +053D;ARMENIAN CAPITAL LETTER XEH;Lu;0;L;;;;;N;;;;056D; +053E;ARMENIAN CAPITAL LETTER CA;Lu;0;L;;;;;N;;;;056E; +053F;ARMENIAN CAPITAL LETTER KEN;Lu;0;L;;;;;N;;;;056F; +0540;ARMENIAN CAPITAL LETTER HO;Lu;0;L;;;;;N;;;;0570; +0541;ARMENIAN CAPITAL LETTER JA;Lu;0;L;;;;;N;;;;0571; +0542;ARMENIAN CAPITAL LETTER GHAD;Lu;0;L;;;;;N;ARMENIAN CAPITAL LETTER LAD;;;0572; +0543;ARMENIAN CAPITAL LETTER CHEH;Lu;0;L;;;;;N;;;;0573; +0544;ARMENIAN CAPITAL LETTER MEN;Lu;0;L;;;;;N;;;;0574; +0545;ARMENIAN CAPITAL LETTER YI;Lu;0;L;;;;;N;;;;0575; +0546;ARMENIAN CAPITAL LETTER NOW;Lu;0;L;;;;;N;;;;0576; +0547;ARMENIAN CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0577; +0548;ARMENIAN CAPITAL LETTER VO;Lu;0;L;;;;;N;;;;0578; +0549;ARMENIAN CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;0579; +054A;ARMENIAN CAPITAL LETTER PEH;Lu;0;L;;;;;N;;;;057A; +054B;ARMENIAN CAPITAL LETTER JHEH;Lu;0;L;;;;;N;;;;057B; +054C;ARMENIAN CAPITAL LETTER RA;Lu;0;L;;;;;N;;;;057C; +054D;ARMENIAN CAPITAL LETTER SEH;Lu;0;L;;;;;N;;;;057D; +054E;ARMENIAN CAPITAL LETTER VEW;Lu;0;L;;;;;N;;;;057E; +054F;ARMENIAN CAPITAL LETTER TIWN;Lu;0;L;;;;;N;;;;057F; +0550;ARMENIAN CAPITAL LETTER REH;Lu;0;L;;;;;N;;;;0580; +0551;ARMENIAN CAPITAL LETTER CO;Lu;0;L;;;;;N;;;;0581; +0552;ARMENIAN CAPITAL LETTER YIWN;Lu;0;L;;;;;N;;;;0582; +0553;ARMENIAN CAPITAL LETTER PIWR;Lu;0;L;;;;;N;;;;0583; +0554;ARMENIAN CAPITAL LETTER KEH;Lu;0;L;;;;;N;;;;0584; +0555;ARMENIAN CAPITAL LETTER OH;Lu;0;L;;;;;N;;;;0585; +0556;ARMENIAN CAPITAL LETTER FEH;Lu;0;L;;;;;N;;;;0586; +0559;ARMENIAN MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;; +055A;ARMENIAN APOSTROPHE;Po;0;L;;;;;N;ARMENIAN MODIFIER LETTER RIGHT HALF RING;;;; +055B;ARMENIAN EMPHASIS MARK;Po;0;L;;;;;N;;;;; +055C;ARMENIAN EXCLAMATION MARK;Po;0;L;;;;;N;;;;; +055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;; +055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;; +055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;; +0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531 +0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532 +0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533 +0564;ARMENIAN SMALL LETTER DA;Ll;0;L;;;;;N;;;0534;;0534 +0565;ARMENIAN SMALL LETTER ECH;Ll;0;L;;;;;N;;;0535;;0535 +0566;ARMENIAN SMALL LETTER ZA;Ll;0;L;;;;;N;;;0536;;0536 +0567;ARMENIAN SMALL LETTER EH;Ll;0;L;;;;;N;;;0537;;0537 +0568;ARMENIAN SMALL LETTER ET;Ll;0;L;;;;;N;;;0538;;0538 +0569;ARMENIAN SMALL LETTER TO;Ll;0;L;;;;;N;;;0539;;0539 +056A;ARMENIAN SMALL LETTER ZHE;Ll;0;L;;;;;N;;;053A;;053A +056B;ARMENIAN SMALL LETTER INI;Ll;0;L;;;;;N;;;053B;;053B +056C;ARMENIAN SMALL LETTER LIWN;Ll;0;L;;;;;N;;;053C;;053C +056D;ARMENIAN SMALL LETTER XEH;Ll;0;L;;;;;N;;;053D;;053D +056E;ARMENIAN SMALL LETTER CA;Ll;0;L;;;;;N;;;053E;;053E +056F;ARMENIAN SMALL LETTER KEN;Ll;0;L;;;;;N;;;053F;;053F +0570;ARMENIAN SMALL LETTER HO;Ll;0;L;;;;;N;;;0540;;0540 +0571;ARMENIAN SMALL LETTER JA;Ll;0;L;;;;;N;;;0541;;0541 +0572;ARMENIAN SMALL LETTER GHAD;Ll;0;L;;;;;N;ARMENIAN SMALL LETTER LAD;;0542;;0542 +0573;ARMENIAN SMALL LETTER CHEH;Ll;0;L;;;;;N;;;0543;;0543 +0574;ARMENIAN SMALL LETTER MEN;Ll;0;L;;;;;N;;;0544;;0544 +0575;ARMENIAN SMALL LETTER YI;Ll;0;L;;;;;N;;;0545;;0545 +0576;ARMENIAN SMALL LETTER NOW;Ll;0;L;;;;;N;;;0546;;0546 +0577;ARMENIAN SMALL LETTER SHA;Ll;0;L;;;;;N;;;0547;;0547 +0578;ARMENIAN SMALL LETTER VO;Ll;0;L;;;;;N;;;0548;;0548 +0579;ARMENIAN SMALL LETTER CHA;Ll;0;L;;;;;N;;;0549;;0549 +057A;ARMENIAN SMALL LETTER PEH;Ll;0;L;;;;;N;;;054A;;054A +057B;ARMENIAN SMALL LETTER JHEH;Ll;0;L;;;;;N;;;054B;;054B +057C;ARMENIAN SMALL LETTER RA;Ll;0;L;;;;;N;;;054C;;054C +057D;ARMENIAN SMALL LETTER SEH;Ll;0;L;;;;;N;;;054D;;054D +057E;ARMENIAN SMALL LETTER VEW;Ll;0;L;;;;;N;;;054E;;054E +057F;ARMENIAN SMALL LETTER TIWN;Ll;0;L;;;;;N;;;054F;;054F +0580;ARMENIAN SMALL LETTER REH;Ll;0;L;;;;;N;;;0550;;0550 +0581;ARMENIAN SMALL LETTER CO;Ll;0;L;;;;;N;;;0551;;0551 +0582;ARMENIAN SMALL LETTER YIWN;Ll;0;L;;;;;N;;;0552;;0552 +0583;ARMENIAN SMALL LETTER PIWR;Ll;0;L;;;;;N;;;0553;;0553 +0584;ARMENIAN SMALL LETTER KEH;Ll;0;L;;;;;N;;;0554;;0554 +0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555 +0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556 +0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;; +0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;; +058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;; +0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;; +0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;; +0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;; +0594;HEBREW ACCENT ZAQEF QATAN;Mn;230;NSM;;;;;N;;;;; +0595;HEBREW ACCENT ZAQEF GADOL;Mn;230;NSM;;;;;N;;;;; +0596;HEBREW ACCENT TIPEHA;Mn;220;NSM;;;;;N;;*;;; +0597;HEBREW ACCENT REVIA;Mn;230;NSM;;;;;N;;;;; +0598;HEBREW ACCENT ZARQA;Mn;230;NSM;;;;;N;;*;;; +0599;HEBREW ACCENT PASHTA;Mn;230;NSM;;;;;N;;;;; +059A;HEBREW ACCENT YETIV;Mn;222;NSM;;;;;N;;;;; +059B;HEBREW ACCENT TEVIR;Mn;220;NSM;;;;;N;;;;; +059C;HEBREW ACCENT GERESH;Mn;230;NSM;;;;;N;;;;; +059D;HEBREW ACCENT GERESH MUQDAM;Mn;230;NSM;;;;;N;;;;; +059E;HEBREW ACCENT GERSHAYIM;Mn;230;NSM;;;;;N;;;;; +059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;; +05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;; +05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;; +05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;; +05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;; +05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;*;;; +05A6;HEBREW ACCENT MERKHA KEFULA;Mn;220;NSM;;;;;N;;;;; +05A7;HEBREW ACCENT DARGA;Mn;220;NSM;;;;;N;;;;; +05A8;HEBREW ACCENT QADMA;Mn;230;NSM;;;;;N;;*;;; +05A9;HEBREW ACCENT TELISHA QETANA;Mn;230;NSM;;;;;N;;;;; +05AA;HEBREW ACCENT YERAH BEN YOMO;Mn;220;NSM;;;;;N;;*;;; +05AB;HEBREW ACCENT OLE;Mn;230;NSM;;;;;N;;;;; +05AC;HEBREW ACCENT ILUY;Mn;230;NSM;;;;;N;;;;; +05AD;HEBREW ACCENT DEHI;Mn;222;NSM;;;;;N;;;;; +05AE;HEBREW ACCENT ZINOR;Mn;228;NSM;;;;;N;;;;; +05AF;HEBREW MARK MASORA CIRCLE;Mn;230;NSM;;;;;N;;;;; +05B0;HEBREW POINT SHEVA;Mn;10;NSM;;;;;N;;;;; +05B1;HEBREW POINT HATAF SEGOL;Mn;11;NSM;;;;;N;;;;; +05B2;HEBREW POINT HATAF PATAH;Mn;12;NSM;;;;;N;;;;; +05B3;HEBREW POINT HATAF QAMATS;Mn;13;NSM;;;;;N;;;;; +05B4;HEBREW POINT HIRIQ;Mn;14;NSM;;;;;N;;;;; +05B5;HEBREW POINT TSERE;Mn;15;NSM;;;;;N;;;;; +05B6;HEBREW POINT SEGOL;Mn;16;NSM;;;;;N;;;;; +05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;; +05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;; +05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;; +05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;; +05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;or shuruq;;; +05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;*;;; +05BE;HEBREW PUNCTUATION MAQAF;Po;0;R;;;;;N;;;;; +05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;; +05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;*;;; +05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;; +05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;; +05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;*;;; +05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;; +05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;; +05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;; +05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;; +05D3;HEBREW LETTER DALET;Lo;0;R;;;;;N;;;;; +05D4;HEBREW LETTER HE;Lo;0;R;;;;;N;;;;; +05D5;HEBREW LETTER VAV;Lo;0;R;;;;;N;;;;; +05D6;HEBREW LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +05D7;HEBREW LETTER HET;Lo;0;R;;;;;N;;;;; +05D8;HEBREW LETTER TET;Lo;0;R;;;;;N;;;;; +05D9;HEBREW LETTER YOD;Lo;0;R;;;;;N;;;;; +05DA;HEBREW LETTER FINAL KAF;Lo;0;R;;;;;N;;;;; +05DB;HEBREW LETTER KAF;Lo;0;R;;;;;N;;;;; +05DC;HEBREW LETTER LAMED;Lo;0;R;;;;;N;;;;; +05DD;HEBREW LETTER FINAL MEM;Lo;0;R;;;;;N;;;;; +05DE;HEBREW LETTER MEM;Lo;0;R;;;;;N;;;;; +05DF;HEBREW LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; +05E0;HEBREW LETTER NUN;Lo;0;R;;;;;N;;;;; +05E1;HEBREW LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +05E2;HEBREW LETTER AYIN;Lo;0;R;;;;;N;;;;; +05E3;HEBREW LETTER FINAL PE;Lo;0;R;;;;;N;;;;; +05E4;HEBREW LETTER PE;Lo;0;R;;;;;N;;;;; +05E5;HEBREW LETTER FINAL TSADI;Lo;0;R;;;;;N;;;;; +05E6;HEBREW LETTER TSADI;Lo;0;R;;;;;N;;;;; +05E7;HEBREW LETTER QOF;Lo;0;R;;;;;N;;;;; +05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;; +05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;; +05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;; +05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;; +05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;; +05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;; +05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;; +05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;; +0600;ARABIC NUMBER SIGN;Cf;0;AL;;;;;N;;;;; +0601;ARABIC SIGN SANAH;Cf;0;AL;;;;;N;;;;; +0602;ARABIC FOOTNOTE MARKER;Cf;0;AL;;;;;N;;;;; +0603;ARABIC SIGN SAFHA;Cf;0;AL;;;;;N;;;;; +060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;; +060D;ARABIC DATE SEPARATOR;Po;0;AL;;;;;N;;;;; +060E;ARABIC POETIC VERSE SIGN;So;0;ON;;;;;N;;;;; +060F;ARABIC SIGN MISRA;So;0;ON;;;;;N;;;;; +0610;ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM;Mn;230;NSM;;;;;N;;;;; +0611;ARABIC SIGN ALAYHE ASSALLAM;Mn;230;NSM;;;;;N;;;;; +0612;ARABIC SIGN RAHMATULLAH ALAYHE;Mn;230;NSM;;;;;N;;;;; +0613;ARABIC SIGN RADI ALLAHOU ANHU;Mn;230;NSM;;;;;N;;;;; +0614;ARABIC SIGN TAKHALLUS;Mn;230;NSM;;;;;N;;;;; +0615;ARABIC SMALL HIGH TAH ;Mn;230;NSM;;;;;N;;;;; +061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;; +061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;; +0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;; +0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;; +0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;; +0624;ARABIC LETTER WAW WITH HAMZA ABOVE;Lo;0;AL;0648 0654;;;;N;ARABIC LETTER HAMZAH ON WAW;;;; +0625;ARABIC LETTER ALEF WITH HAMZA BELOW;Lo;0;AL;0627 0655;;;;N;ARABIC LETTER HAMZAH UNDER ALEF;;;; +0626;ARABIC LETTER YEH WITH HAMZA ABOVE;Lo;0;AL;064A 0654;;;;N;ARABIC LETTER HAMZAH ON YA;;;; +0627;ARABIC LETTER ALEF;Lo;0;AL;;;;;N;;;;; +0628;ARABIC LETTER BEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA;;;; +0629;ARABIC LETTER TEH MARBUTA;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH;;;; +062A;ARABIC LETTER TEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA;;;; +062B;ARABIC LETTER THEH;Lo;0;AL;;;;;N;ARABIC LETTER THAA;;;; +062C;ARABIC LETTER JEEM;Lo;0;AL;;;;;N;;;;; +062D;ARABIC LETTER HAH;Lo;0;AL;;;;;N;ARABIC LETTER HAA;;;; +062E;ARABIC LETTER KHAH;Lo;0;AL;;;;;N;ARABIC LETTER KHAA;;;; +062F;ARABIC LETTER DAL;Lo;0;AL;;;;;N;;;;; +0630;ARABIC LETTER THAL;Lo;0;AL;;;;;N;;;;; +0631;ARABIC LETTER REH;Lo;0;AL;;;;;N;ARABIC LETTER RA;;;; +0632;ARABIC LETTER ZAIN;Lo;0;AL;;;;;N;;;;; +0633;ARABIC LETTER SEEN;Lo;0;AL;;;;;N;;;;; +0634;ARABIC LETTER SHEEN;Lo;0;AL;;;;;N;;;;; +0635;ARABIC LETTER SAD;Lo;0;AL;;;;;N;;;;; +0636;ARABIC LETTER DAD;Lo;0;AL;;;;;N;;;;; +0637;ARABIC LETTER TAH;Lo;0;AL;;;;;N;;;;; +0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;; +0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;; +063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;; +0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;; +0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;; +0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;; +0643;ARABIC LETTER KAF;Lo;0;AL;;;;;N;ARABIC LETTER CAF;;;; +0644;ARABIC LETTER LAM;Lo;0;AL;;;;;N;;;;; +0645;ARABIC LETTER MEEM;Lo;0;AL;;;;;N;;;;; +0646;ARABIC LETTER NOON;Lo;0;AL;;;;;N;;;;; +0647;ARABIC LETTER HEH;Lo;0;AL;;;;;N;ARABIC LETTER HA;;;; +0648;ARABIC LETTER WAW;Lo;0;AL;;;;;N;;;;; +0649;ARABIC LETTER ALEF MAKSURA;Lo;0;AL;;;;;N;ARABIC LETTER ALEF MAQSURAH;;;; +064A;ARABIC LETTER YEH;Lo;0;AL;;;;;N;ARABIC LETTER YA;;;; +064B;ARABIC FATHATAN;Mn;27;NSM;;;;;N;;;;; +064C;ARABIC DAMMATAN;Mn;28;NSM;;;;;N;;;;; +064D;ARABIC KASRATAN;Mn;29;NSM;;;;;N;;;;; +064E;ARABIC FATHA;Mn;30;NSM;;;;;N;ARABIC FATHAH;;;; +064F;ARABIC DAMMA;Mn;31;NSM;;;;;N;ARABIC DAMMAH;;;; +0650;ARABIC KASRA;Mn;32;NSM;;;;;N;ARABIC KASRAH;;;; +0651;ARABIC SHADDA;Mn;33;NSM;;;;;N;ARABIC SHADDAH;;;; +0652;ARABIC SUKUN;Mn;34;NSM;;;;;N;;;;; +0653;ARABIC MADDAH ABOVE;Mn;230;NSM;;;;;N;;;;; +0654;ARABIC HAMZA ABOVE;Mn;230;NSM;;;;;N;;;;; +0655;ARABIC HAMZA BELOW;Mn;220;NSM;;;;;N;;;;; +0656;ARABIC SUBSCRIPT ALEF;Mn;220;NSM;;;;;N;;;;; +0657;ARABIC INVERTED DAMMA;Mn;230;NSM;;;;;N;;;;; +0658;ARABIC MARK NOON GHUNNA;Mn;230;NSM;;;;;N;;;;; +0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; +0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; +0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; +0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; +0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; +0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; +0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; +0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; +0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; +0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; +066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;; +066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;; +066C;ARABIC THOUSANDS SEPARATOR;Po;0;AN;;;;;N;;;;; +066D;ARABIC FIVE POINTED STAR;Po;0;AL;;;;;N;;;;; +066E;ARABIC LETTER DOTLESS BEH;Lo;0;AL;;;;;N;;;;; +066F;ARABIC LETTER DOTLESS QAF;Lo;0;AL;;;;;N;;;;; +0670;ARABIC LETTER SUPERSCRIPT ALEF;Mn;35;NSM;;;;;N;ARABIC ALEF ABOVE;;;; +0671;ARABIC LETTER ALEF WASLA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAT WASL ON ALEF;;;; +0672;ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH ON ALEF;;;; +0673;ARABIC LETTER ALEF WITH WAVY HAMZA BELOW;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH UNDER ALEF;;;; +0674;ARABIC LETTER HIGH HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HIGH HAMZAH;;;; +0675;ARABIC LETTER HIGH HAMZA ALEF;Lo;0;AL;<compat> 0627 0674;;;;N;ARABIC LETTER HIGH HAMZAH ALEF;;;; +0676;ARABIC LETTER HIGH HAMZA WAW;Lo;0;AL;<compat> 0648 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW;;;; +0677;ARABIC LETTER U WITH HAMZA ABOVE;Lo;0;AL;<compat> 06C7 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW WITH DAMMAH;;;; +0678;ARABIC LETTER HIGH HAMZA YEH;Lo;0;AL;<compat> 064A 0674;;;;N;ARABIC LETTER HIGH HAMZAH YA;;;; +0679;ARABIC LETTER TTEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH SMALL TAH;;;; +067A;ARABIC LETTER TTEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH TWO DOTS VERTICAL ABOVE;;;; +067B;ARABIC LETTER BEEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH TWO DOTS VERTICAL BELOW;;;; +067C;ARABIC LETTER TEH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH RING;;;; +067D;ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS ABOVE DOWNWARD;;;; +067E;ARABIC LETTER PEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS BELOW;;;; +067F;ARABIC LETTER TEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH FOUR DOTS ABOVE;;;; +0680;ARABIC LETTER BEHEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH FOUR DOTS BELOW;;;; +0681;ARABIC LETTER HAH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH ON HAA;;;; +0682;ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH TWO DOTS VERTICAL ABOVE;;;; +0683;ARABIC LETTER NYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS;;;; +0684;ARABIC LETTER DYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS VERTICAL;;;; +0685;ARABIC LETTER HAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH THREE DOTS ABOVE;;;; +0686;ARABIC LETTER TCHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE THREE DOTS DOWNWARD;;;; +0687;ARABIC LETTER TCHEHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE FOUR DOTS;;;; +0688;ARABIC LETTER DDAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH SMALL TAH;;;; +0689;ARABIC LETTER DAL WITH RING;Lo;0;AL;;;;;N;;;;; +068A;ARABIC LETTER DAL WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +068B;ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;; +068C;ARABIC LETTER DAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS ABOVE;;;; +068D;ARABIC LETTER DDAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS BELOW;;;; +068E;ARABIC LETTER DUL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE;;;; +068F;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARD;;;; +0690;ARABIC LETTER DAL WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0691;ARABIC LETTER RREH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL TAH;;;; +0692;ARABIC LETTER REH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V;;;; +0693;ARABIC LETTER REH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH RING;;;; +0694;ARABIC LETTER REH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW;;;; +0695;ARABIC LETTER REH WITH SMALL V BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V BELOW;;;; +0696;ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW AND DOT ABOVE;;;; +0697;ARABIC LETTER REH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH TWO DOTS ABOVE;;;; +0698;ARABIC LETTER JEH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH THREE DOTS ABOVE;;;; +0699;ARABIC LETTER REH WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH FOUR DOTS ABOVE;;;; +069A;ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +069B;ARABIC LETTER SEEN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +069C;ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +069D;ARABIC LETTER SAD WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +069E;ARABIC LETTER SAD WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +069F;ARABIC LETTER TAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06A0;ARABIC LETTER AIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06A1;ARABIC LETTER DOTLESS FEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS FA;;;; +06A2;ARABIC LETTER FEH WITH DOT MOVED BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT MOVED BELOW;;;; +06A3;ARABIC LETTER FEH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT BELOW;;;; +06A4;ARABIC LETTER VEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS ABOVE;;;; +06A5;ARABIC LETTER FEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS BELOW;;;; +06A6;ARABIC LETTER PEHEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH FOUR DOTS ABOVE;;;; +06A7;ARABIC LETTER QAF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06A8;ARABIC LETTER QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06A9;ARABIC LETTER KEHEH;Lo;0;AL;;;;;N;ARABIC LETTER OPEN CAF;;;; +06AA;ARABIC LETTER SWASH KAF;Lo;0;AL;;;;;N;ARABIC LETTER SWASH CAF;;;; +06AB;ARABIC LETTER KAF WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH RING;;;; +06AC;ARABIC LETTER KAF WITH DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH DOT ABOVE;;;; +06AD;ARABIC LETTER NG;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS ABOVE;;;; +06AE;ARABIC LETTER KAF WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS BELOW;;;; +06AF;ARABIC LETTER GAF;Lo;0;AL;;;;;N;;*;;; +06B0;ARABIC LETTER GAF WITH RING;Lo;0;AL;;;;;N;;;;; +06B1;ARABIC LETTER NGOEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS ABOVE;;;; +06B2;ARABIC LETTER GAF WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +06B3;ARABIC LETTER GUEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS VERTICAL BELOW;;;; +06B4;ARABIC LETTER GAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06B5;ARABIC LETTER LAM WITH SMALL V;Lo;0;AL;;;;;N;;;;; +06B6;ARABIC LETTER LAM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06B7;ARABIC LETTER LAM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06B8;ARABIC LETTER LAM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +06B9;ARABIC LETTER NOON WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06BA;ARABIC LETTER NOON GHUNNA;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON;;;; +06BB;ARABIC LETTER RNOON;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON WITH SMALL TAH;;;; +06BC;ARABIC LETTER NOON WITH RING;Lo;0;AL;;;;;N;;;;; +06BD;ARABIC LETTER NOON WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06BE;ARABIC LETTER HEH DOACHASHMEE;Lo;0;AL;;;;;N;ARABIC LETTER KNOTTED HA;;;; +06BF;ARABIC LETTER TCHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06C0;ARABIC LETTER HEH WITH YEH ABOVE;Lo;0;AL;06D5 0654;;;;N;ARABIC LETTER HAMZAH ON HA;;;; +06C1;ARABIC LETTER HEH GOAL;Lo;0;AL;;;;;N;ARABIC LETTER HA GOAL;;;; +06C2;ARABIC LETTER HEH GOAL WITH HAMZA ABOVE;Lo;0;AL;06C1 0654;;;;N;ARABIC LETTER HAMZAH ON HA GOAL;;;; +06C3;ARABIC LETTER TEH MARBUTA GOAL;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH GOAL;;;; +06C4;ARABIC LETTER WAW WITH RING;Lo;0;AL;;;;;N;;;;; +06C5;ARABIC LETTER KIRGHIZ OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH BAR;;;; +06C6;ARABIC LETTER OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH SMALL V;;;; +06C7;ARABIC LETTER U;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH DAMMAH;;;; +06C8;ARABIC LETTER YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH ALEF ABOVE;;;; +06C9;ARABIC LETTER KIRGHIZ YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH INVERTED SMALL V;;;; +06CA;ARABIC LETTER WAW WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06CB;ARABIC LETTER VE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH THREE DOTS ABOVE;;;; +06CC;ARABIC LETTER FARSI YEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS YA;;;; +06CD;ARABIC LETTER YEH WITH TAIL;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TAIL;;;; +06CE;ARABIC LETTER YEH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH SMALL V;;;; +06CF;ARABIC LETTER WAW WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06D0;ARABIC LETTER E;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TWO DOTS VERTICAL BELOW;*;;; +06D1;ARABIC LETTER YEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH THREE DOTS BELOW;;;; +06D2;ARABIC LETTER YEH BARREE;Lo;0;AL;;;;;N;ARABIC LETTER YA BARREE;;;; +06D3;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE;Lo;0;AL;06D2 0654;;;;N;ARABIC LETTER HAMZAH ON YA BARREE;;;; +06D4;ARABIC FULL STOP;Po;0;AL;;;;;N;ARABIC PERIOD;;;; +06D5;ARABIC LETTER AE;Lo;0;AL;;;;;N;;;;; +06D6;ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;; +06D7;ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;; +06D8;ARABIC SMALL HIGH MEEM INITIAL FORM;Mn;230;NSM;;;;;N;;;;; +06D9;ARABIC SMALL HIGH LAM ALEF;Mn;230;NSM;;;;;N;;;;; +06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;; +06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;; +06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;; +06DD;ARABIC END OF AYAH;Cf;0;AL;;;;;N;;;;; +06DE;ARABIC START OF RUB EL HIZB;Me;0;NSM;;;;;N;;;;; +06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;; +06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;; +06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;; +06E2;ARABIC SMALL HIGH MEEM ISOLATED FORM;Mn;230;NSM;;;;;N;;;;; +06E3;ARABIC SMALL LOW SEEN;Mn;220;NSM;;;;;N;;;;; +06E4;ARABIC SMALL HIGH MADDA;Mn;230;NSM;;;;;N;;;;; +06E5;ARABIC SMALL WAW;Lm;0;AL;;;;;N;;;;; +06E6;ARABIC SMALL YEH;Lm;0;AL;;;;;N;;;;; +06E7;ARABIC SMALL HIGH YEH;Mn;230;NSM;;;;;N;;;;; +06E8;ARABIC SMALL HIGH NOON;Mn;230;NSM;;;;;N;;;;; +06E9;ARABIC PLACE OF SAJDAH;So;0;ON;;;;;N;;;;; +06EA;ARABIC EMPTY CENTRE LOW STOP;Mn;220;NSM;;;;;N;;;;; +06EB;ARABIC EMPTY CENTRE HIGH STOP;Mn;230;NSM;;;;;N;;;;; +06EC;ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE;Mn;230;NSM;;;;;N;;;;; +06ED;ARABIC SMALL LOW MEEM;Mn;220;NSM;;;;;N;;;;; +06EE;ARABIC LETTER DAL WITH INVERTED V;Lo;0;AL;;;;;N;;;;; +06EF;ARABIC LETTER REH WITH INVERTED V;Lo;0;AL;;;;;N;;;;; +06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;; +06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;; +06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;; +06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;; +06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;; +06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;; +06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;; +06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;; +06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;; +06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;; +06FA;ARABIC LETTER SHEEN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06FB;ARABIC LETTER DAD WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06FC;ARABIC LETTER GHAIN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06FD;ARABIC SIGN SINDHI AMPERSAND;So;0;AL;;;;;N;;;;; +06FE;ARABIC SIGN SINDHI POSTPOSITION MEN;So;0;AL;;;;;N;;;;; +06FF;ARABIC LETTER HEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;; +0700;SYRIAC END OF PARAGRAPH;Po;0;AL;;;;;N;;;;; +0701;SYRIAC SUPRALINEAR FULL STOP;Po;0;AL;;;;;N;;;;; +0702;SYRIAC SUBLINEAR FULL STOP;Po;0;AL;;;;;N;;;;; +0703;SYRIAC SUPRALINEAR COLON;Po;0;AL;;;;;N;;;;; +0704;SYRIAC SUBLINEAR COLON;Po;0;AL;;;;;N;;;;; +0705;SYRIAC HORIZONTAL COLON;Po;0;AL;;;;;N;;;;; +0706;SYRIAC COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;; +0707;SYRIAC COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;; +0708;SYRIAC SUPRALINEAR COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;; +0709;SYRIAC SUBLINEAR COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;; +070A;SYRIAC CONTRACTION;Po;0;AL;;;;;N;;;;; +070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;; +070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;; +070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;; +070F;SYRIAC ABBREVIATION MARK;Cf;0;BN;;;;;N;;;;; +0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;; +0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;; +0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;; +0713;SYRIAC LETTER GAMAL;Lo;0;AL;;;;;N;;;;; +0714;SYRIAC LETTER GAMAL GARSHUNI;Lo;0;AL;;;;;N;;;;; +0715;SYRIAC LETTER DALATH;Lo;0;AL;;;;;N;;;;; +0716;SYRIAC LETTER DOTLESS DALATH RISH;Lo;0;AL;;;;;N;;;;; +0717;SYRIAC LETTER HE;Lo;0;AL;;;;;N;;;;; +0718;SYRIAC LETTER WAW;Lo;0;AL;;;;;N;;;;; +0719;SYRIAC LETTER ZAIN;Lo;0;AL;;;;;N;;;;; +071A;SYRIAC LETTER HETH;Lo;0;AL;;;;;N;;;;; +071B;SYRIAC LETTER TETH;Lo;0;AL;;;;;N;;;;; +071C;SYRIAC LETTER TETH GARSHUNI;Lo;0;AL;;;;;N;;;;; +071D;SYRIAC LETTER YUDH;Lo;0;AL;;;;;N;;;;; +071E;SYRIAC LETTER YUDH HE;Lo;0;AL;;;;;N;;;;; +071F;SYRIAC LETTER KAPH;Lo;0;AL;;;;;N;;;;; +0720;SYRIAC LETTER LAMADH;Lo;0;AL;;;;;N;;;;; +0721;SYRIAC LETTER MIM;Lo;0;AL;;;;;N;;;;; +0722;SYRIAC LETTER NUN;Lo;0;AL;;;;;N;;;;; +0723;SYRIAC LETTER SEMKATH;Lo;0;AL;;;;;N;;;;; +0724;SYRIAC LETTER FINAL SEMKATH;Lo;0;AL;;;;;N;;;;; +0725;SYRIAC LETTER E;Lo;0;AL;;;;;N;;;;; +0726;SYRIAC LETTER PE;Lo;0;AL;;;;;N;;;;; +0727;SYRIAC LETTER REVERSED PE;Lo;0;AL;;;;;N;;;;; +0728;SYRIAC LETTER SADHE;Lo;0;AL;;;;;N;;;;; +0729;SYRIAC LETTER QAPH;Lo;0;AL;;;;;N;;;;; +072A;SYRIAC LETTER RISH;Lo;0;AL;;;;;N;;;;; +072B;SYRIAC LETTER SHIN;Lo;0;AL;;;;;N;;;;; +072C;SYRIAC LETTER TAW;Lo;0;AL;;;;;N;;;;; +072D;SYRIAC LETTER PERSIAN BHETH;Lo;0;AL;;;;;N;;;;; +072E;SYRIAC LETTER PERSIAN GHAMAL;Lo;0;AL;;;;;N;;;;; +072F;SYRIAC LETTER PERSIAN DHALATH;Lo;0;AL;;;;;N;;;;; +0730;SYRIAC PTHAHA ABOVE;Mn;230;NSM;;;;;N;;;;; +0731;SYRIAC PTHAHA BELOW;Mn;220;NSM;;;;;N;;;;; +0732;SYRIAC PTHAHA DOTTED;Mn;230;NSM;;;;;N;;;;; +0733;SYRIAC ZQAPHA ABOVE;Mn;230;NSM;;;;;N;;;;; +0734;SYRIAC ZQAPHA BELOW;Mn;220;NSM;;;;;N;;;;; +0735;SYRIAC ZQAPHA DOTTED;Mn;230;NSM;;;;;N;;;;; +0736;SYRIAC RBASA ABOVE;Mn;230;NSM;;;;;N;;;;; +0737;SYRIAC RBASA BELOW;Mn;220;NSM;;;;;N;;;;; +0738;SYRIAC DOTTED ZLAMA HORIZONTAL;Mn;220;NSM;;;;;N;;;;; +0739;SYRIAC DOTTED ZLAMA ANGULAR;Mn;220;NSM;;;;;N;;;;; +073A;SYRIAC HBASA ABOVE;Mn;230;NSM;;;;;N;;;;; +073B;SYRIAC HBASA BELOW;Mn;220;NSM;;;;;N;;;;; +073C;SYRIAC HBASA-ESASA DOTTED;Mn;220;NSM;;;;;N;;;;; +073D;SYRIAC ESASA ABOVE;Mn;230;NSM;;;;;N;;;;; +073E;SYRIAC ESASA BELOW;Mn;220;NSM;;;;;N;;;;; +073F;SYRIAC RWAHA;Mn;230;NSM;;;;;N;;;;; +0740;SYRIAC FEMININE DOT;Mn;230;NSM;;;;;N;;;;; +0741;SYRIAC QUSHSHAYA;Mn;230;NSM;;;;;N;;;;; +0742;SYRIAC RUKKAKHA;Mn;220;NSM;;;;;N;;;;; +0743;SYRIAC TWO VERTICAL DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +0744;SYRIAC TWO VERTICAL DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +0745;SYRIAC THREE DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +0746;SYRIAC THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +0747;SYRIAC OBLIQUE LINE ABOVE;Mn;230;NSM;;;;;N;;;;; +0748;SYRIAC OBLIQUE LINE BELOW;Mn;220;NSM;;;;;N;;;;; +0749;SYRIAC MUSIC;Mn;230;NSM;;;;;N;;;;; +074A;SYRIAC BARREKH;Mn;230;NSM;;;;;N;;;;; +074D;SYRIAC LETTER SOGDIAN ZHAIN;Lo;0;AL;;;;;N;;;;; +074E;SYRIAC LETTER SOGDIAN KHAPH;Lo;0;AL;;;;;N;;;;; +074F;SYRIAC LETTER SOGDIAN FE;Lo;0;AL;;;;;N;;;;; +0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;; +0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;; +0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;; +0783;THAANA LETTER RAA;Lo;0;AL;;;;;N;;;;; +0784;THAANA LETTER BAA;Lo;0;AL;;;;;N;;;;; +0785;THAANA LETTER LHAVIYANI;Lo;0;AL;;;;;N;;;;; +0786;THAANA LETTER KAAFU;Lo;0;AL;;;;;N;;;;; +0787;THAANA LETTER ALIFU;Lo;0;AL;;;;;N;;;;; +0788;THAANA LETTER VAAVU;Lo;0;AL;;;;;N;;;;; +0789;THAANA LETTER MEEMU;Lo;0;AL;;;;;N;;;;; +078A;THAANA LETTER FAAFU;Lo;0;AL;;;;;N;;;;; +078B;THAANA LETTER DHAALU;Lo;0;AL;;;;;N;;;;; +078C;THAANA LETTER THAA;Lo;0;AL;;;;;N;;;;; +078D;THAANA LETTER LAAMU;Lo;0;AL;;;;;N;;;;; +078E;THAANA LETTER GAAFU;Lo;0;AL;;;;;N;;;;; +078F;THAANA LETTER GNAVIYANI;Lo;0;AL;;;;;N;;;;; +0790;THAANA LETTER SEENU;Lo;0;AL;;;;;N;;;;; +0791;THAANA LETTER DAVIYANI;Lo;0;AL;;;;;N;;;;; +0792;THAANA LETTER ZAVIYANI;Lo;0;AL;;;;;N;;;;; +0793;THAANA LETTER TAVIYANI;Lo;0;AL;;;;;N;;;;; +0794;THAANA LETTER YAA;Lo;0;AL;;;;;N;;;;; +0795;THAANA LETTER PAVIYANI;Lo;0;AL;;;;;N;;;;; +0796;THAANA LETTER JAVIYANI;Lo;0;AL;;;;;N;;;;; +0797;THAANA LETTER CHAVIYANI;Lo;0;AL;;;;;N;;;;; +0798;THAANA LETTER TTAA;Lo;0;AL;;;;;N;;;;; +0799;THAANA LETTER HHAA;Lo;0;AL;;;;;N;;;;; +079A;THAANA LETTER KHAA;Lo;0;AL;;;;;N;;;;; +079B;THAANA LETTER THAALU;Lo;0;AL;;;;;N;;;;; +079C;THAANA LETTER ZAA;Lo;0;AL;;;;;N;;;;; +079D;THAANA LETTER SHEENU;Lo;0;AL;;;;;N;;;;; +079E;THAANA LETTER SAADHU;Lo;0;AL;;;;;N;;;;; +079F;THAANA LETTER DAADHU;Lo;0;AL;;;;;N;;;;; +07A0;THAANA LETTER TO;Lo;0;AL;;;;;N;;;;; +07A1;THAANA LETTER ZO;Lo;0;AL;;;;;N;;;;; +07A2;THAANA LETTER AINU;Lo;0;AL;;;;;N;;;;; +07A3;THAANA LETTER GHAINU;Lo;0;AL;;;;;N;;;;; +07A4;THAANA LETTER QAAFU;Lo;0;AL;;;;;N;;;;; +07A5;THAANA LETTER WAAVU;Lo;0;AL;;;;;N;;;;; +07A6;THAANA ABAFILI;Mn;0;NSM;;;;;N;;;;; +07A7;THAANA AABAAFILI;Mn;0;NSM;;;;;N;;;;; +07A8;THAANA IBIFILI;Mn;0;NSM;;;;;N;;;;; +07A9;THAANA EEBEEFILI;Mn;0;NSM;;;;;N;;;;; +07AA;THAANA UBUFILI;Mn;0;NSM;;;;;N;;;;; +07AB;THAANA OOBOOFILI;Mn;0;NSM;;;;;N;;;;; +07AC;THAANA EBEFILI;Mn;0;NSM;;;;;N;;;;; +07AD;THAANA EYBEYFILI;Mn;0;NSM;;;;;N;;;;; +07AE;THAANA OBOFILI;Mn;0;NSM;;;;;N;;;;; +07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;; +07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;; +07B1;THAANA LETTER NAA;Lo;0;AL;;;;;N;;;;; +0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0904;DEVANAGARI LETTER SHORT A;Lo;0;L;;;;;N;;;;; +0905;DEVANAGARI LETTER A;Lo;0;L;;;;;N;;;;; +0906;DEVANAGARI LETTER AA;Lo;0;L;;;;;N;;;;; +0907;DEVANAGARI LETTER I;Lo;0;L;;;;;N;;;;; +0908;DEVANAGARI LETTER II;Lo;0;L;;;;;N;;;;; +0909;DEVANAGARI LETTER U;Lo;0;L;;;;;N;;;;; +090A;DEVANAGARI LETTER UU;Lo;0;L;;;;;N;;;;; +090B;DEVANAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +090C;DEVANAGARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +090D;DEVANAGARI LETTER CANDRA E;Lo;0;L;;;;;N;;;;; +090E;DEVANAGARI LETTER SHORT E;Lo;0;L;;;;;N;;;;; +090F;DEVANAGARI LETTER E;Lo;0;L;;;;;N;;;;; +0910;DEVANAGARI LETTER AI;Lo;0;L;;;;;N;;;;; +0911;DEVANAGARI LETTER CANDRA O;Lo;0;L;;;;;N;;;;; +0912;DEVANAGARI LETTER SHORT O;Lo;0;L;;;;;N;;;;; +0913;DEVANAGARI LETTER O;Lo;0;L;;;;;N;;;;; +0914;DEVANAGARI LETTER AU;Lo;0;L;;;;;N;;;;; +0915;DEVANAGARI LETTER KA;Lo;0;L;;;;;N;;;;; +0916;DEVANAGARI LETTER KHA;Lo;0;L;;;;;N;;;;; +0917;DEVANAGARI LETTER GA;Lo;0;L;;;;;N;;;;; +0918;DEVANAGARI LETTER GHA;Lo;0;L;;;;;N;;;;; +0919;DEVANAGARI LETTER NGA;Lo;0;L;;;;;N;;;;; +091A;DEVANAGARI LETTER CA;Lo;0;L;;;;;N;;;;; +091B;DEVANAGARI LETTER CHA;Lo;0;L;;;;;N;;;;; +091C;DEVANAGARI LETTER JA;Lo;0;L;;;;;N;;;;; +091D;DEVANAGARI LETTER JHA;Lo;0;L;;;;;N;;;;; +091E;DEVANAGARI LETTER NYA;Lo;0;L;;;;;N;;;;; +091F;DEVANAGARI LETTER TTA;Lo;0;L;;;;;N;;;;; +0920;DEVANAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;; +0921;DEVANAGARI LETTER DDA;Lo;0;L;;;;;N;;;;; +0922;DEVANAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;; +0923;DEVANAGARI LETTER NNA;Lo;0;L;;;;;N;;;;; +0924;DEVANAGARI LETTER TA;Lo;0;L;;;;;N;;;;; +0925;DEVANAGARI LETTER THA;Lo;0;L;;;;;N;;;;; +0926;DEVANAGARI LETTER DA;Lo;0;L;;;;;N;;;;; +0927;DEVANAGARI LETTER DHA;Lo;0;L;;;;;N;;;;; +0928;DEVANAGARI LETTER NA;Lo;0;L;;;;;N;;;;; +0929;DEVANAGARI LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;; +092A;DEVANAGARI LETTER PA;Lo;0;L;;;;;N;;;;; +092B;DEVANAGARI LETTER PHA;Lo;0;L;;;;;N;;;;; +092C;DEVANAGARI LETTER BA;Lo;0;L;;;;;N;;;;; +092D;DEVANAGARI LETTER BHA;Lo;0;L;;;;;N;;;;; +092E;DEVANAGARI LETTER MA;Lo;0;L;;;;;N;;;;; +092F;DEVANAGARI LETTER YA;Lo;0;L;;;;;N;;;;; +0930;DEVANAGARI LETTER RA;Lo;0;L;;;;;N;;;;; +0931;DEVANAGARI LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;; +0932;DEVANAGARI LETTER LA;Lo;0;L;;;;;N;;;;; +0933;DEVANAGARI LETTER LLA;Lo;0;L;;;;;N;;;;; +0934;DEVANAGARI LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;; +0935;DEVANAGARI LETTER VA;Lo;0;L;;;;;N;;;;; +0936;DEVANAGARI LETTER SHA;Lo;0;L;;;;;N;;;;; +0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;; +0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;; +0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;; +093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +093F;DEVANAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0940;DEVANAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0941;DEVANAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0942;DEVANAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0943;DEVANAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0944;DEVANAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +0945;DEVANAGARI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; +0946;DEVANAGARI VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;; +0947;DEVANAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +0948;DEVANAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +0949;DEVANAGARI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; +094A;DEVANAGARI VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;; +094B;DEVANAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;; +0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;; +0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;; +0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;; +0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; +0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;; +0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;; +095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;; +095B;DEVANAGARI LETTER ZA;Lo;0;L;091C 093C;;;;N;;;;; +095C;DEVANAGARI LETTER DDDHA;Lo;0;L;0921 093C;;;;N;;;;; +095D;DEVANAGARI LETTER RHA;Lo;0;L;0922 093C;;;;N;;;;; +095E;DEVANAGARI LETTER FA;Lo;0;L;092B 093C;;;;N;;;;; +095F;DEVANAGARI LETTER YYA;Lo;0;L;092F 093C;;;;N;;;;; +0960;DEVANAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0961;DEVANAGARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0962;DEVANAGARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0963;DEVANAGARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +0964;DEVANAGARI DANDA;Po;0;L;;;;;N;;;;; +0965;DEVANAGARI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0985;BENGALI LETTER A;Lo;0;L;;;;;N;;;;; +0986;BENGALI LETTER AA;Lo;0;L;;;;;N;;;;; +0987;BENGALI LETTER I;Lo;0;L;;;;;N;;;;; +0988;BENGALI LETTER II;Lo;0;L;;;;;N;;;;; +0989;BENGALI LETTER U;Lo;0;L;;;;;N;;;;; +098A;BENGALI LETTER UU;Lo;0;L;;;;;N;;;;; +098B;BENGALI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +098C;BENGALI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +098F;BENGALI LETTER E;Lo;0;L;;;;;N;;;;; +0990;BENGALI LETTER AI;Lo;0;L;;;;;N;;;;; +0993;BENGALI LETTER O;Lo;0;L;;;;;N;;;;; +0994;BENGALI LETTER AU;Lo;0;L;;;;;N;;;;; +0995;BENGALI LETTER KA;Lo;0;L;;;;;N;;;;; +0996;BENGALI LETTER KHA;Lo;0;L;;;;;N;;;;; +0997;BENGALI LETTER GA;Lo;0;L;;;;;N;;;;; +0998;BENGALI LETTER GHA;Lo;0;L;;;;;N;;;;; +0999;BENGALI LETTER NGA;Lo;0;L;;;;;N;;;;; +099A;BENGALI LETTER CA;Lo;0;L;;;;;N;;;;; +099B;BENGALI LETTER CHA;Lo;0;L;;;;;N;;;;; +099C;BENGALI LETTER JA;Lo;0;L;;;;;N;;;;; +099D;BENGALI LETTER JHA;Lo;0;L;;;;;N;;;;; +099E;BENGALI LETTER NYA;Lo;0;L;;;;;N;;;;; +099F;BENGALI LETTER TTA;Lo;0;L;;;;;N;;;;; +09A0;BENGALI LETTER TTHA;Lo;0;L;;;;;N;;;;; +09A1;BENGALI LETTER DDA;Lo;0;L;;;;;N;;;;; +09A2;BENGALI LETTER DDHA;Lo;0;L;;;;;N;;;;; +09A3;BENGALI LETTER NNA;Lo;0;L;;;;;N;;;;; +09A4;BENGALI LETTER TA;Lo;0;L;;;;;N;;;;; +09A5;BENGALI LETTER THA;Lo;0;L;;;;;N;;;;; +09A6;BENGALI LETTER DA;Lo;0;L;;;;;N;;;;; +09A7;BENGALI LETTER DHA;Lo;0;L;;;;;N;;;;; +09A8;BENGALI LETTER NA;Lo;0;L;;;;;N;;;;; +09AA;BENGALI LETTER PA;Lo;0;L;;;;;N;;;;; +09AB;BENGALI LETTER PHA;Lo;0;L;;;;;N;;;;; +09AC;BENGALI LETTER BA;Lo;0;L;;;;;N;;;;; +09AD;BENGALI LETTER BHA;Lo;0;L;;;;;N;;;;; +09AE;BENGALI LETTER MA;Lo;0;L;;;;;N;;;;; +09AF;BENGALI LETTER YA;Lo;0;L;;;;;N;;;;; +09B0;BENGALI LETTER RA;Lo;0;L;;;;;N;;;;; +09B2;BENGALI LETTER LA;Lo;0;L;;;;;N;;;;; +09B6;BENGALI LETTER SHA;Lo;0;L;;;;;N;;;;; +09B7;BENGALI LETTER SSA;Lo;0;L;;;;;N;;;;; +09B8;BENGALI LETTER SA;Lo;0;L;;;;;N;;;;; +09B9;BENGALI LETTER HA;Lo;0;L;;;;;N;;;;; +09BC;BENGALI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +09BD;BENGALI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +09BE;BENGALI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +09BF;BENGALI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +09C0;BENGALI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +09C1;BENGALI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +09C2;BENGALI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +09C3;BENGALI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +09C4;BENGALI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +09C7;BENGALI VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +09C8;BENGALI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;; +09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;; +09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;; +09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;; +09DF;BENGALI LETTER YYA;Lo;0;L;09AF 09BC;;;;N;;;;; +09E0;BENGALI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +09E1;BENGALI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +09E2;BENGALI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +09E3;BENGALI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +09F0;BENGALI LETTER RA WITH MIDDLE DIAGONAL;Lo;0;L;;;;;N;;Assamese;;; +09F1;BENGALI LETTER RA WITH LOWER DIAGONAL;Lo;0;L;;;;;N;BENGALI LETTER VA WITH LOWER DIAGONAL;Assamese;;; +09F2;BENGALI RUPEE MARK;Sc;0;ET;;;;;N;;;;; +09F3;BENGALI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; +09F4;BENGALI CURRENCY NUMERATOR ONE;No;0;L;;;;1;N;;;;; +09F5;BENGALI CURRENCY NUMERATOR TWO;No;0;L;;;;2;N;;;;; +09F6;BENGALI CURRENCY NUMERATOR THREE;No;0;L;;;;3;N;;;;; +09F7;BENGALI CURRENCY NUMERATOR FOUR;No;0;L;;;;4;N;;;;; +09F8;BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR;No;0;L;;;;;N;;;;; +09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;; +09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;; +0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;; +0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;; +0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0A05;GURMUKHI LETTER A;Lo;0;L;;;;;N;;;;; +0A06;GURMUKHI LETTER AA;Lo;0;L;;;;;N;;;;; +0A07;GURMUKHI LETTER I;Lo;0;L;;;;;N;;;;; +0A08;GURMUKHI LETTER II;Lo;0;L;;;;;N;;;;; +0A09;GURMUKHI LETTER U;Lo;0;L;;;;;N;;;;; +0A0A;GURMUKHI LETTER UU;Lo;0;L;;;;;N;;;;; +0A0F;GURMUKHI LETTER EE;Lo;0;L;;;;;N;;;;; +0A10;GURMUKHI LETTER AI;Lo;0;L;;;;;N;;;;; +0A13;GURMUKHI LETTER OO;Lo;0;L;;;;;N;;;;; +0A14;GURMUKHI LETTER AU;Lo;0;L;;;;;N;;;;; +0A15;GURMUKHI LETTER KA;Lo;0;L;;;;;N;;;;; +0A16;GURMUKHI LETTER KHA;Lo;0;L;;;;;N;;;;; +0A17;GURMUKHI LETTER GA;Lo;0;L;;;;;N;;;;; +0A18;GURMUKHI LETTER GHA;Lo;0;L;;;;;N;;;;; +0A19;GURMUKHI LETTER NGA;Lo;0;L;;;;;N;;;;; +0A1A;GURMUKHI LETTER CA;Lo;0;L;;;;;N;;;;; +0A1B;GURMUKHI LETTER CHA;Lo;0;L;;;;;N;;;;; +0A1C;GURMUKHI LETTER JA;Lo;0;L;;;;;N;;;;; +0A1D;GURMUKHI LETTER JHA;Lo;0;L;;;;;N;;;;; +0A1E;GURMUKHI LETTER NYA;Lo;0;L;;;;;N;;;;; +0A1F;GURMUKHI LETTER TTA;Lo;0;L;;;;;N;;;;; +0A20;GURMUKHI LETTER TTHA;Lo;0;L;;;;;N;;;;; +0A21;GURMUKHI LETTER DDA;Lo;0;L;;;;;N;;;;; +0A22;GURMUKHI LETTER DDHA;Lo;0;L;;;;;N;;;;; +0A23;GURMUKHI LETTER NNA;Lo;0;L;;;;;N;;;;; +0A24;GURMUKHI LETTER TA;Lo;0;L;;;;;N;;;;; +0A25;GURMUKHI LETTER THA;Lo;0;L;;;;;N;;;;; +0A26;GURMUKHI LETTER DA;Lo;0;L;;;;;N;;;;; +0A27;GURMUKHI LETTER DHA;Lo;0;L;;;;;N;;;;; +0A28;GURMUKHI LETTER NA;Lo;0;L;;;;;N;;;;; +0A2A;GURMUKHI LETTER PA;Lo;0;L;;;;;N;;;;; +0A2B;GURMUKHI LETTER PHA;Lo;0;L;;;;;N;;;;; +0A2C;GURMUKHI LETTER BA;Lo;0;L;;;;;N;;;;; +0A2D;GURMUKHI LETTER BHA;Lo;0;L;;;;;N;;;;; +0A2E;GURMUKHI LETTER MA;Lo;0;L;;;;;N;;;;; +0A2F;GURMUKHI LETTER YA;Lo;0;L;;;;;N;;;;; +0A30;GURMUKHI LETTER RA;Lo;0;L;;;;;N;;;;; +0A32;GURMUKHI LETTER LA;Lo;0;L;;;;;N;;;;; +0A33;GURMUKHI LETTER LLA;Lo;0;L;0A32 0A3C;;;;N;;;;; +0A35;GURMUKHI LETTER VA;Lo;0;L;;;;;N;;;;; +0A36;GURMUKHI LETTER SHA;Lo;0;L;0A38 0A3C;;;;N;;;;; +0A38;GURMUKHI LETTER SA;Lo;0;L;;;;;N;;;;; +0A39;GURMUKHI LETTER HA;Lo;0;L;;;;;N;;;;; +0A3C;GURMUKHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0A3E;GURMUKHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0A3F;GURMUKHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0A40;GURMUKHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0A41;GURMUKHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0A42;GURMUKHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0A47;GURMUKHI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; +0A48;GURMUKHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; +0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;; +0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;; +0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;; +0A5C;GURMUKHI LETTER RRA;Lo;0;L;;;;;N;;;;; +0A5E;GURMUKHI LETTER FA;Lo;0;L;0A2B 0A3C;;;;N;;;;; +0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0A70;GURMUKHI TIPPI;Mn;0;NSM;;;;;N;;;;; +0A71;GURMUKHI ADDAK;Mn;0;NSM;;;;;N;;;;; +0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;; +0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;; +0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;; +0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0A85;GUJARATI LETTER A;Lo;0;L;;;;;N;;;;; +0A86;GUJARATI LETTER AA;Lo;0;L;;;;;N;;;;; +0A87;GUJARATI LETTER I;Lo;0;L;;;;;N;;;;; +0A88;GUJARATI LETTER II;Lo;0;L;;;;;N;;;;; +0A89;GUJARATI LETTER U;Lo;0;L;;;;;N;;;;; +0A8A;GUJARATI LETTER UU;Lo;0;L;;;;;N;;;;; +0A8B;GUJARATI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0A8C;GUJARATI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0A8D;GUJARATI VOWEL CANDRA E;Lo;0;L;;;;;N;;;;; +0A8F;GUJARATI LETTER E;Lo;0;L;;;;;N;;;;; +0A90;GUJARATI LETTER AI;Lo;0;L;;;;;N;;;;; +0A91;GUJARATI VOWEL CANDRA O;Lo;0;L;;;;;N;;;;; +0A93;GUJARATI LETTER O;Lo;0;L;;;;;N;;;;; +0A94;GUJARATI LETTER AU;Lo;0;L;;;;;N;;;;; +0A95;GUJARATI LETTER KA;Lo;0;L;;;;;N;;;;; +0A96;GUJARATI LETTER KHA;Lo;0;L;;;;;N;;;;; +0A97;GUJARATI LETTER GA;Lo;0;L;;;;;N;;;;; +0A98;GUJARATI LETTER GHA;Lo;0;L;;;;;N;;;;; +0A99;GUJARATI LETTER NGA;Lo;0;L;;;;;N;;;;; +0A9A;GUJARATI LETTER CA;Lo;0;L;;;;;N;;;;; +0A9B;GUJARATI LETTER CHA;Lo;0;L;;;;;N;;;;; +0A9C;GUJARATI LETTER JA;Lo;0;L;;;;;N;;;;; +0A9D;GUJARATI LETTER JHA;Lo;0;L;;;;;N;;;;; +0A9E;GUJARATI LETTER NYA;Lo;0;L;;;;;N;;;;; +0A9F;GUJARATI LETTER TTA;Lo;0;L;;;;;N;;;;; +0AA0;GUJARATI LETTER TTHA;Lo;0;L;;;;;N;;;;; +0AA1;GUJARATI LETTER DDA;Lo;0;L;;;;;N;;;;; +0AA2;GUJARATI LETTER DDHA;Lo;0;L;;;;;N;;;;; +0AA3;GUJARATI LETTER NNA;Lo;0;L;;;;;N;;;;; +0AA4;GUJARATI LETTER TA;Lo;0;L;;;;;N;;;;; +0AA5;GUJARATI LETTER THA;Lo;0;L;;;;;N;;;;; +0AA6;GUJARATI LETTER DA;Lo;0;L;;;;;N;;;;; +0AA7;GUJARATI LETTER DHA;Lo;0;L;;;;;N;;;;; +0AA8;GUJARATI LETTER NA;Lo;0;L;;;;;N;;;;; +0AAA;GUJARATI LETTER PA;Lo;0;L;;;;;N;;;;; +0AAB;GUJARATI LETTER PHA;Lo;0;L;;;;;N;;;;; +0AAC;GUJARATI LETTER BA;Lo;0;L;;;;;N;;;;; +0AAD;GUJARATI LETTER BHA;Lo;0;L;;;;;N;;;;; +0AAE;GUJARATI LETTER MA;Lo;0;L;;;;;N;;;;; +0AAF;GUJARATI LETTER YA;Lo;0;L;;;;;N;;;;; +0AB0;GUJARATI LETTER RA;Lo;0;L;;;;;N;;;;; +0AB2;GUJARATI LETTER LA;Lo;0;L;;;;;N;;;;; +0AB3;GUJARATI LETTER LLA;Lo;0;L;;;;;N;;;;; +0AB5;GUJARATI LETTER VA;Lo;0;L;;;;;N;;;;; +0AB6;GUJARATI LETTER SHA;Lo;0;L;;;;;N;;;;; +0AB7;GUJARATI LETTER SSA;Lo;0;L;;;;;N;;;;; +0AB8;GUJARATI LETTER SA;Lo;0;L;;;;;N;;;;; +0AB9;GUJARATI LETTER HA;Lo;0;L;;;;;N;;;;; +0ABC;GUJARATI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0ABD;GUJARATI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +0ABE;GUJARATI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0ABF;GUJARATI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0AC0;GUJARATI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0AC1;GUJARATI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0AC2;GUJARATI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0AC3;GUJARATI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0AC4;GUJARATI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +0AC5;GUJARATI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; +0AC7;GUJARATI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +0AC8;GUJARATI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +0AC9;GUJARATI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; +0ACB;GUJARATI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +0ACC;GUJARATI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +0ACD;GUJARATI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0AD0;GUJARATI OM;Lo;0;L;;;;;N;;;;; +0AE0;GUJARATI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0AE1;GUJARATI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0AE2;GUJARATI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0AE3;GUJARATI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; +0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0B05;ORIYA LETTER A;Lo;0;L;;;;;N;;;;; +0B06;ORIYA LETTER AA;Lo;0;L;;;;;N;;;;; +0B07;ORIYA LETTER I;Lo;0;L;;;;;N;;;;; +0B08;ORIYA LETTER II;Lo;0;L;;;;;N;;;;; +0B09;ORIYA LETTER U;Lo;0;L;;;;;N;;;;; +0B0A;ORIYA LETTER UU;Lo;0;L;;;;;N;;;;; +0B0B;ORIYA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0B0C;ORIYA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0B0F;ORIYA LETTER E;Lo;0;L;;;;;N;;;;; +0B10;ORIYA LETTER AI;Lo;0;L;;;;;N;;;;; +0B13;ORIYA LETTER O;Lo;0;L;;;;;N;;;;; +0B14;ORIYA LETTER AU;Lo;0;L;;;;;N;;;;; +0B15;ORIYA LETTER KA;Lo;0;L;;;;;N;;;;; +0B16;ORIYA LETTER KHA;Lo;0;L;;;;;N;;;;; +0B17;ORIYA LETTER GA;Lo;0;L;;;;;N;;;;; +0B18;ORIYA LETTER GHA;Lo;0;L;;;;;N;;;;; +0B19;ORIYA LETTER NGA;Lo;0;L;;;;;N;;;;; +0B1A;ORIYA LETTER CA;Lo;0;L;;;;;N;;;;; +0B1B;ORIYA LETTER CHA;Lo;0;L;;;;;N;;;;; +0B1C;ORIYA LETTER JA;Lo;0;L;;;;;N;;;;; +0B1D;ORIYA LETTER JHA;Lo;0;L;;;;;N;;;;; +0B1E;ORIYA LETTER NYA;Lo;0;L;;;;;N;;;;; +0B1F;ORIYA LETTER TTA;Lo;0;L;;;;;N;;;;; +0B20;ORIYA LETTER TTHA;Lo;0;L;;;;;N;;;;; +0B21;ORIYA LETTER DDA;Lo;0;L;;;;;N;;;;; +0B22;ORIYA LETTER DDHA;Lo;0;L;;;;;N;;;;; +0B23;ORIYA LETTER NNA;Lo;0;L;;;;;N;;;;; +0B24;ORIYA LETTER TA;Lo;0;L;;;;;N;;;;; +0B25;ORIYA LETTER THA;Lo;0;L;;;;;N;;;;; +0B26;ORIYA LETTER DA;Lo;0;L;;;;;N;;;;; +0B27;ORIYA LETTER DHA;Lo;0;L;;;;;N;;;;; +0B28;ORIYA LETTER NA;Lo;0;L;;;;;N;;;;; +0B2A;ORIYA LETTER PA;Lo;0;L;;;;;N;;;;; +0B2B;ORIYA LETTER PHA;Lo;0;L;;;;;N;;;;; +0B2C;ORIYA LETTER BA;Lo;0;L;;;;;N;;;;; +0B2D;ORIYA LETTER BHA;Lo;0;L;;;;;N;;;;; +0B2E;ORIYA LETTER MA;Lo;0;L;;;;;N;;;;; +0B2F;ORIYA LETTER YA;Lo;0;L;;;;;N;;;;; +0B30;ORIYA LETTER RA;Lo;0;L;;;;;N;;;;; +0B32;ORIYA LETTER LA;Lo;0;L;;;;;N;;;;; +0B33;ORIYA LETTER LLA;Lo;0;L;;;;;N;;;;; +0B35;ORIYA LETTER VA;Lo;0;L;;;;;N;;;;; +0B36;ORIYA LETTER SHA;Lo;0;L;;;;;N;;;;; +0B37;ORIYA LETTER SSA;Lo;0;L;;;;;N;;;;; +0B38;ORIYA LETTER SA;Lo;0;L;;;;;N;;;;; +0B39;ORIYA LETTER HA;Lo;0;L;;;;;N;;;;; +0B3C;ORIYA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0B3D;ORIYA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +0B3E;ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0B3F;ORIYA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +0B40;ORIYA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;; +0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;; +0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;; +0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;; +0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;; +0B5D;ORIYA LETTER RHA;Lo;0;L;0B22 0B3C;;;;N;;;;; +0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;; +0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;; +0B71;ORIYA LETTER WA;Lo;0;L;;;;;N;;;;; +0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +0B83;TAMIL SIGN VISARGA;Lo;0;L;;;;;N;;;;; +0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;; +0B86;TAMIL LETTER AA;Lo;0;L;;;;;N;;;;; +0B87;TAMIL LETTER I;Lo;0;L;;;;;N;;;;; +0B88;TAMIL LETTER II;Lo;0;L;;;;;N;;;;; +0B89;TAMIL LETTER U;Lo;0;L;;;;;N;;;;; +0B8A;TAMIL LETTER UU;Lo;0;L;;;;;N;;;;; +0B8E;TAMIL LETTER E;Lo;0;L;;;;;N;;;;; +0B8F;TAMIL LETTER EE;Lo;0;L;;;;;N;;;;; +0B90;TAMIL LETTER AI;Lo;0;L;;;;;N;;;;; +0B92;TAMIL LETTER O;Lo;0;L;;;;;N;;;;; +0B93;TAMIL LETTER OO;Lo;0;L;;;;;N;;;;; +0B94;TAMIL LETTER AU;Lo;0;L;0B92 0BD7;;;;N;;;;; +0B95;TAMIL LETTER KA;Lo;0;L;;;;;N;;;;; +0B99;TAMIL LETTER NGA;Lo;0;L;;;;;N;;;;; +0B9A;TAMIL LETTER CA;Lo;0;L;;;;;N;;;;; +0B9C;TAMIL LETTER JA;Lo;0;L;;;;;N;;;;; +0B9E;TAMIL LETTER NYA;Lo;0;L;;;;;N;;;;; +0B9F;TAMIL LETTER TTA;Lo;0;L;;;;;N;;;;; +0BA3;TAMIL LETTER NNA;Lo;0;L;;;;;N;;;;; +0BA4;TAMIL LETTER TA;Lo;0;L;;;;;N;;;;; +0BA8;TAMIL LETTER NA;Lo;0;L;;;;;N;;;;; +0BA9;TAMIL LETTER NNNA;Lo;0;L;;;;;N;;;;; +0BAA;TAMIL LETTER PA;Lo;0;L;;;;;N;;;;; +0BAE;TAMIL LETTER MA;Lo;0;L;;;;;N;;;;; +0BAF;TAMIL LETTER YA;Lo;0;L;;;;;N;;;;; +0BB0;TAMIL LETTER RA;Lo;0;L;;;;;N;;;;; +0BB1;TAMIL LETTER RRA;Lo;0;L;;;;;N;;;;; +0BB2;TAMIL LETTER LA;Lo;0;L;;;;;N;;;;; +0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;; +0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;; +0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;; +0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;; +0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;; +0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;; +0BBE;TAMIL VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0BBF;TAMIL VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0BC0;TAMIL VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +0BC1;TAMIL VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +0BC2;TAMIL VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +0BC6;TAMIL VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +0BC7;TAMIL VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +0BC8;TAMIL VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +0BCA;TAMIL VOWEL SIGN O;Mc;0;L;0BC6 0BBE;;;;N;;;;; +0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;; +0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;; +0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0BF0;TAMIL NUMBER TEN;No;0;L;;;;10;N;;;;; +0BF1;TAMIL NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; +0BF2;TAMIL NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; +0BF3;TAMIL DAY SIGN;So;0;ON;;;;;N;;Naal;;; +0BF4;TAMIL MONTH SIGN;So;0;ON;;;;;N;;Maatham;;; +0BF5;TAMIL YEAR SIGN;So;0;ON;;;;;N;;Varudam;;; +0BF6;TAMIL DEBIT SIGN;So;0;ON;;;;;N;;Patru;;; +0BF7;TAMIL CREDIT SIGN;So;0;ON;;;;;N;;Varavu;;; +0BF8;TAMIL AS ABOVE SIGN;So;0;ON;;;;;N;;Merpadi;;; +0BF9;TAMIL RUPEE SIGN;Sc;0;ET;;;;;N;;Rupai;;; +0BFA;TAMIL NUMBER SIGN;So;0;ON;;;;;N;;Enn;;; +0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; +0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;; +0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;; +0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;; +0C08;TELUGU LETTER II;Lo;0;L;;;;;N;;;;; +0C09;TELUGU LETTER U;Lo;0;L;;;;;N;;;;; +0C0A;TELUGU LETTER UU;Lo;0;L;;;;;N;;;;; +0C0B;TELUGU LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0C0C;TELUGU LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0C0E;TELUGU LETTER E;Lo;0;L;;;;;N;;;;; +0C0F;TELUGU LETTER EE;Lo;0;L;;;;;N;;;;; +0C10;TELUGU LETTER AI;Lo;0;L;;;;;N;;;;; +0C12;TELUGU LETTER O;Lo;0;L;;;;;N;;;;; +0C13;TELUGU LETTER OO;Lo;0;L;;;;;N;;;;; +0C14;TELUGU LETTER AU;Lo;0;L;;;;;N;;;;; +0C15;TELUGU LETTER KA;Lo;0;L;;;;;N;;;;; +0C16;TELUGU LETTER KHA;Lo;0;L;;;;;N;;;;; +0C17;TELUGU LETTER GA;Lo;0;L;;;;;N;;;;; +0C18;TELUGU LETTER GHA;Lo;0;L;;;;;N;;;;; +0C19;TELUGU LETTER NGA;Lo;0;L;;;;;N;;;;; +0C1A;TELUGU LETTER CA;Lo;0;L;;;;;N;;;;; +0C1B;TELUGU LETTER CHA;Lo;0;L;;;;;N;;;;; +0C1C;TELUGU LETTER JA;Lo;0;L;;;;;N;;;;; +0C1D;TELUGU LETTER JHA;Lo;0;L;;;;;N;;;;; +0C1E;TELUGU LETTER NYA;Lo;0;L;;;;;N;;;;; +0C1F;TELUGU LETTER TTA;Lo;0;L;;;;;N;;;;; +0C20;TELUGU LETTER TTHA;Lo;0;L;;;;;N;;;;; +0C21;TELUGU LETTER DDA;Lo;0;L;;;;;N;;;;; +0C22;TELUGU LETTER DDHA;Lo;0;L;;;;;N;;;;; +0C23;TELUGU LETTER NNA;Lo;0;L;;;;;N;;;;; +0C24;TELUGU LETTER TA;Lo;0;L;;;;;N;;;;; +0C25;TELUGU LETTER THA;Lo;0;L;;;;;N;;;;; +0C26;TELUGU LETTER DA;Lo;0;L;;;;;N;;;;; +0C27;TELUGU LETTER DHA;Lo;0;L;;;;;N;;;;; +0C28;TELUGU LETTER NA;Lo;0;L;;;;;N;;;;; +0C2A;TELUGU LETTER PA;Lo;0;L;;;;;N;;;;; +0C2B;TELUGU LETTER PHA;Lo;0;L;;;;;N;;;;; +0C2C;TELUGU LETTER BA;Lo;0;L;;;;;N;;;;; +0C2D;TELUGU LETTER BHA;Lo;0;L;;;;;N;;;;; +0C2E;TELUGU LETTER MA;Lo;0;L;;;;;N;;;;; +0C2F;TELUGU LETTER YA;Lo;0;L;;;;;N;;;;; +0C30;TELUGU LETTER RA;Lo;0;L;;;;;N;;;;; +0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;; +0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;; +0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;; +0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;; +0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;; +0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;; +0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;; +0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;; +0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +0C41;TELUGU VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +0C42;TELUGU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +0C43;TELUGU VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +0C44;TELUGU VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +0C46;TELUGU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +0C47;TELUGU VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; +0C48;TELUGU VOWEL SIGN AI;Mn;0;NSM;0C46 0C56;;;;N;;;;; +0C4A;TELUGU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +0C4B;TELUGU VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; +0C4C;TELUGU VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;; +0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;; +0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;; +0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;; +0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;; +0C88;KANNADA LETTER II;Lo;0;L;;;;;N;;;;; +0C89;KANNADA LETTER U;Lo;0;L;;;;;N;;;;; +0C8A;KANNADA LETTER UU;Lo;0;L;;;;;N;;;;; +0C8B;KANNADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0C8C;KANNADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0C8E;KANNADA LETTER E;Lo;0;L;;;;;N;;;;; +0C8F;KANNADA LETTER EE;Lo;0;L;;;;;N;;;;; +0C90;KANNADA LETTER AI;Lo;0;L;;;;;N;;;;; +0C92;KANNADA LETTER O;Lo;0;L;;;;;N;;;;; +0C93;KANNADA LETTER OO;Lo;0;L;;;;;N;;;;; +0C94;KANNADA LETTER AU;Lo;0;L;;;;;N;;;;; +0C95;KANNADA LETTER KA;Lo;0;L;;;;;N;;;;; +0C96;KANNADA LETTER KHA;Lo;0;L;;;;;N;;;;; +0C97;KANNADA LETTER GA;Lo;0;L;;;;;N;;;;; +0C98;KANNADA LETTER GHA;Lo;0;L;;;;;N;;;;; +0C99;KANNADA LETTER NGA;Lo;0;L;;;;;N;;;;; +0C9A;KANNADA LETTER CA;Lo;0;L;;;;;N;;;;; +0C9B;KANNADA LETTER CHA;Lo;0;L;;;;;N;;;;; +0C9C;KANNADA LETTER JA;Lo;0;L;;;;;N;;;;; +0C9D;KANNADA LETTER JHA;Lo;0;L;;;;;N;;;;; +0C9E;KANNADA LETTER NYA;Lo;0;L;;;;;N;;;;; +0C9F;KANNADA LETTER TTA;Lo;0;L;;;;;N;;;;; +0CA0;KANNADA LETTER TTHA;Lo;0;L;;;;;N;;;;; +0CA1;KANNADA LETTER DDA;Lo;0;L;;;;;N;;;;; +0CA2;KANNADA LETTER DDHA;Lo;0;L;;;;;N;;;;; +0CA3;KANNADA LETTER NNA;Lo;0;L;;;;;N;;;;; +0CA4;KANNADA LETTER TA;Lo;0;L;;;;;N;;;;; +0CA5;KANNADA LETTER THA;Lo;0;L;;;;;N;;;;; +0CA6;KANNADA LETTER DA;Lo;0;L;;;;;N;;;;; +0CA7;KANNADA LETTER DHA;Lo;0;L;;;;;N;;;;; +0CA8;KANNADA LETTER NA;Lo;0;L;;;;;N;;;;; +0CAA;KANNADA LETTER PA;Lo;0;L;;;;;N;;;;; +0CAB;KANNADA LETTER PHA;Lo;0;L;;;;;N;;;;; +0CAC;KANNADA LETTER BA;Lo;0;L;;;;;N;;;;; +0CAD;KANNADA LETTER BHA;Lo;0;L;;;;;N;;;;; +0CAE;KANNADA LETTER MA;Lo;0;L;;;;;N;;;;; +0CAF;KANNADA LETTER YA;Lo;0;L;;;;;N;;;;; +0CB0;KANNADA LETTER RA;Lo;0;L;;;;;N;;;;; +0CB1;KANNADA LETTER RRA;Lo;0;L;;;;;N;;;;; +0CB2;KANNADA LETTER LA;Lo;0;L;;;;;N;;;;; +0CB3;KANNADA LETTER LLA;Lo;0;L;;;;;N;;;;; +0CB5;KANNADA LETTER VA;Lo;0;L;;;;;N;;;;; +0CB6;KANNADA LETTER SHA;Lo;0;L;;;;;N;;;;; +0CB7;KANNADA LETTER SSA;Lo;0;L;;;;;N;;;;; +0CB8;KANNADA LETTER SA;Lo;0;L;;;;;N;;;;; +0CB9;KANNADA LETTER HA;Lo;0;L;;;;;N;;;;; +0CBC;KANNADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0CBD;KANNADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +0CBE;KANNADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0CBF;KANNADA VOWEL SIGN I;Mn;0;L;;;;;N;;;;; +0CC0;KANNADA VOWEL SIGN II;Mc;0;L;0CBF 0CD5;;;;N;;;;; +0CC1;KANNADA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +0CC2;KANNADA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +0CC3;KANNADA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +0CC4;KANNADA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +0CC6;KANNADA VOWEL SIGN E;Mn;0;L;;;;;N;;;;; +0CC7;KANNADA VOWEL SIGN EE;Mc;0;L;0CC6 0CD5;;;;N;;;;; +0CC8;KANNADA VOWEL SIGN AI;Mc;0;L;0CC6 0CD6;;;;N;;;;; +0CCA;KANNADA VOWEL SIGN O;Mc;0;L;0CC6 0CC2;;;;N;;;;; +0CCB;KANNADA VOWEL SIGN OO;Mc;0;L;0CCA 0CD5;;;;N;;;;; +0CCC;KANNADA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;; +0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;; +0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;; +0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;; +0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;; +0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;; +0D08;MALAYALAM LETTER II;Lo;0;L;;;;;N;;;;; +0D09;MALAYALAM LETTER U;Lo;0;L;;;;;N;;;;; +0D0A;MALAYALAM LETTER UU;Lo;0;L;;;;;N;;;;; +0D0B;MALAYALAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0D0C;MALAYALAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0D0E;MALAYALAM LETTER E;Lo;0;L;;;;;N;;;;; +0D0F;MALAYALAM LETTER EE;Lo;0;L;;;;;N;;;;; +0D10;MALAYALAM LETTER AI;Lo;0;L;;;;;N;;;;; +0D12;MALAYALAM LETTER O;Lo;0;L;;;;;N;;;;; +0D13;MALAYALAM LETTER OO;Lo;0;L;;;;;N;;;;; +0D14;MALAYALAM LETTER AU;Lo;0;L;;;;;N;;;;; +0D15;MALAYALAM LETTER KA;Lo;0;L;;;;;N;;;;; +0D16;MALAYALAM LETTER KHA;Lo;0;L;;;;;N;;;;; +0D17;MALAYALAM LETTER GA;Lo;0;L;;;;;N;;;;; +0D18;MALAYALAM LETTER GHA;Lo;0;L;;;;;N;;;;; +0D19;MALAYALAM LETTER NGA;Lo;0;L;;;;;N;;;;; +0D1A;MALAYALAM LETTER CA;Lo;0;L;;;;;N;;;;; +0D1B;MALAYALAM LETTER CHA;Lo;0;L;;;;;N;;;;; +0D1C;MALAYALAM LETTER JA;Lo;0;L;;;;;N;;;;; +0D1D;MALAYALAM LETTER JHA;Lo;0;L;;;;;N;;;;; +0D1E;MALAYALAM LETTER NYA;Lo;0;L;;;;;N;;;;; +0D1F;MALAYALAM LETTER TTA;Lo;0;L;;;;;N;;;;; +0D20;MALAYALAM LETTER TTHA;Lo;0;L;;;;;N;;;;; +0D21;MALAYALAM LETTER DDA;Lo;0;L;;;;;N;;;;; +0D22;MALAYALAM LETTER DDHA;Lo;0;L;;;;;N;;;;; +0D23;MALAYALAM LETTER NNA;Lo;0;L;;;;;N;;;;; +0D24;MALAYALAM LETTER TA;Lo;0;L;;;;;N;;;;; +0D25;MALAYALAM LETTER THA;Lo;0;L;;;;;N;;;;; +0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;; +0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;; +0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;; +0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;; +0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;; +0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;; +0D2D;MALAYALAM LETTER BHA;Lo;0;L;;;;;N;;;;; +0D2E;MALAYALAM LETTER MA;Lo;0;L;;;;;N;;;;; +0D2F;MALAYALAM LETTER YA;Lo;0;L;;;;;N;;;;; +0D30;MALAYALAM LETTER RA;Lo;0;L;;;;;N;;;;; +0D31;MALAYALAM LETTER RRA;Lo;0;L;;;;;N;;;;; +0D32;MALAYALAM LETTER LA;Lo;0;L;;;;;N;;;;; +0D33;MALAYALAM LETTER LLA;Lo;0;L;;;;;N;;;;; +0D34;MALAYALAM LETTER LLLA;Lo;0;L;;;;;N;;;;; +0D35;MALAYALAM LETTER VA;Lo;0;L;;;;;N;;;;; +0D36;MALAYALAM LETTER SHA;Lo;0;L;;;;;N;;;;; +0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;; +0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;; +0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;; +0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +0D4A;MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;; +0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;; +0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;; +0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;; +0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;; +0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;; +0D86;SINHALA LETTER AAYANNA;Lo;0;L;;;;;N;;;;; +0D87;SINHALA LETTER AEYANNA;Lo;0;L;;;;;N;;;;; +0D88;SINHALA LETTER AEEYANNA;Lo;0;L;;;;;N;;;;; +0D89;SINHALA LETTER IYANNA;Lo;0;L;;;;;N;;;;; +0D8A;SINHALA LETTER IIYANNA;Lo;0;L;;;;;N;;;;; +0D8B;SINHALA LETTER UYANNA;Lo;0;L;;;;;N;;;;; +0D8C;SINHALA LETTER UUYANNA;Lo;0;L;;;;;N;;;;; +0D8D;SINHALA LETTER IRUYANNA;Lo;0;L;;;;;N;;;;; +0D8E;SINHALA LETTER IRUUYANNA;Lo;0;L;;;;;N;;;;; +0D8F;SINHALA LETTER ILUYANNA;Lo;0;L;;;;;N;;;;; +0D90;SINHALA LETTER ILUUYANNA;Lo;0;L;;;;;N;;;;; +0D91;SINHALA LETTER EYANNA;Lo;0;L;;;;;N;;;;; +0D92;SINHALA LETTER EEYANNA;Lo;0;L;;;;;N;;;;; +0D93;SINHALA LETTER AIYANNA;Lo;0;L;;;;;N;;;;; +0D94;SINHALA LETTER OYANNA;Lo;0;L;;;;;N;;;;; +0D95;SINHALA LETTER OOYANNA;Lo;0;L;;;;;N;;;;; +0D96;SINHALA LETTER AUYANNA;Lo;0;L;;;;;N;;;;; +0D9A;SINHALA LETTER ALPAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;; +0D9B;SINHALA LETTER MAHAAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;; +0D9C;SINHALA LETTER ALPAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;; +0D9D;SINHALA LETTER MAHAAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;; +0D9E;SINHALA LETTER KANTAJA NAASIKYAYA;Lo;0;L;;;;;N;;;;; +0D9F;SINHALA LETTER SANYAKA GAYANNA;Lo;0;L;;;;;N;;;;; +0DA0;SINHALA LETTER ALPAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;; +0DA1;SINHALA LETTER MAHAAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;; +0DA2;SINHALA LETTER ALPAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;; +0DA3;SINHALA LETTER MAHAAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;; +0DA4;SINHALA LETTER TAALUJA NAASIKYAYA;Lo;0;L;;;;;N;;;;; +0DA5;SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA;Lo;0;L;;;;;N;;;;; +0DA6;SINHALA LETTER SANYAKA JAYANNA;Lo;0;L;;;;;N;;;;; +0DA7;SINHALA LETTER ALPAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;; +0DA8;SINHALA LETTER MAHAAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;; +0DA9;SINHALA LETTER ALPAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;; +0DAA;SINHALA LETTER MAHAAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;; +0DAB;SINHALA LETTER MUURDHAJA NAYANNA;Lo;0;L;;;;;N;;;;; +0DAC;SINHALA LETTER SANYAKA DDAYANNA;Lo;0;L;;;;;N;;;;; +0DAD;SINHALA LETTER ALPAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;; +0DAE;SINHALA LETTER MAHAAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;; +0DAF;SINHALA LETTER ALPAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;; +0DB0;SINHALA LETTER MAHAAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;; +0DB1;SINHALA LETTER DANTAJA NAYANNA;Lo;0;L;;;;;N;;;;; +0DB3;SINHALA LETTER SANYAKA DAYANNA;Lo;0;L;;;;;N;;;;; +0DB4;SINHALA LETTER ALPAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;; +0DB5;SINHALA LETTER MAHAAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;; +0DB6;SINHALA LETTER ALPAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;; +0DB7;SINHALA LETTER MAHAAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;; +0DB8;SINHALA LETTER MAYANNA;Lo;0;L;;;;;N;;;;; +0DB9;SINHALA LETTER AMBA BAYANNA;Lo;0;L;;;;;N;;;;; +0DBA;SINHALA LETTER YAYANNA;Lo;0;L;;;;;N;;;;; +0DBB;SINHALA LETTER RAYANNA;Lo;0;L;;;;;N;;;;; +0DBD;SINHALA LETTER DANTAJA LAYANNA;Lo;0;L;;;;;N;;;;; +0DC0;SINHALA LETTER VAYANNA;Lo;0;L;;;;;N;;;;; +0DC1;SINHALA LETTER TAALUJA SAYANNA;Lo;0;L;;;;;N;;;;; +0DC2;SINHALA LETTER MUURDHAJA SAYANNA;Lo;0;L;;;;;N;;;;; +0DC3;SINHALA LETTER DANTAJA SAYANNA;Lo;0;L;;;;;N;;;;; +0DC4;SINHALA LETTER HAYANNA;Lo;0;L;;;;;N;;;;; +0DC5;SINHALA LETTER MUURDHAJA LAYANNA;Lo;0;L;;;;;N;;;;; +0DC6;SINHALA LETTER FAYANNA;Lo;0;L;;;;;N;;;;; +0DCA;SINHALA SIGN AL-LAKUNA;Mn;9;NSM;;;;;N;;;;; +0DCF;SINHALA VOWEL SIGN AELA-PILLA;Mc;0;L;;;;;N;;;;; +0DD0;SINHALA VOWEL SIGN KETTI AEDA-PILLA;Mc;0;L;;;;;N;;;;; +0DD1;SINHALA VOWEL SIGN DIGA AEDA-PILLA;Mc;0;L;;;;;N;;;;; +0DD2;SINHALA VOWEL SIGN KETTI IS-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD3;SINHALA VOWEL SIGN DIGA IS-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD4;SINHALA VOWEL SIGN KETTI PAA-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD6;SINHALA VOWEL SIGN DIGA PAA-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD8;SINHALA VOWEL SIGN GAETTA-PILLA;Mc;0;L;;;;;N;;;;; +0DD9;SINHALA VOWEL SIGN KOMBUVA;Mc;0;L;;;;;N;;;;; +0DDA;SINHALA VOWEL SIGN DIGA KOMBUVA;Mc;0;L;0DD9 0DCA;;;;N;;;;; +0DDB;SINHALA VOWEL SIGN KOMBU DEKA;Mc;0;L;;;;;N;;;;; +0DDC;SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA;Mc;0;L;0DD9 0DCF;;;;N;;;;; +0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;; +0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;; +0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;; +0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;; +0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;; +0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;; +0E01;THAI CHARACTER KO KAI;Lo;0;L;;;;;N;THAI LETTER KO KAI;;;; +0E02;THAI CHARACTER KHO KHAI;Lo;0;L;;;;;N;THAI LETTER KHO KHAI;;;; +0E03;THAI CHARACTER KHO KHUAT;Lo;0;L;;;;;N;THAI LETTER KHO KHUAT;;;; +0E04;THAI CHARACTER KHO KHWAI;Lo;0;L;;;;;N;THAI LETTER KHO KHWAI;;;; +0E05;THAI CHARACTER KHO KHON;Lo;0;L;;;;;N;THAI LETTER KHO KHON;;;; +0E06;THAI CHARACTER KHO RAKHANG;Lo;0;L;;;;;N;THAI LETTER KHO RAKHANG;;;; +0E07;THAI CHARACTER NGO NGU;Lo;0;L;;;;;N;THAI LETTER NGO NGU;;;; +0E08;THAI CHARACTER CHO CHAN;Lo;0;L;;;;;N;THAI LETTER CHO CHAN;;;; +0E09;THAI CHARACTER CHO CHING;Lo;0;L;;;;;N;THAI LETTER CHO CHING;;;; +0E0A;THAI CHARACTER CHO CHANG;Lo;0;L;;;;;N;THAI LETTER CHO CHANG;;;; +0E0B;THAI CHARACTER SO SO;Lo;0;L;;;;;N;THAI LETTER SO SO;;;; +0E0C;THAI CHARACTER CHO CHOE;Lo;0;L;;;;;N;THAI LETTER CHO CHOE;;;; +0E0D;THAI CHARACTER YO YING;Lo;0;L;;;;;N;THAI LETTER YO YING;;;; +0E0E;THAI CHARACTER DO CHADA;Lo;0;L;;;;;N;THAI LETTER DO CHADA;;;; +0E0F;THAI CHARACTER TO PATAK;Lo;0;L;;;;;N;THAI LETTER TO PATAK;;;; +0E10;THAI CHARACTER THO THAN;Lo;0;L;;;;;N;THAI LETTER THO THAN;;;; +0E11;THAI CHARACTER THO NANGMONTHO;Lo;0;L;;;;;N;THAI LETTER THO NANGMONTHO;;;; +0E12;THAI CHARACTER THO PHUTHAO;Lo;0;L;;;;;N;THAI LETTER THO PHUTHAO;;;; +0E13;THAI CHARACTER NO NEN;Lo;0;L;;;;;N;THAI LETTER NO NEN;;;; +0E14;THAI CHARACTER DO DEK;Lo;0;L;;;;;N;THAI LETTER DO DEK;;;; +0E15;THAI CHARACTER TO TAO;Lo;0;L;;;;;N;THAI LETTER TO TAO;;;; +0E16;THAI CHARACTER THO THUNG;Lo;0;L;;;;;N;THAI LETTER THO THUNG;;;; +0E17;THAI CHARACTER THO THAHAN;Lo;0;L;;;;;N;THAI LETTER THO THAHAN;;;; +0E18;THAI CHARACTER THO THONG;Lo;0;L;;;;;N;THAI LETTER THO THONG;;;; +0E19;THAI CHARACTER NO NU;Lo;0;L;;;;;N;THAI LETTER NO NU;;;; +0E1A;THAI CHARACTER BO BAIMAI;Lo;0;L;;;;;N;THAI LETTER BO BAIMAI;;;; +0E1B;THAI CHARACTER PO PLA;Lo;0;L;;;;;N;THAI LETTER PO PLA;;;; +0E1C;THAI CHARACTER PHO PHUNG;Lo;0;L;;;;;N;THAI LETTER PHO PHUNG;;;; +0E1D;THAI CHARACTER FO FA;Lo;0;L;;;;;N;THAI LETTER FO FA;;;; +0E1E;THAI CHARACTER PHO PHAN;Lo;0;L;;;;;N;THAI LETTER PHO PHAN;;;; +0E1F;THAI CHARACTER FO FAN;Lo;0;L;;;;;N;THAI LETTER FO FAN;;;; +0E20;THAI CHARACTER PHO SAMPHAO;Lo;0;L;;;;;N;THAI LETTER PHO SAMPHAO;;;; +0E21;THAI CHARACTER MO MA;Lo;0;L;;;;;N;THAI LETTER MO MA;;;; +0E22;THAI CHARACTER YO YAK;Lo;0;L;;;;;N;THAI LETTER YO YAK;;;; +0E23;THAI CHARACTER RO RUA;Lo;0;L;;;;;N;THAI LETTER RO RUA;;;; +0E24;THAI CHARACTER RU;Lo;0;L;;;;;N;THAI LETTER RU;;;; +0E25;THAI CHARACTER LO LING;Lo;0;L;;;;;N;THAI LETTER LO LING;;;; +0E26;THAI CHARACTER LU;Lo;0;L;;;;;N;THAI LETTER LU;;;; +0E27;THAI CHARACTER WO WAEN;Lo;0;L;;;;;N;THAI LETTER WO WAEN;;;; +0E28;THAI CHARACTER SO SALA;Lo;0;L;;;;;N;THAI LETTER SO SALA;;;; +0E29;THAI CHARACTER SO RUSI;Lo;0;L;;;;;N;THAI LETTER SO RUSI;;;; +0E2A;THAI CHARACTER SO SUA;Lo;0;L;;;;;N;THAI LETTER SO SUA;;;; +0E2B;THAI CHARACTER HO HIP;Lo;0;L;;;;;N;THAI LETTER HO HIP;;;; +0E2C;THAI CHARACTER LO CHULA;Lo;0;L;;;;;N;THAI LETTER LO CHULA;;;; +0E2D;THAI CHARACTER O ANG;Lo;0;L;;;;;N;THAI LETTER O ANG;;;; +0E2E;THAI CHARACTER HO NOKHUK;Lo;0;L;;;;;N;THAI LETTER HO NOK HUK;;;; +0E2F;THAI CHARACTER PAIYANNOI;Lo;0;L;;;;;N;THAI PAI YAN NOI;paiyan noi;;; +0E30;THAI CHARACTER SARA A;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA A;;;; +0E31;THAI CHARACTER MAI HAN-AKAT;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI HAN-AKAT;;;; +0E32;THAI CHARACTER SARA AA;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AA;;;; +0E33;THAI CHARACTER SARA AM;Lo;0;L;<compat> 0E4D 0E32;;;;N;THAI VOWEL SIGN SARA AM;;;; +0E34;THAI CHARACTER SARA I;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA I;;;; +0E35;THAI CHARACTER SARA II;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA II;;;; +0E36;THAI CHARACTER SARA UE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UE;;;; +0E37;THAI CHARACTER SARA UEE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UEE;sara uue;;; +0E38;THAI CHARACTER SARA U;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA U;;;; +0E39;THAI CHARACTER SARA UU;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA UU;;;; +0E3A;THAI CHARACTER PHINTHU;Mn;9;NSM;;;;;N;THAI VOWEL SIGN PHINTHU;;;; +0E3F;THAI CURRENCY SYMBOL BAHT;Sc;0;ET;;;;;N;THAI BAHT SIGN;;;; +0E40;THAI CHARACTER SARA E;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA E;;;; +0E41;THAI CHARACTER SARA AE;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AE;;;; +0E42;THAI CHARACTER SARA O;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA O;;;; +0E43;THAI CHARACTER SARA AI MAIMUAN;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MUAN;sara ai mai muan;;; +0E44;THAI CHARACTER SARA AI MAIMALAI;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MALAI;sara ai mai malai;;; +0E45;THAI CHARACTER LAKKHANGYAO;Lo;0;L;;;;;N;THAI LAK KHANG YAO;lakkhang yao;;; +0E46;THAI CHARACTER MAIYAMOK;Lm;0;L;;;;;N;THAI MAI YAMOK;mai yamok;;; +0E47;THAI CHARACTER MAITAIKHU;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI TAI KHU;mai taikhu;;; +0E48;THAI CHARACTER MAI EK;Mn;107;NSM;;;;;N;THAI TONE MAI EK;;;; +0E49;THAI CHARACTER MAI THO;Mn;107;NSM;;;;;N;THAI TONE MAI THO;;;; +0E4A;THAI CHARACTER MAI TRI;Mn;107;NSM;;;;;N;THAI TONE MAI TRI;;;; +0E4B;THAI CHARACTER MAI CHATTAWA;Mn;107;NSM;;;;;N;THAI TONE MAI CHATTAWA;;;; +0E4C;THAI CHARACTER THANTHAKHAT;Mn;0;NSM;;;;;N;THAI THANTHAKHAT;;;; +0E4D;THAI CHARACTER NIKHAHIT;Mn;0;NSM;;;;;N;THAI NIKKHAHIT;nikkhahit;;; +0E4E;THAI CHARACTER YAMAKKAN;Mn;0;NSM;;;;;N;THAI YAMAKKAN;;;; +0E4F;THAI CHARACTER FONGMAN;Po;0;L;;;;;N;THAI FONGMAN;;;; +0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0E5A;THAI CHARACTER ANGKHANKHU;Po;0;L;;;;;N;THAI ANGKHANKHU;;;; +0E5B;THAI CHARACTER KHOMUT;Po;0;L;;;;;N;THAI KHOMUT;;;; +0E81;LAO LETTER KO;Lo;0;L;;;;;N;;;;; +0E82;LAO LETTER KHO SUNG;Lo;0;L;;;;;N;;;;; +0E84;LAO LETTER KHO TAM;Lo;0;L;;;;;N;;;;; +0E87;LAO LETTER NGO;Lo;0;L;;;;;N;;;;; +0E88;LAO LETTER CO;Lo;0;L;;;;;N;;;;; +0E8A;LAO LETTER SO TAM;Lo;0;L;;;;;N;;;;; +0E8D;LAO LETTER NYO;Lo;0;L;;;;;N;;;;; +0E94;LAO LETTER DO;Lo;0;L;;;;;N;;;;; +0E95;LAO LETTER TO;Lo;0;L;;;;;N;;;;; +0E96;LAO LETTER THO SUNG;Lo;0;L;;;;;N;;;;; +0E97;LAO LETTER THO TAM;Lo;0;L;;;;;N;;;;; +0E99;LAO LETTER NO;Lo;0;L;;;;;N;;;;; +0E9A;LAO LETTER BO;Lo;0;L;;;;;N;;;;; +0E9B;LAO LETTER PO;Lo;0;L;;;;;N;;;;; +0E9C;LAO LETTER PHO SUNG;Lo;0;L;;;;;N;;;;; +0E9D;LAO LETTER FO TAM;Lo;0;L;;;;;N;;;;; +0E9E;LAO LETTER PHO TAM;Lo;0;L;;;;;N;;;;; +0E9F;LAO LETTER FO SUNG;Lo;0;L;;;;;N;;;;; +0EA1;LAO LETTER MO;Lo;0;L;;;;;N;;;;; +0EA2;LAO LETTER YO;Lo;0;L;;;;;N;;;;; +0EA3;LAO LETTER LO LING;Lo;0;L;;;;;N;;;;; +0EA5;LAO LETTER LO LOOT;Lo;0;L;;;;;N;;;;; +0EA7;LAO LETTER WO;Lo;0;L;;;;;N;;;;; +0EAA;LAO LETTER SO SUNG;Lo;0;L;;;;;N;;;;; +0EAB;LAO LETTER HO SUNG;Lo;0;L;;;;;N;;;;; +0EAD;LAO LETTER O;Lo;0;L;;;;;N;;;;; +0EAE;LAO LETTER HO TAM;Lo;0;L;;;;;N;;;;; +0EAF;LAO ELLIPSIS;Lo;0;L;;;;;N;;;;; +0EB0;LAO VOWEL SIGN A;Lo;0;L;;;;;N;;;;; +0EB1;LAO VOWEL SIGN MAI KAN;Mn;0;NSM;;;;;N;;;;; +0EB2;LAO VOWEL SIGN AA;Lo;0;L;;;;;N;;;;; +0EB3;LAO VOWEL SIGN AM;Lo;0;L;<compat> 0ECD 0EB2;;;;N;;;;; +0EB4;LAO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +0EB5;LAO VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +0EB6;LAO VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;; +0EB7;LAO VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;; +0EB8;LAO VOWEL SIGN U;Mn;118;NSM;;;;;N;;;;; +0EB9;LAO VOWEL SIGN UU;Mn;118;NSM;;;;;N;;;;; +0EBB;LAO VOWEL SIGN MAI KON;Mn;0;NSM;;;;;N;;;;; +0EBC;LAO SEMIVOWEL SIGN LO;Mn;0;NSM;;;;;N;;;;; +0EBD;LAO SEMIVOWEL SIGN NYO;Lo;0;L;;;;;N;;;;; +0EC0;LAO VOWEL SIGN E;Lo;0;L;;;;;N;;;;; +0EC1;LAO VOWEL SIGN EI;Lo;0;L;;;;;N;;;;; +0EC2;LAO VOWEL SIGN O;Lo;0;L;;;;;N;;;;; +0EC3;LAO VOWEL SIGN AY;Lo;0;L;;;;;N;;;;; +0EC4;LAO VOWEL SIGN AI;Lo;0;L;;;;;N;;;;; +0EC6;LAO KO LA;Lm;0;L;;;;;N;;;;; +0EC8;LAO TONE MAI EK;Mn;122;NSM;;;;;N;;;;; +0EC9;LAO TONE MAI THO;Mn;122;NSM;;;;;N;;;;; +0ECA;LAO TONE MAI TI;Mn;122;NSM;;;;;N;;;;; +0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;; +0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;; +0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;; +0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0EDC;LAO HO NO;Lo;0;L;<compat> 0EAB 0E99;;;;N;;;;; +0EDD;LAO HO MO;Lo;0;L;<compat> 0EAB 0EA1;;;;N;;;;; +0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;; +0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;ter yik go a thung;;; +0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;ter yik go wum nam chey ma;;; +0F03;TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA;So;0;L;;;;;N;;ter yik go wum ter tsek ma;;; +0F04;TIBETAN MARK INITIAL YIG MGO MDUN MA;Po;0;L;;;;;N;TIBETAN SINGLE ORNAMENT;yik go dun ma;;; +0F05;TIBETAN MARK CLOSING YIG MGO SGAB MA;Po;0;L;;;;;N;;yik go kab ma;;; +0F06;TIBETAN MARK CARET YIG MGO PHUR SHAD MA;Po;0;L;;;;;N;;yik go pur shey ma;;; +0F07;TIBETAN MARK YIG MGO TSHEG SHAD MA;Po;0;L;;;;;N;;yik go tsek shey ma;;; +0F08;TIBETAN MARK SBRUL SHAD;Po;0;L;;;;;N;TIBETAN RGYANSHAD;drul shey;;; +0F09;TIBETAN MARK BSKUR YIG MGO;Po;0;L;;;;;N;;kur yik go;;; +0F0A;TIBETAN MARK BKA- SHOG YIG MGO;Po;0;L;;;;;N;;ka sho yik go;;; +0F0B;TIBETAN MARK INTERSYLLABIC TSHEG;Po;0;L;;;;;N;TIBETAN TSEG;tsek;;; +0F0C;TIBETAN MARK DELIMITER TSHEG BSTAR;Po;0;L;<noBreak> 0F0B;;;;N;;tsek tar;;; +0F0D;TIBETAN MARK SHAD;Po;0;L;;;;;N;TIBETAN SHAD;shey;;; +0F0E;TIBETAN MARK NYIS SHAD;Po;0;L;;;;;N;TIBETAN DOUBLE SHAD;nyi shey;;; +0F0F;TIBETAN MARK TSHEG SHAD;Po;0;L;;;;;N;;tsek shey;;; +0F10;TIBETAN MARK NYIS TSHEG SHAD;Po;0;L;;;;;N;;nyi tsek shey;;; +0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;rinchen pung shey;;; +0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;gya tram shey;;; +0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;dzu ta me long chen;;; +0F14;TIBETAN MARK GTER TSHEG;So;0;L;;;;;N;TIBETAN COMMA;ter tsek;;; +0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;che ta;;; +0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;hlak ta;;; +0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;trachen char ta;;; +0F18;TIBETAN ASTROLOGICAL SIGN -KHYUD PA;Mn;220;NSM;;;;;N;;kyu pa;;; +0F19;TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS;Mn;220;NSM;;;;;N;;dong tsu;;; +0F1A;TIBETAN SIGN RDEL DKAR GCIG;So;0;L;;;;;N;;deka chig;;; +0F1B;TIBETAN SIGN RDEL DKAR GNYIS;So;0;L;;;;;N;;deka nyi;;; +0F1C;TIBETAN SIGN RDEL DKAR GSUM;So;0;L;;;;;N;;deka sum;;; +0F1D;TIBETAN SIGN RDEL NAG GCIG;So;0;L;;;;;N;;dena chig;;; +0F1E;TIBETAN SIGN RDEL NAG GNYIS;So;0;L;;;;;N;;dena nyi;;; +0F1F;TIBETAN SIGN RDEL DKAR RDEL NAG;So;0;L;;;;;N;;deka dena;;; +0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0F2A;TIBETAN DIGIT HALF ONE;No;0;L;;;;1/2;N;;;;; +0F2B;TIBETAN DIGIT HALF TWO;No;0;L;;;;3/2;N;;;;; +0F2C;TIBETAN DIGIT HALF THREE;No;0;L;;;;5/2;N;;;;; +0F2D;TIBETAN DIGIT HALF FOUR;No;0;L;;;;7/2;N;;;;; +0F2E;TIBETAN DIGIT HALF FIVE;No;0;L;;;;9/2;N;;;;; +0F2F;TIBETAN DIGIT HALF SIX;No;0;L;;;;11/2;N;;;;; +0F30;TIBETAN DIGIT HALF SEVEN;No;0;L;;;;13/2;N;;;;; +0F31;TIBETAN DIGIT HALF EIGHT;No;0;L;;;;15/2;N;;;;; +0F32;TIBETAN DIGIT HALF NINE;No;0;L;;;;17/2;N;;;;; +0F33;TIBETAN DIGIT HALF ZERO;No;0;L;;;;-1/2;N;;;;; +0F34;TIBETAN MARK BSDUS RTAGS;So;0;L;;;;;N;;du ta;;; +0F35;TIBETAN MARK NGAS BZUNG NYI ZLA;Mn;220;NSM;;;;;N;TIBETAN HONORIFIC UNDER RING;nge zung nyi da;;; +0F36;TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN;So;0;L;;;;;N;;dzu ta shi mig chen;;; +0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;nge zung gor ta;;; +0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;che go;;; +0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;tsa tru;;; +0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;N;;gug ta yun;;; +0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;N;;gug ta ye;;; +0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;N;TIBETAN LEFT BRACE;ang kang yun;;; +0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;N;TIBETAN RIGHT BRACE;ang kang ye;;; +0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;yar tse;;; +0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;mar tse;;; +0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;; +0F41;TIBETAN LETTER KHA;Lo;0;L;;;;;N;;;;; +0F42;TIBETAN LETTER GA;Lo;0;L;;;;;N;;;;; +0F43;TIBETAN LETTER GHA;Lo;0;L;0F42 0FB7;;;;N;;;;; +0F44;TIBETAN LETTER NGA;Lo;0;L;;;;;N;;;;; +0F45;TIBETAN LETTER CA;Lo;0;L;;;;;N;;;;; +0F46;TIBETAN LETTER CHA;Lo;0;L;;;;;N;;;;; +0F47;TIBETAN LETTER JA;Lo;0;L;;;;;N;;;;; +0F49;TIBETAN LETTER NYA;Lo;0;L;;;;;N;;;;; +0F4A;TIBETAN LETTER TTA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED TA;;;; +0F4B;TIBETAN LETTER TTHA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED THA;;;; +0F4C;TIBETAN LETTER DDA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED DA;;;; +0F4D;TIBETAN LETTER DDHA;Lo;0;L;0F4C 0FB7;;;;N;;;;; +0F4E;TIBETAN LETTER NNA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED NA;;;; +0F4F;TIBETAN LETTER TA;Lo;0;L;;;;;N;;;;; +0F50;TIBETAN LETTER THA;Lo;0;L;;;;;N;;;;; +0F51;TIBETAN LETTER DA;Lo;0;L;;;;;N;;;;; +0F52;TIBETAN LETTER DHA;Lo;0;L;0F51 0FB7;;;;N;;;;; +0F53;TIBETAN LETTER NA;Lo;0;L;;;;;N;;;;; +0F54;TIBETAN LETTER PA;Lo;0;L;;;;;N;;;;; +0F55;TIBETAN LETTER PHA;Lo;0;L;;;;;N;;;;; +0F56;TIBETAN LETTER BA;Lo;0;L;;;;;N;;;;; +0F57;TIBETAN LETTER BHA;Lo;0;L;0F56 0FB7;;;;N;;;;; +0F58;TIBETAN LETTER MA;Lo;0;L;;;;;N;;;;; +0F59;TIBETAN LETTER TSA;Lo;0;L;;;;;N;;;;; +0F5A;TIBETAN LETTER TSHA;Lo;0;L;;;;;N;;;;; +0F5B;TIBETAN LETTER DZA;Lo;0;L;;;;;N;;;;; +0F5C;TIBETAN LETTER DZHA;Lo;0;L;0F5B 0FB7;;;;N;;;;; +0F5D;TIBETAN LETTER WA;Lo;0;L;;;;;N;;;;; +0F5E;TIBETAN LETTER ZHA;Lo;0;L;;;;;N;;;;; +0F5F;TIBETAN LETTER ZA;Lo;0;L;;;;;N;;;;; +0F60;TIBETAN LETTER -A;Lo;0;L;;;;;N;TIBETAN LETTER AA;;;; +0F61;TIBETAN LETTER YA;Lo;0;L;;;;;N;;;;; +0F62;TIBETAN LETTER RA;Lo;0;L;;;;;N;;*;;; +0F63;TIBETAN LETTER LA;Lo;0;L;;;;;N;;;;; +0F64;TIBETAN LETTER SHA;Lo;0;L;;;;;N;;;;; +0F65;TIBETAN LETTER SSA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED SHA;;;; +0F66;TIBETAN LETTER SA;Lo;0;L;;;;;N;;;;; +0F67;TIBETAN LETTER HA;Lo;0;L;;;;;N;;;;; +0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;; +0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;; +0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;*;;; +0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;; +0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;; +0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;; +0F74;TIBETAN VOWEL SIGN U;Mn;132;NSM;;;;;N;;;;; +0F75;TIBETAN VOWEL SIGN UU;Mn;0;NSM;0F71 0F74;;;;N;;;;; +0F76;TIBETAN VOWEL SIGN VOCALIC R;Mn;0;NSM;0FB2 0F80;;;;N;;;;; +0F77;TIBETAN VOWEL SIGN VOCALIC RR;Mn;0;NSM;<compat> 0FB2 0F81;;;;N;;;;; +0F78;TIBETAN VOWEL SIGN VOCALIC L;Mn;0;NSM;0FB3 0F80;;;;N;;;;; +0F79;TIBETAN VOWEL SIGN VOCALIC LL;Mn;0;NSM;<compat> 0FB3 0F81;;;;N;;;;; +0F7A;TIBETAN VOWEL SIGN E;Mn;130;NSM;;;;;N;;;;; +0F7B;TIBETAN VOWEL SIGN EE;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AI;;;; +0F7C;TIBETAN VOWEL SIGN O;Mn;130;NSM;;;;;N;;;;; +0F7D;TIBETAN VOWEL SIGN OO;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AU;;;; +0F7E;TIBETAN SIGN RJES SU NGA RO;Mn;0;NSM;;;;;N;TIBETAN ANUSVARA;je su nga ro;;; +0F7F;TIBETAN SIGN RNAM BCAD;Mc;0;L;;;;;N;TIBETAN VISARGA;nam chey;;; +0F80;TIBETAN VOWEL SIGN REVERSED I;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN SHORT I;;;; +0F81;TIBETAN VOWEL SIGN REVERSED II;Mn;0;NSM;0F71 0F80;;;;N;;;;; +0F82;TIBETAN SIGN NYI ZLA NAA DA;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU WITH ORNAMENT;nyi da na da;;; +0F83;TIBETAN SIGN SNA LDAN;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU;nan de;;; +0F84;TIBETAN MARK HALANTA;Mn;9;NSM;;;;;N;TIBETAN VIRAMA;;;; +0F85;TIBETAN MARK PALUTA;Po;0;L;;;;;N;TIBETAN CHUCHENYIGE;;;; +0F86;TIBETAN SIGN LCI RTAGS;Mn;230;NSM;;;;;N;;ji ta;;; +0F87;TIBETAN SIGN YANG RTAGS;Mn;230;NSM;;;;;N;;yang ta;;; +0F88;TIBETAN SIGN LCE TSA CAN;Lo;0;L;;;;;N;;che tsa chen;;; +0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;chu chen;;; +0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;tru chen ging;;; +0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;tru me ging;;; +0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;; +0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;; +0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;; +0F93;TIBETAN SUBJOINED LETTER GHA;Mn;0;NSM;0F92 0FB7;;;;N;;;;; +0F94;TIBETAN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;; +0F95;TIBETAN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;; +0F96;TIBETAN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;; +0F97;TIBETAN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;; +0F99;TIBETAN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;; +0F9A;TIBETAN SUBJOINED LETTER TTA;Mn;0;NSM;;;;;N;;;;; +0F9B;TIBETAN SUBJOINED LETTER TTHA;Mn;0;NSM;;;;;N;;;;; +0F9C;TIBETAN SUBJOINED LETTER DDA;Mn;0;NSM;;;;;N;;;;; +0F9D;TIBETAN SUBJOINED LETTER DDHA;Mn;0;NSM;0F9C 0FB7;;;;N;;;;; +0F9E;TIBETAN SUBJOINED LETTER NNA;Mn;0;NSM;;;;;N;;;;; +0F9F;TIBETAN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;; +0FA0;TIBETAN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;; +0FA1;TIBETAN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;; +0FA2;TIBETAN SUBJOINED LETTER DHA;Mn;0;NSM;0FA1 0FB7;;;;N;;;;; +0FA3;TIBETAN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;; +0FA4;TIBETAN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;; +0FA5;TIBETAN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;; +0FA6;TIBETAN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;; +0FA7;TIBETAN SUBJOINED LETTER BHA;Mn;0;NSM;0FA6 0FB7;;;;N;;;;; +0FA8;TIBETAN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;; +0FA9;TIBETAN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;; +0FAA;TIBETAN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;; +0FAB;TIBETAN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;; +0FAC;TIBETAN SUBJOINED LETTER DZHA;Mn;0;NSM;0FAB 0FB7;;;;N;;;;; +0FAD;TIBETAN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;*;;; +0FAE;TIBETAN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;; +0FAF;TIBETAN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;; +0FB0;TIBETAN SUBJOINED LETTER -A;Mn;0;NSM;;;;;N;;;;; +0FB1;TIBETAN SUBJOINED LETTER YA;Mn;0;NSM;;;;;N;;*;;; +0FB2;TIBETAN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;*;;; +0FB3;TIBETAN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;; +0FB4;TIBETAN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;; +0FB5;TIBETAN SUBJOINED LETTER SSA;Mn;0;NSM;;;;;N;;;;; +0FB6;TIBETAN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;; +0FB7;TIBETAN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;; +0FB8;TIBETAN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;; +0FB9;TIBETAN SUBJOINED LETTER KSSA;Mn;0;NSM;0F90 0FB5;;;;N;;;;; +0FBA;TIBETAN SUBJOINED LETTER FIXED-FORM WA;Mn;0;NSM;;;;;N;;*;;; +0FBB;TIBETAN SUBJOINED LETTER FIXED-FORM YA;Mn;0;NSM;;;;;N;;*;;; +0FBC;TIBETAN SUBJOINED LETTER FIXED-FORM RA;Mn;0;NSM;;;;;N;;*;;; +0FBE;TIBETAN KU RU KHA;So;0;L;;;;;N;;kuruka;;; +0FBF;TIBETAN KU RU KHA BZHI MIG CAN;So;0;L;;;;;N;;kuruka shi mik chen;;; +0FC0;TIBETAN CANTILLATION SIGN HEAVY BEAT;So;0;L;;;;;N;;;;; +0FC1;TIBETAN CANTILLATION SIGN LIGHT BEAT;So;0;L;;;;;N;;;;; +0FC2;TIBETAN CANTILLATION SIGN CANG TE-U;So;0;L;;;;;N;;chang tyu;;; +0FC3;TIBETAN CANTILLATION SIGN SBUB -CHAL;So;0;L;;;;;N;;bub chey;;; +0FC4;TIBETAN SYMBOL DRIL BU;So;0;L;;;;;N;;drilbu;;; +0FC5;TIBETAN SYMBOL RDO RJE;So;0;L;;;;;N;;dorje;;; +0FC6;TIBETAN SYMBOL PADMA GDAN;Mn;220;NSM;;;;;N;;pema den;;; +0FC7;TIBETAN SYMBOL RDO RJE RGYA GRAM;So;0;L;;;;;N;;dorje gya dram;;; +0FC8;TIBETAN SYMBOL PHUR PA;So;0;L;;;;;N;;phurba;;; +0FC9;TIBETAN SYMBOL NOR BU;So;0;L;;;;;N;;norbu;;; +0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;norbu nyi khyi;;; +0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;norbu sum khyi;;; +0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;norbu shi khyi;;; +0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;dena sum;;; +1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;; +1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;; +1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;; +1003;MYANMAR LETTER GHA;Lo;0;L;;;;;N;;;;; +1004;MYANMAR LETTER NGA;Lo;0;L;;;;;N;;;;; +1005;MYANMAR LETTER CA;Lo;0;L;;;;;N;;;;; +1006;MYANMAR LETTER CHA;Lo;0;L;;;;;N;;;;; +1007;MYANMAR LETTER JA;Lo;0;L;;;;;N;;;;; +1008;MYANMAR LETTER JHA;Lo;0;L;;;;;N;;;;; +1009;MYANMAR LETTER NYA;Lo;0;L;;;;;N;;;;; +100A;MYANMAR LETTER NNYA;Lo;0;L;;;;;N;;;;; +100B;MYANMAR LETTER TTA;Lo;0;L;;;;;N;;;;; +100C;MYANMAR LETTER TTHA;Lo;0;L;;;;;N;;;;; +100D;MYANMAR LETTER DDA;Lo;0;L;;;;;N;;;;; +100E;MYANMAR LETTER DDHA;Lo;0;L;;;;;N;;;;; +100F;MYANMAR LETTER NNA;Lo;0;L;;;;;N;;;;; +1010;MYANMAR LETTER TA;Lo;0;L;;;;;N;;;;; +1011;MYANMAR LETTER THA;Lo;0;L;;;;;N;;;;; +1012;MYANMAR LETTER DA;Lo;0;L;;;;;N;;;;; +1013;MYANMAR LETTER DHA;Lo;0;L;;;;;N;;;;; +1014;MYANMAR LETTER NA;Lo;0;L;;;;;N;;;;; +1015;MYANMAR LETTER PA;Lo;0;L;;;;;N;;;;; +1016;MYANMAR LETTER PHA;Lo;0;L;;;;;N;;;;; +1017;MYANMAR LETTER BA;Lo;0;L;;;;;N;;;;; +1018;MYANMAR LETTER BHA;Lo;0;L;;;;;N;;;;; +1019;MYANMAR LETTER MA;Lo;0;L;;;;;N;;;;; +101A;MYANMAR LETTER YA;Lo;0;L;;;;;N;;;;; +101B;MYANMAR LETTER RA;Lo;0;L;;;;;N;;;;; +101C;MYANMAR LETTER LA;Lo;0;L;;;;;N;;;;; +101D;MYANMAR LETTER WA;Lo;0;L;;;;;N;;;;; +101E;MYANMAR LETTER SA;Lo;0;L;;;;;N;;;;; +101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;; +1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;; +1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;; +1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;; +1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;; +1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;; +1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;; +1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;; +1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;; +102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;; +102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +102F;MYANMAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;; +1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;; +1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +104A;MYANMAR SIGN LITTLE SECTION;Po;0;L;;;;;N;;;;; +104B;MYANMAR SIGN SECTION;Po;0;L;;;;;N;;;;; +104C;MYANMAR SYMBOL LOCATIVE;Po;0;L;;;;;N;;;;; +104D;MYANMAR SYMBOL COMPLETED;Po;0;L;;;;;N;;;;; +104E;MYANMAR SYMBOL AFOREMENTIONED;Po;0;L;;;;;N;;;;; +104F;MYANMAR SYMBOL GENITIVE;Po;0;L;;;;;N;;;;; +1050;MYANMAR LETTER SHA;Lo;0;L;;;;;N;;;;; +1051;MYANMAR LETTER SSA;Lo;0;L;;;;;N;;;;; +1052;MYANMAR LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +1053;MYANMAR LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +1054;MYANMAR LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1055;MYANMAR LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1056;MYANMAR VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;Khutsuri;;; +10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;Khutsuri;;; +10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;Khutsuri;;; +10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;Khutsuri;;; +10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;Khutsuri;;; +10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;Khutsuri;;; +10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;Khutsuri;;; +10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;Khutsuri;;; +10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;Khutsuri;;; +10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;Khutsuri;;; +10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;Khutsuri;;; +10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;Khutsuri;;; +10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;Khutsuri;;; +10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;Khutsuri;;; +10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;Khutsuri;;; +10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;Khutsuri;;; +10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;Khutsuri;;; +10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;Khutsuri;;; +10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;Khutsuri;;; +10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;Khutsuri;;; +10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;Khutsuri;;; +10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;Khutsuri;;; +10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;Khutsuri;;; +10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;Khutsuri;;; +10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;Khutsuri;;; +10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;Khutsuri;;; +10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;Khutsuri;;; +10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;Khutsuri;;; +10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;Khutsuri;;; +10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;Khutsuri;;; +10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;Khutsuri;;; +10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;Khutsuri;;; +10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;Khutsuri;;; +10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;Khutsuri;;; +10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;Khutsuri;;; +10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;Khutsuri;;; +10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;Khutsuri;;; +10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;Khutsuri;;; +10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;; +10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;; +10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;; +10D3;GEORGIAN LETTER DON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;;; +10D4;GEORGIAN LETTER EN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;;; +10D5;GEORGIAN LETTER VIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;;; +10D6;GEORGIAN LETTER ZEN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;;; +10D7;GEORGIAN LETTER TAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;;; +10D8;GEORGIAN LETTER IN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;;; +10D9;GEORGIAN LETTER KAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;;; +10DA;GEORGIAN LETTER LAS;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;;; +10DB;GEORGIAN LETTER MAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;;; +10DC;GEORGIAN LETTER NAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;;; +10DD;GEORGIAN LETTER ON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;;; +10DE;GEORGIAN LETTER PAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;;; +10DF;GEORGIAN LETTER ZHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;;; +10E0;GEORGIAN LETTER RAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;;; +10E1;GEORGIAN LETTER SAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;;; +10E2;GEORGIAN LETTER TAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;;; +10E3;GEORGIAN LETTER UN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;;; +10E4;GEORGIAN LETTER PHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;;; +10E5;GEORGIAN LETTER KHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;;; +10E6;GEORGIAN LETTER GHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;;; +10E7;GEORGIAN LETTER QAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;;; +10E8;GEORGIAN LETTER SHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;;; +10E9;GEORGIAN LETTER CHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;;; +10EA;GEORGIAN LETTER CAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;;; +10EB;GEORGIAN LETTER JIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;;; +10EC;GEORGIAN LETTER CIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;;; +10ED;GEORGIAN LETTER CHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;;; +10EE;GEORGIAN LETTER XAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;;; +10EF;GEORGIAN LETTER JHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;;; +10F0;GEORGIAN LETTER HAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;;; +10F1;GEORGIAN LETTER HE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;;; +10F2;GEORGIAN LETTER HIE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;;; +10F3;GEORGIAN LETTER WE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;;; +10F4;GEORGIAN LETTER HAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;;; +10F5;GEORGIAN LETTER HOE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;;; +10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;; +10F7;GEORGIAN LETTER YN;Lo;0;L;;;;;N;;;;; +10F8;GEORGIAN LETTER ELIFI;Lo;0;L;;;;;N;;;;; +10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; +1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;; +1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;; +1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;n *;;; +1103;HANGUL CHOSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;; +1104;HANGUL CHOSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;dd *;;; +1105;HANGUL CHOSEONG RIEUL;Lo;0;L;;;;;N;;r *;;; +1106;HANGUL CHOSEONG MIEUM;Lo;0;L;;;;;N;;m *;;; +1107;HANGUL CHOSEONG PIEUP;Lo;0;L;;;;;N;;b *;;; +1108;HANGUL CHOSEONG SSANGPIEUP;Lo;0;L;;;;;N;;bb *;;; +1109;HANGUL CHOSEONG SIOS;Lo;0;L;;;;;N;;s *;;; +110A;HANGUL CHOSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;; +110B;HANGUL CHOSEONG IEUNG;Lo;0;L;;;;;N;;;;; +110C;HANGUL CHOSEONG CIEUC;Lo;0;L;;;;;N;;j *;;; +110D;HANGUL CHOSEONG SSANGCIEUC;Lo;0;L;;;;;N;;jj *;;; +110E;HANGUL CHOSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;; +110F;HANGUL CHOSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;; +1110;HANGUL CHOSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;; +1111;HANGUL CHOSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;; +1112;HANGUL CHOSEONG HIEUH;Lo;0;L;;;;;N;;h *;;; +1113;HANGUL CHOSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;; +1114;HANGUL CHOSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;; +1115;HANGUL CHOSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;; +1116;HANGUL CHOSEONG NIEUN-PIEUP;Lo;0;L;;;;;N;;;;; +1117;HANGUL CHOSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;; +1118;HANGUL CHOSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;; +1119;HANGUL CHOSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;; +111A;HANGUL CHOSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;; +111B;HANGUL CHOSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;; +111C;HANGUL CHOSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;; +111D;HANGUL CHOSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;; +111E;HANGUL CHOSEONG PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;; +111F;HANGUL CHOSEONG PIEUP-NIEUN;Lo;0;L;;;;;N;;;;; +1120;HANGUL CHOSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;; +1121;HANGUL CHOSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;; +1122;HANGUL CHOSEONG PIEUP-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +1123;HANGUL CHOSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +1124;HANGUL CHOSEONG PIEUP-SIOS-PIEUP;Lo;0;L;;;;;N;;;;; +1125;HANGUL CHOSEONG PIEUP-SSANGSIOS;Lo;0;L;;;;;N;;;;; +1126;HANGUL CHOSEONG PIEUP-SIOS-CIEUC;Lo;0;L;;;;;N;;;;; +1127;HANGUL CHOSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;; +1128;HANGUL CHOSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;; +1129;HANGUL CHOSEONG PIEUP-THIEUTH;Lo;0;L;;;;;N;;;;; +112A;HANGUL CHOSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; +112B;HANGUL CHOSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +112C;HANGUL CHOSEONG KAPYEOUNSSANGPIEUP;Lo;0;L;;;;;N;;;;; +112D;HANGUL CHOSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +112E;HANGUL CHOSEONG SIOS-NIEUN;Lo;0;L;;;;;N;;;;; +112F;HANGUL CHOSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +1130;HANGUL CHOSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;; +1131;HANGUL CHOSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;; +1132;HANGUL CHOSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;; +1133;HANGUL CHOSEONG SIOS-PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;; +1134;HANGUL CHOSEONG SIOS-SSANGSIOS;Lo;0;L;;;;;N;;;;; +1135;HANGUL CHOSEONG SIOS-IEUNG;Lo;0;L;;;;;N;;;;; +1136;HANGUL CHOSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;; +1137;HANGUL CHOSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;; +1138;HANGUL CHOSEONG SIOS-KHIEUKH;Lo;0;L;;;;;N;;;;; +1139;HANGUL CHOSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;; +113A;HANGUL CHOSEONG SIOS-PHIEUPH;Lo;0;L;;;;;N;;;;; +113B;HANGUL CHOSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;; +113C;HANGUL CHOSEONG CHITUEUMSIOS;Lo;0;L;;;;;N;;;;; +113D;HANGUL CHOSEONG CHITUEUMSSANGSIOS;Lo;0;L;;;;;N;;;;; +113E;HANGUL CHOSEONG CEONGCHIEUMSIOS;Lo;0;L;;;;;N;;;;; +113F;HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS;Lo;0;L;;;;;N;;;;; +1140;HANGUL CHOSEONG PANSIOS;Lo;0;L;;;;;N;;;;; +1141;HANGUL CHOSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;; +1142;HANGUL CHOSEONG IEUNG-TIKEUT;Lo;0;L;;;;;N;;;;; +1143;HANGUL CHOSEONG IEUNG-MIEUM;Lo;0;L;;;;;N;;;;; +1144;HANGUL CHOSEONG IEUNG-PIEUP;Lo;0;L;;;;;N;;;;; +1145;HANGUL CHOSEONG IEUNG-SIOS;Lo;0;L;;;;;N;;;;; +1146;HANGUL CHOSEONG IEUNG-PANSIOS;Lo;0;L;;;;;N;;;;; +1147;HANGUL CHOSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;; +1148;HANGUL CHOSEONG IEUNG-CIEUC;Lo;0;L;;;;;N;;;;; +1149;HANGUL CHOSEONG IEUNG-CHIEUCH;Lo;0;L;;;;;N;;;;; +114A;HANGUL CHOSEONG IEUNG-THIEUTH;Lo;0;L;;;;;N;;;;; +114B;HANGUL CHOSEONG IEUNG-PHIEUPH;Lo;0;L;;;;;N;;;;; +114C;HANGUL CHOSEONG YESIEUNG;Lo;0;L;;;;;N;;;;; +114D;HANGUL CHOSEONG CIEUC-IEUNG;Lo;0;L;;;;;N;;;;; +114E;HANGUL CHOSEONG CHITUEUMCIEUC;Lo;0;L;;;;;N;;;;; +114F;HANGUL CHOSEONG CHITUEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;; +1150;HANGUL CHOSEONG CEONGCHIEUMCIEUC;Lo;0;L;;;;;N;;;;; +1151;HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;; +1152;HANGUL CHOSEONG CHIEUCH-KHIEUKH;Lo;0;L;;;;;N;;;;; +1153;HANGUL CHOSEONG CHIEUCH-HIEUH;Lo;0;L;;;;;N;;;;; +1154;HANGUL CHOSEONG CHITUEUMCHIEUCH;Lo;0;L;;;;;N;;;;; +1155;HANGUL CHOSEONG CEONGCHIEUMCHIEUCH;Lo;0;L;;;;;N;;;;; +1156;HANGUL CHOSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;; +1157;HANGUL CHOSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;; +1158;HANGUL CHOSEONG SSANGHIEUH;Lo;0;L;;;;;N;;;;; +1159;HANGUL CHOSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;; +115F;HANGUL CHOSEONG FILLER;Lo;0;L;;;;;N;;;;; +1160;HANGUL JUNGSEONG FILLER;Lo;0;L;;;;;N;;;;; +1161;HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;; +1162;HANGUL JUNGSEONG AE;Lo;0;L;;;;;N;;;;; +1163;HANGUL JUNGSEONG YA;Lo;0;L;;;;;N;;;;; +1164;HANGUL JUNGSEONG YAE;Lo;0;L;;;;;N;;;;; +1165;HANGUL JUNGSEONG EO;Lo;0;L;;;;;N;;;;; +1166;HANGUL JUNGSEONG E;Lo;0;L;;;;;N;;;;; +1167;HANGUL JUNGSEONG YEO;Lo;0;L;;;;;N;;;;; +1168;HANGUL JUNGSEONG YE;Lo;0;L;;;;;N;;;;; +1169;HANGUL JUNGSEONG O;Lo;0;L;;;;;N;;;;; +116A;HANGUL JUNGSEONG WA;Lo;0;L;;;;;N;;;;; +116B;HANGUL JUNGSEONG WAE;Lo;0;L;;;;;N;;;;; +116C;HANGUL JUNGSEONG OE;Lo;0;L;;;;;N;;;;; +116D;HANGUL JUNGSEONG YO;Lo;0;L;;;;;N;;;;; +116E;HANGUL JUNGSEONG U;Lo;0;L;;;;;N;;;;; +116F;HANGUL JUNGSEONG WEO;Lo;0;L;;;;;N;;;;; +1170;HANGUL JUNGSEONG WE;Lo;0;L;;;;;N;;;;; +1171;HANGUL JUNGSEONG WI;Lo;0;L;;;;;N;;;;; +1172;HANGUL JUNGSEONG YU;Lo;0;L;;;;;N;;;;; +1173;HANGUL JUNGSEONG EU;Lo;0;L;;;;;N;;;;; +1174;HANGUL JUNGSEONG YI;Lo;0;L;;;;;N;;;;; +1175;HANGUL JUNGSEONG I;Lo;0;L;;;;;N;;;;; +1176;HANGUL JUNGSEONG A-O;Lo;0;L;;;;;N;;;;; +1177;HANGUL JUNGSEONG A-U;Lo;0;L;;;;;N;;;;; +1178;HANGUL JUNGSEONG YA-O;Lo;0;L;;;;;N;;;;; +1179;HANGUL JUNGSEONG YA-YO;Lo;0;L;;;;;N;;;;; +117A;HANGUL JUNGSEONG EO-O;Lo;0;L;;;;;N;;;;; +117B;HANGUL JUNGSEONG EO-U;Lo;0;L;;;;;N;;;;; +117C;HANGUL JUNGSEONG EO-EU;Lo;0;L;;;;;N;;;;; +117D;HANGUL JUNGSEONG YEO-O;Lo;0;L;;;;;N;;;;; +117E;HANGUL JUNGSEONG YEO-U;Lo;0;L;;;;;N;;;;; +117F;HANGUL JUNGSEONG O-EO;Lo;0;L;;;;;N;;;;; +1180;HANGUL JUNGSEONG O-E;Lo;0;L;;;;;N;;;;; +1181;HANGUL JUNGSEONG O-YE;Lo;0;L;;;;;N;;;;; +1182;HANGUL JUNGSEONG O-O;Lo;0;L;;;;;N;;;;; +1183;HANGUL JUNGSEONG O-U;Lo;0;L;;;;;N;;;;; +1184;HANGUL JUNGSEONG YO-YA;Lo;0;L;;;;;N;;;;; +1185;HANGUL JUNGSEONG YO-YAE;Lo;0;L;;;;;N;;;;; +1186;HANGUL JUNGSEONG YO-YEO;Lo;0;L;;;;;N;;;;; +1187;HANGUL JUNGSEONG YO-O;Lo;0;L;;;;;N;;;;; +1188;HANGUL JUNGSEONG YO-I;Lo;0;L;;;;;N;;;;; +1189;HANGUL JUNGSEONG U-A;Lo;0;L;;;;;N;;;;; +118A;HANGUL JUNGSEONG U-AE;Lo;0;L;;;;;N;;;;; +118B;HANGUL JUNGSEONG U-EO-EU;Lo;0;L;;;;;N;;;;; +118C;HANGUL JUNGSEONG U-YE;Lo;0;L;;;;;N;;;;; +118D;HANGUL JUNGSEONG U-U;Lo;0;L;;;;;N;;;;; +118E;HANGUL JUNGSEONG YU-A;Lo;0;L;;;;;N;;;;; +118F;HANGUL JUNGSEONG YU-EO;Lo;0;L;;;;;N;;;;; +1190;HANGUL JUNGSEONG YU-E;Lo;0;L;;;;;N;;;;; +1191;HANGUL JUNGSEONG YU-YEO;Lo;0;L;;;;;N;;;;; +1192;HANGUL JUNGSEONG YU-YE;Lo;0;L;;;;;N;;;;; +1193;HANGUL JUNGSEONG YU-U;Lo;0;L;;;;;N;;;;; +1194;HANGUL JUNGSEONG YU-I;Lo;0;L;;;;;N;;;;; +1195;HANGUL JUNGSEONG EU-U;Lo;0;L;;;;;N;;;;; +1196;HANGUL JUNGSEONG EU-EU;Lo;0;L;;;;;N;;;;; +1197;HANGUL JUNGSEONG YI-U;Lo;0;L;;;;;N;;;;; +1198;HANGUL JUNGSEONG I-A;Lo;0;L;;;;;N;;;;; +1199;HANGUL JUNGSEONG I-YA;Lo;0;L;;;;;N;;;;; +119A;HANGUL JUNGSEONG I-O;Lo;0;L;;;;;N;;;;; +119B;HANGUL JUNGSEONG I-U;Lo;0;L;;;;;N;;;;; +119C;HANGUL JUNGSEONG I-EU;Lo;0;L;;;;;N;;;;; +119D;HANGUL JUNGSEONG I-ARAEA;Lo;0;L;;;;;N;;;;; +119E;HANGUL JUNGSEONG ARAEA;Lo;0;L;;;;;N;;;;; +119F;HANGUL JUNGSEONG ARAEA-EO;Lo;0;L;;;;;N;;;;; +11A0;HANGUL JUNGSEONG ARAEA-U;Lo;0;L;;;;;N;;;;; +11A1;HANGUL JUNGSEONG ARAEA-I;Lo;0;L;;;;;N;;;;; +11A2;HANGUL JUNGSEONG SSANGARAEA;Lo;0;L;;;;;N;;;;; +11A8;HANGUL JONGSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;; +11A9;HANGUL JONGSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;; +11AA;HANGUL JONGSEONG KIYEOK-SIOS;Lo;0;L;;;;;N;;gs *;;; +11AB;HANGUL JONGSEONG NIEUN;Lo;0;L;;;;;N;;n *;;; +11AC;HANGUL JONGSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;nj *;;; +11AD;HANGUL JONGSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;nh *;;; +11AE;HANGUL JONGSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;; +11AF;HANGUL JONGSEONG RIEUL;Lo;0;L;;;;;N;;l *;;; +11B0;HANGUL JONGSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;lg *;;; +11B1;HANGUL JONGSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;lm *;;; +11B2;HANGUL JONGSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;lb *;;; +11B3;HANGUL JONGSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;ls *;;; +11B4;HANGUL JONGSEONG RIEUL-THIEUTH;Lo;0;L;;;;;N;;lt *;;; +11B5;HANGUL JONGSEONG RIEUL-PHIEUPH;Lo;0;L;;;;;N;;lp *;;; +11B6;HANGUL JONGSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;lh *;;; +11B7;HANGUL JONGSEONG MIEUM;Lo;0;L;;;;;N;;m *;;; +11B8;HANGUL JONGSEONG PIEUP;Lo;0;L;;;;;N;;b *;;; +11B9;HANGUL JONGSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;bs *;;; +11BA;HANGUL JONGSEONG SIOS;Lo;0;L;;;;;N;;s *;;; +11BB;HANGUL JONGSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;; +11BC;HANGUL JONGSEONG IEUNG;Lo;0;L;;;;;N;;ng *;;; +11BD;HANGUL JONGSEONG CIEUC;Lo;0;L;;;;;N;;j *;;; +11BE;HANGUL JONGSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;; +11BF;HANGUL JONGSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;; +11C0;HANGUL JONGSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;; +11C1;HANGUL JONGSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;; +11C2;HANGUL JONGSEONG HIEUH;Lo;0;L;;;;;N;;h *;;; +11C3;HANGUL JONGSEONG KIYEOK-RIEUL;Lo;0;L;;;;;N;;;;; +11C4;HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +11C5;HANGUL JONGSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;; +11C6;HANGUL JONGSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;; +11C7;HANGUL JONGSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;; +11C8;HANGUL JONGSEONG NIEUN-PANSIOS;Lo;0;L;;;;;N;;;;; +11C9;HANGUL JONGSEONG NIEUN-THIEUTH;Lo;0;L;;;;;N;;;;; +11CA;HANGUL JONGSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;; +11CB;HANGUL JONGSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;; +11CC;HANGUL JONGSEONG RIEUL-KIYEOK-SIOS;Lo;0;L;;;;;N;;;;; +11CD;HANGUL JONGSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;; +11CE;HANGUL JONGSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;; +11CF;HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH;Lo;0;L;;;;;N;;;;; +11D0;HANGUL JONGSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;; +11D1;HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; +11D2;HANGUL JONGSEONG RIEUL-MIEUM-SIOS;Lo;0;L;;;;;N;;;;; +11D3;HANGUL JONGSEONG RIEUL-PIEUP-SIOS;Lo;0;L;;;;;N;;;;; +11D4;HANGUL JONGSEONG RIEUL-PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; +11D5;HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +11D6;HANGUL JONGSEONG RIEUL-SSANGSIOS;Lo;0;L;;;;;N;;;;; +11D7;HANGUL JONGSEONG RIEUL-PANSIOS;Lo;0;L;;;;;N;;;;; +11D8;HANGUL JONGSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;; +11D9;HANGUL JONGSEONG RIEUL-YEORINHIEUH;Lo;0;L;;;;;N;;;;; +11DA;HANGUL JONGSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; +11DB;HANGUL JONGSEONG MIEUM-RIEUL;Lo;0;L;;;;;N;;;;; +11DC;HANGUL JONGSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;; +11DD;HANGUL JONGSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;; +11DE;HANGUL JONGSEONG MIEUM-SSANGSIOS;Lo;0;L;;;;;N;;;;; +11DF;HANGUL JONGSEONG MIEUM-PANSIOS;Lo;0;L;;;;;N;;;;; +11E0;HANGUL JONGSEONG MIEUM-CHIEUCH;Lo;0;L;;;;;N;;;;; +11E1;HANGUL JONGSEONG MIEUM-HIEUH;Lo;0;L;;;;;N;;;;; +11E2;HANGUL JONGSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;; +11E3;HANGUL JONGSEONG PIEUP-RIEUL;Lo;0;L;;;;;N;;;;; +11E4;HANGUL JONGSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; +11E5;HANGUL JONGSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; +11E6;HANGUL JONGSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +11E7;HANGUL JONGSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +11E8;HANGUL JONGSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +11E9;HANGUL JONGSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;; +11EA;HANGUL JONGSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;; +11EB;HANGUL JONGSEONG PANSIOS;Lo;0;L;;;;;N;;;;; +11EC;HANGUL JONGSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;; +11ED;HANGUL JONGSEONG IEUNG-SSANGKIYEOK;Lo;0;L;;;;;N;;;;; +11EE;HANGUL JONGSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;; +11EF;HANGUL JONGSEONG IEUNG-KHIEUKH;Lo;0;L;;;;;N;;;;; +11F0;HANGUL JONGSEONG YESIEUNG;Lo;0;L;;;;;N;;;;; +11F1;HANGUL JONGSEONG YESIEUNG-SIOS;Lo;0;L;;;;;N;;;;; +11F2;HANGUL JONGSEONG YESIEUNG-PANSIOS;Lo;0;L;;;;;N;;;;; +11F3;HANGUL JONGSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;; +11F4;HANGUL JONGSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;; +11F5;HANGUL JONGSEONG HIEUH-NIEUN;Lo;0;L;;;;;N;;;;; +11F6;HANGUL JONGSEONG HIEUH-RIEUL;Lo;0;L;;;;;N;;;;; +11F7;HANGUL JONGSEONG HIEUH-MIEUM;Lo;0;L;;;;;N;;;;; +11F8;HANGUL JONGSEONG HIEUH-PIEUP;Lo;0;L;;;;;N;;;;; +11F9;HANGUL JONGSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;; +1200;ETHIOPIC SYLLABLE HA;Lo;0;L;;;;;N;;;;; +1201;ETHIOPIC SYLLABLE HU;Lo;0;L;;;;;N;;;;; +1202;ETHIOPIC SYLLABLE HI;Lo;0;L;;;;;N;;;;; +1203;ETHIOPIC SYLLABLE HAA;Lo;0;L;;;;;N;;;;; +1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;; +1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;; +1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;; +1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;; +1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;; +120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;; +120B;ETHIOPIC SYLLABLE LAA;Lo;0;L;;;;;N;;;;; +120C;ETHIOPIC SYLLABLE LEE;Lo;0;L;;;;;N;;;;; +120D;ETHIOPIC SYLLABLE LE;Lo;0;L;;;;;N;;;;; +120E;ETHIOPIC SYLLABLE LO;Lo;0;L;;;;;N;;;;; +120F;ETHIOPIC SYLLABLE LWA;Lo;0;L;;;;;N;;;;; +1210;ETHIOPIC SYLLABLE HHA;Lo;0;L;;;;;N;;;;; +1211;ETHIOPIC SYLLABLE HHU;Lo;0;L;;;;;N;;;;; +1212;ETHIOPIC SYLLABLE HHI;Lo;0;L;;;;;N;;;;; +1213;ETHIOPIC SYLLABLE HHAA;Lo;0;L;;;;;N;;;;; +1214;ETHIOPIC SYLLABLE HHEE;Lo;0;L;;;;;N;;;;; +1215;ETHIOPIC SYLLABLE HHE;Lo;0;L;;;;;N;;;;; +1216;ETHIOPIC SYLLABLE HHO;Lo;0;L;;;;;N;;;;; +1217;ETHIOPIC SYLLABLE HHWA;Lo;0;L;;;;;N;;;;; +1218;ETHIOPIC SYLLABLE MA;Lo;0;L;;;;;N;;;;; +1219;ETHIOPIC SYLLABLE MU;Lo;0;L;;;;;N;;;;; +121A;ETHIOPIC SYLLABLE MI;Lo;0;L;;;;;N;;;;; +121B;ETHIOPIC SYLLABLE MAA;Lo;0;L;;;;;N;;;;; +121C;ETHIOPIC SYLLABLE MEE;Lo;0;L;;;;;N;;;;; +121D;ETHIOPIC SYLLABLE ME;Lo;0;L;;;;;N;;;;; +121E;ETHIOPIC SYLLABLE MO;Lo;0;L;;;;;N;;;;; +121F;ETHIOPIC SYLLABLE MWA;Lo;0;L;;;;;N;;;;; +1220;ETHIOPIC SYLLABLE SZA;Lo;0;L;;;;;N;;;;; +1221;ETHIOPIC SYLLABLE SZU;Lo;0;L;;;;;N;;;;; +1222;ETHIOPIC SYLLABLE SZI;Lo;0;L;;;;;N;;;;; +1223;ETHIOPIC SYLLABLE SZAA;Lo;0;L;;;;;N;;;;; +1224;ETHIOPIC SYLLABLE SZEE;Lo;0;L;;;;;N;;;;; +1225;ETHIOPIC SYLLABLE SZE;Lo;0;L;;;;;N;;;;; +1226;ETHIOPIC SYLLABLE SZO;Lo;0;L;;;;;N;;;;; +1227;ETHIOPIC SYLLABLE SZWA;Lo;0;L;;;;;N;;;;; +1228;ETHIOPIC SYLLABLE RA;Lo;0;L;;;;;N;;;;; +1229;ETHIOPIC SYLLABLE RU;Lo;0;L;;;;;N;;;;; +122A;ETHIOPIC SYLLABLE RI;Lo;0;L;;;;;N;;;;; +122B;ETHIOPIC SYLLABLE RAA;Lo;0;L;;;;;N;;;;; +122C;ETHIOPIC SYLLABLE REE;Lo;0;L;;;;;N;;;;; +122D;ETHIOPIC SYLLABLE RE;Lo;0;L;;;;;N;;;;; +122E;ETHIOPIC SYLLABLE RO;Lo;0;L;;;;;N;;;;; +122F;ETHIOPIC SYLLABLE RWA;Lo;0;L;;;;;N;;;;; +1230;ETHIOPIC SYLLABLE SA;Lo;0;L;;;;;N;;;;; +1231;ETHIOPIC SYLLABLE SU;Lo;0;L;;;;;N;;;;; +1232;ETHIOPIC SYLLABLE SI;Lo;0;L;;;;;N;;;;; +1233;ETHIOPIC SYLLABLE SAA;Lo;0;L;;;;;N;;;;; +1234;ETHIOPIC SYLLABLE SEE;Lo;0;L;;;;;N;;;;; +1235;ETHIOPIC SYLLABLE SE;Lo;0;L;;;;;N;;;;; +1236;ETHIOPIC SYLLABLE SO;Lo;0;L;;;;;N;;;;; +1237;ETHIOPIC SYLLABLE SWA;Lo;0;L;;;;;N;;;;; +1238;ETHIOPIC SYLLABLE SHA;Lo;0;L;;;;;N;;;;; +1239;ETHIOPIC SYLLABLE SHU;Lo;0;L;;;;;N;;;;; +123A;ETHIOPIC SYLLABLE SHI;Lo;0;L;;;;;N;;;;; +123B;ETHIOPIC SYLLABLE SHAA;Lo;0;L;;;;;N;;;;; +123C;ETHIOPIC SYLLABLE SHEE;Lo;0;L;;;;;N;;;;; +123D;ETHIOPIC SYLLABLE SHE;Lo;0;L;;;;;N;;;;; +123E;ETHIOPIC SYLLABLE SHO;Lo;0;L;;;;;N;;;;; +123F;ETHIOPIC SYLLABLE SHWA;Lo;0;L;;;;;N;;;;; +1240;ETHIOPIC SYLLABLE QA;Lo;0;L;;;;;N;;;;; +1241;ETHIOPIC SYLLABLE QU;Lo;0;L;;;;;N;;;;; +1242;ETHIOPIC SYLLABLE QI;Lo;0;L;;;;;N;;;;; +1243;ETHIOPIC SYLLABLE QAA;Lo;0;L;;;;;N;;;;; +1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;; +1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;; +1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;; +1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;; +124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;; +124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;; +124C;ETHIOPIC SYLLABLE QWEE;Lo;0;L;;;;;N;;;;; +124D;ETHIOPIC SYLLABLE QWE;Lo;0;L;;;;;N;;;;; +1250;ETHIOPIC SYLLABLE QHA;Lo;0;L;;;;;N;;;;; +1251;ETHIOPIC SYLLABLE QHU;Lo;0;L;;;;;N;;;;; +1252;ETHIOPIC SYLLABLE QHI;Lo;0;L;;;;;N;;;;; +1253;ETHIOPIC SYLLABLE QHAA;Lo;0;L;;;;;N;;;;; +1254;ETHIOPIC SYLLABLE QHEE;Lo;0;L;;;;;N;;;;; +1255;ETHIOPIC SYLLABLE QHE;Lo;0;L;;;;;N;;;;; +1256;ETHIOPIC SYLLABLE QHO;Lo;0;L;;;;;N;;;;; +1258;ETHIOPIC SYLLABLE QHWA;Lo;0;L;;;;;N;;;;; +125A;ETHIOPIC SYLLABLE QHWI;Lo;0;L;;;;;N;;;;; +125B;ETHIOPIC SYLLABLE QHWAA;Lo;0;L;;;;;N;;;;; +125C;ETHIOPIC SYLLABLE QHWEE;Lo;0;L;;;;;N;;;;; +125D;ETHIOPIC SYLLABLE QHWE;Lo;0;L;;;;;N;;;;; +1260;ETHIOPIC SYLLABLE BA;Lo;0;L;;;;;N;;;;; +1261;ETHIOPIC SYLLABLE BU;Lo;0;L;;;;;N;;;;; +1262;ETHIOPIC SYLLABLE BI;Lo;0;L;;;;;N;;;;; +1263;ETHIOPIC SYLLABLE BAA;Lo;0;L;;;;;N;;;;; +1264;ETHIOPIC SYLLABLE BEE;Lo;0;L;;;;;N;;;;; +1265;ETHIOPIC SYLLABLE BE;Lo;0;L;;;;;N;;;;; +1266;ETHIOPIC SYLLABLE BO;Lo;0;L;;;;;N;;;;; +1267;ETHIOPIC SYLLABLE BWA;Lo;0;L;;;;;N;;;;; +1268;ETHIOPIC SYLLABLE VA;Lo;0;L;;;;;N;;;;; +1269;ETHIOPIC SYLLABLE VU;Lo;0;L;;;;;N;;;;; +126A;ETHIOPIC SYLLABLE VI;Lo;0;L;;;;;N;;;;; +126B;ETHIOPIC SYLLABLE VAA;Lo;0;L;;;;;N;;;;; +126C;ETHIOPIC SYLLABLE VEE;Lo;0;L;;;;;N;;;;; +126D;ETHIOPIC SYLLABLE VE;Lo;0;L;;;;;N;;;;; +126E;ETHIOPIC SYLLABLE VO;Lo;0;L;;;;;N;;;;; +126F;ETHIOPIC SYLLABLE VWA;Lo;0;L;;;;;N;;;;; +1270;ETHIOPIC SYLLABLE TA;Lo;0;L;;;;;N;;;;; +1271;ETHIOPIC SYLLABLE TU;Lo;0;L;;;;;N;;;;; +1272;ETHIOPIC SYLLABLE TI;Lo;0;L;;;;;N;;;;; +1273;ETHIOPIC SYLLABLE TAA;Lo;0;L;;;;;N;;;;; +1274;ETHIOPIC SYLLABLE TEE;Lo;0;L;;;;;N;;;;; +1275;ETHIOPIC SYLLABLE TE;Lo;0;L;;;;;N;;;;; +1276;ETHIOPIC SYLLABLE TO;Lo;0;L;;;;;N;;;;; +1277;ETHIOPIC SYLLABLE TWA;Lo;0;L;;;;;N;;;;; +1278;ETHIOPIC SYLLABLE CA;Lo;0;L;;;;;N;;;;; +1279;ETHIOPIC SYLLABLE CU;Lo;0;L;;;;;N;;;;; +127A;ETHIOPIC SYLLABLE CI;Lo;0;L;;;;;N;;;;; +127B;ETHIOPIC SYLLABLE CAA;Lo;0;L;;;;;N;;;;; +127C;ETHIOPIC SYLLABLE CEE;Lo;0;L;;;;;N;;;;; +127D;ETHIOPIC SYLLABLE CE;Lo;0;L;;;;;N;;;;; +127E;ETHIOPIC SYLLABLE CO;Lo;0;L;;;;;N;;;;; +127F;ETHIOPIC SYLLABLE CWA;Lo;0;L;;;;;N;;;;; +1280;ETHIOPIC SYLLABLE XA;Lo;0;L;;;;;N;;;;; +1281;ETHIOPIC SYLLABLE XU;Lo;0;L;;;;;N;;;;; +1282;ETHIOPIC SYLLABLE XI;Lo;0;L;;;;;N;;;;; +1283;ETHIOPIC SYLLABLE XAA;Lo;0;L;;;;;N;;;;; +1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;; +1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;; +1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;; +1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;; +128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;; +128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;; +128C;ETHIOPIC SYLLABLE XWEE;Lo;0;L;;;;;N;;;;; +128D;ETHIOPIC SYLLABLE XWE;Lo;0;L;;;;;N;;;;; +1290;ETHIOPIC SYLLABLE NA;Lo;0;L;;;;;N;;;;; +1291;ETHIOPIC SYLLABLE NU;Lo;0;L;;;;;N;;;;; +1292;ETHIOPIC SYLLABLE NI;Lo;0;L;;;;;N;;;;; +1293;ETHIOPIC SYLLABLE NAA;Lo;0;L;;;;;N;;;;; +1294;ETHIOPIC SYLLABLE NEE;Lo;0;L;;;;;N;;;;; +1295;ETHIOPIC SYLLABLE NE;Lo;0;L;;;;;N;;;;; +1296;ETHIOPIC SYLLABLE NO;Lo;0;L;;;;;N;;;;; +1297;ETHIOPIC SYLLABLE NWA;Lo;0;L;;;;;N;;;;; +1298;ETHIOPIC SYLLABLE NYA;Lo;0;L;;;;;N;;;;; +1299;ETHIOPIC SYLLABLE NYU;Lo;0;L;;;;;N;;;;; +129A;ETHIOPIC SYLLABLE NYI;Lo;0;L;;;;;N;;;;; +129B;ETHIOPIC SYLLABLE NYAA;Lo;0;L;;;;;N;;;;; +129C;ETHIOPIC SYLLABLE NYEE;Lo;0;L;;;;;N;;;;; +129D;ETHIOPIC SYLLABLE NYE;Lo;0;L;;;;;N;;;;; +129E;ETHIOPIC SYLLABLE NYO;Lo;0;L;;;;;N;;;;; +129F;ETHIOPIC SYLLABLE NYWA;Lo;0;L;;;;;N;;;;; +12A0;ETHIOPIC SYLLABLE GLOTTAL A;Lo;0;L;;;;;N;;;;; +12A1;ETHIOPIC SYLLABLE GLOTTAL U;Lo;0;L;;;;;N;;;;; +12A2;ETHIOPIC SYLLABLE GLOTTAL I;Lo;0;L;;;;;N;;;;; +12A3;ETHIOPIC SYLLABLE GLOTTAL AA;Lo;0;L;;;;;N;;;;; +12A4;ETHIOPIC SYLLABLE GLOTTAL EE;Lo;0;L;;;;;N;;;;; +12A5;ETHIOPIC SYLLABLE GLOTTAL E;Lo;0;L;;;;;N;;;;; +12A6;ETHIOPIC SYLLABLE GLOTTAL O;Lo;0;L;;;;;N;;;;; +12A7;ETHIOPIC SYLLABLE GLOTTAL WA;Lo;0;L;;;;;N;;;;; +12A8;ETHIOPIC SYLLABLE KA;Lo;0;L;;;;;N;;;;; +12A9;ETHIOPIC SYLLABLE KU;Lo;0;L;;;;;N;;;;; +12AA;ETHIOPIC SYLLABLE KI;Lo;0;L;;;;;N;;;;; +12AB;ETHIOPIC SYLLABLE KAA;Lo;0;L;;;;;N;;;;; +12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;; +12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;; +12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;; +12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;; +12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;; +12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;; +12B4;ETHIOPIC SYLLABLE KWEE;Lo;0;L;;;;;N;;;;; +12B5;ETHIOPIC SYLLABLE KWE;Lo;0;L;;;;;N;;;;; +12B8;ETHIOPIC SYLLABLE KXA;Lo;0;L;;;;;N;;;;; +12B9;ETHIOPIC SYLLABLE KXU;Lo;0;L;;;;;N;;;;; +12BA;ETHIOPIC SYLLABLE KXI;Lo;0;L;;;;;N;;;;; +12BB;ETHIOPIC SYLLABLE KXAA;Lo;0;L;;;;;N;;;;; +12BC;ETHIOPIC SYLLABLE KXEE;Lo;0;L;;;;;N;;;;; +12BD;ETHIOPIC SYLLABLE KXE;Lo;0;L;;;;;N;;;;; +12BE;ETHIOPIC SYLLABLE KXO;Lo;0;L;;;;;N;;;;; +12C0;ETHIOPIC SYLLABLE KXWA;Lo;0;L;;;;;N;;;;; +12C2;ETHIOPIC SYLLABLE KXWI;Lo;0;L;;;;;N;;;;; +12C3;ETHIOPIC SYLLABLE KXWAA;Lo;0;L;;;;;N;;;;; +12C4;ETHIOPIC SYLLABLE KXWEE;Lo;0;L;;;;;N;;;;; +12C5;ETHIOPIC SYLLABLE KXWE;Lo;0;L;;;;;N;;;;; +12C8;ETHIOPIC SYLLABLE WA;Lo;0;L;;;;;N;;;;; +12C9;ETHIOPIC SYLLABLE WU;Lo;0;L;;;;;N;;;;; +12CA;ETHIOPIC SYLLABLE WI;Lo;0;L;;;;;N;;;;; +12CB;ETHIOPIC SYLLABLE WAA;Lo;0;L;;;;;N;;;;; +12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;; +12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;; +12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;; +12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;; +12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;; +12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;; +12D3;ETHIOPIC SYLLABLE PHARYNGEAL AA;Lo;0;L;;;;;N;;;;; +12D4;ETHIOPIC SYLLABLE PHARYNGEAL EE;Lo;0;L;;;;;N;;;;; +12D5;ETHIOPIC SYLLABLE PHARYNGEAL E;Lo;0;L;;;;;N;;;;; +12D6;ETHIOPIC SYLLABLE PHARYNGEAL O;Lo;0;L;;;;;N;;;;; +12D8;ETHIOPIC SYLLABLE ZA;Lo;0;L;;;;;N;;;;; +12D9;ETHIOPIC SYLLABLE ZU;Lo;0;L;;;;;N;;;;; +12DA;ETHIOPIC SYLLABLE ZI;Lo;0;L;;;;;N;;;;; +12DB;ETHIOPIC SYLLABLE ZAA;Lo;0;L;;;;;N;;;;; +12DC;ETHIOPIC SYLLABLE ZEE;Lo;0;L;;;;;N;;;;; +12DD;ETHIOPIC SYLLABLE ZE;Lo;0;L;;;;;N;;;;; +12DE;ETHIOPIC SYLLABLE ZO;Lo;0;L;;;;;N;;;;; +12DF;ETHIOPIC SYLLABLE ZWA;Lo;0;L;;;;;N;;;;; +12E0;ETHIOPIC SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; +12E1;ETHIOPIC SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; +12E2;ETHIOPIC SYLLABLE ZHI;Lo;0;L;;;;;N;;;;; +12E3;ETHIOPIC SYLLABLE ZHAA;Lo;0;L;;;;;N;;;;; +12E4;ETHIOPIC SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;; +12E5;ETHIOPIC SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; +12E6;ETHIOPIC SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; +12E7;ETHIOPIC SYLLABLE ZHWA;Lo;0;L;;;;;N;;;;; +12E8;ETHIOPIC SYLLABLE YA;Lo;0;L;;;;;N;;;;; +12E9;ETHIOPIC SYLLABLE YU;Lo;0;L;;;;;N;;;;; +12EA;ETHIOPIC SYLLABLE YI;Lo;0;L;;;;;N;;;;; +12EB;ETHIOPIC SYLLABLE YAA;Lo;0;L;;;;;N;;;;; +12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;; +12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;; +12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;; +12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;; +12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;; +12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;; +12F3;ETHIOPIC SYLLABLE DAA;Lo;0;L;;;;;N;;;;; +12F4;ETHIOPIC SYLLABLE DEE;Lo;0;L;;;;;N;;;;; +12F5;ETHIOPIC SYLLABLE DE;Lo;0;L;;;;;N;;;;; +12F6;ETHIOPIC SYLLABLE DO;Lo;0;L;;;;;N;;;;; +12F7;ETHIOPIC SYLLABLE DWA;Lo;0;L;;;;;N;;;;; +12F8;ETHIOPIC SYLLABLE DDA;Lo;0;L;;;;;N;;;;; +12F9;ETHIOPIC SYLLABLE DDU;Lo;0;L;;;;;N;;;;; +12FA;ETHIOPIC SYLLABLE DDI;Lo;0;L;;;;;N;;;;; +12FB;ETHIOPIC SYLLABLE DDAA;Lo;0;L;;;;;N;;;;; +12FC;ETHIOPIC SYLLABLE DDEE;Lo;0;L;;;;;N;;;;; +12FD;ETHIOPIC SYLLABLE DDE;Lo;0;L;;;;;N;;;;; +12FE;ETHIOPIC SYLLABLE DDO;Lo;0;L;;;;;N;;;;; +12FF;ETHIOPIC SYLLABLE DDWA;Lo;0;L;;;;;N;;;;; +1300;ETHIOPIC SYLLABLE JA;Lo;0;L;;;;;N;;;;; +1301;ETHIOPIC SYLLABLE JU;Lo;0;L;;;;;N;;;;; +1302;ETHIOPIC SYLLABLE JI;Lo;0;L;;;;;N;;;;; +1303;ETHIOPIC SYLLABLE JAA;Lo;0;L;;;;;N;;;;; +1304;ETHIOPIC SYLLABLE JEE;Lo;0;L;;;;;N;;;;; +1305;ETHIOPIC SYLLABLE JE;Lo;0;L;;;;;N;;;;; +1306;ETHIOPIC SYLLABLE JO;Lo;0;L;;;;;N;;;;; +1307;ETHIOPIC SYLLABLE JWA;Lo;0;L;;;;;N;;;;; +1308;ETHIOPIC SYLLABLE GA;Lo;0;L;;;;;N;;;;; +1309;ETHIOPIC SYLLABLE GU;Lo;0;L;;;;;N;;;;; +130A;ETHIOPIC SYLLABLE GI;Lo;0;L;;;;;N;;;;; +130B;ETHIOPIC SYLLABLE GAA;Lo;0;L;;;;;N;;;;; +130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;; +130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;; +130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;; +1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;; +1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;; +1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;; +1314;ETHIOPIC SYLLABLE GWEE;Lo;0;L;;;;;N;;;;; +1315;ETHIOPIC SYLLABLE GWE;Lo;0;L;;;;;N;;;;; +1318;ETHIOPIC SYLLABLE GGA;Lo;0;L;;;;;N;;;;; +1319;ETHIOPIC SYLLABLE GGU;Lo;0;L;;;;;N;;;;; +131A;ETHIOPIC SYLLABLE GGI;Lo;0;L;;;;;N;;;;; +131B;ETHIOPIC SYLLABLE GGAA;Lo;0;L;;;;;N;;;;; +131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;; +131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;; +131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;; +1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;; +1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;; +1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;; +1323;ETHIOPIC SYLLABLE THAA;Lo;0;L;;;;;N;;;;; +1324;ETHIOPIC SYLLABLE THEE;Lo;0;L;;;;;N;;;;; +1325;ETHIOPIC SYLLABLE THE;Lo;0;L;;;;;N;;;;; +1326;ETHIOPIC SYLLABLE THO;Lo;0;L;;;;;N;;;;; +1327;ETHIOPIC SYLLABLE THWA;Lo;0;L;;;;;N;;;;; +1328;ETHIOPIC SYLLABLE CHA;Lo;0;L;;;;;N;;;;; +1329;ETHIOPIC SYLLABLE CHU;Lo;0;L;;;;;N;;;;; +132A;ETHIOPIC SYLLABLE CHI;Lo;0;L;;;;;N;;;;; +132B;ETHIOPIC SYLLABLE CHAA;Lo;0;L;;;;;N;;;;; +132C;ETHIOPIC SYLLABLE CHEE;Lo;0;L;;;;;N;;;;; +132D;ETHIOPIC SYLLABLE CHE;Lo;0;L;;;;;N;;;;; +132E;ETHIOPIC SYLLABLE CHO;Lo;0;L;;;;;N;;;;; +132F;ETHIOPIC SYLLABLE CHWA;Lo;0;L;;;;;N;;;;; +1330;ETHIOPIC SYLLABLE PHA;Lo;0;L;;;;;N;;;;; +1331;ETHIOPIC SYLLABLE PHU;Lo;0;L;;;;;N;;;;; +1332;ETHIOPIC SYLLABLE PHI;Lo;0;L;;;;;N;;;;; +1333;ETHIOPIC SYLLABLE PHAA;Lo;0;L;;;;;N;;;;; +1334;ETHIOPIC SYLLABLE PHEE;Lo;0;L;;;;;N;;;;; +1335;ETHIOPIC SYLLABLE PHE;Lo;0;L;;;;;N;;;;; +1336;ETHIOPIC SYLLABLE PHO;Lo;0;L;;;;;N;;;;; +1337;ETHIOPIC SYLLABLE PHWA;Lo;0;L;;;;;N;;;;; +1338;ETHIOPIC SYLLABLE TSA;Lo;0;L;;;;;N;;;;; +1339;ETHIOPIC SYLLABLE TSU;Lo;0;L;;;;;N;;;;; +133A;ETHIOPIC SYLLABLE TSI;Lo;0;L;;;;;N;;;;; +133B;ETHIOPIC SYLLABLE TSAA;Lo;0;L;;;;;N;;;;; +133C;ETHIOPIC SYLLABLE TSEE;Lo;0;L;;;;;N;;;;; +133D;ETHIOPIC SYLLABLE TSE;Lo;0;L;;;;;N;;;;; +133E;ETHIOPIC SYLLABLE TSO;Lo;0;L;;;;;N;;;;; +133F;ETHIOPIC SYLLABLE TSWA;Lo;0;L;;;;;N;;;;; +1340;ETHIOPIC SYLLABLE TZA;Lo;0;L;;;;;N;;;;; +1341;ETHIOPIC SYLLABLE TZU;Lo;0;L;;;;;N;;;;; +1342;ETHIOPIC SYLLABLE TZI;Lo;0;L;;;;;N;;;;; +1343;ETHIOPIC SYLLABLE TZAA;Lo;0;L;;;;;N;;;;; +1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;; +1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;; +1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;; +1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;; +1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;; +134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;; +134B;ETHIOPIC SYLLABLE FAA;Lo;0;L;;;;;N;;;;; +134C;ETHIOPIC SYLLABLE FEE;Lo;0;L;;;;;N;;;;; +134D;ETHIOPIC SYLLABLE FE;Lo;0;L;;;;;N;;;;; +134E;ETHIOPIC SYLLABLE FO;Lo;0;L;;;;;N;;;;; +134F;ETHIOPIC SYLLABLE FWA;Lo;0;L;;;;;N;;;;; +1350;ETHIOPIC SYLLABLE PA;Lo;0;L;;;;;N;;;;; +1351;ETHIOPIC SYLLABLE PU;Lo;0;L;;;;;N;;;;; +1352;ETHIOPIC SYLLABLE PI;Lo;0;L;;;;;N;;;;; +1353;ETHIOPIC SYLLABLE PAA;Lo;0;L;;;;;N;;;;; +1354;ETHIOPIC SYLLABLE PEE;Lo;0;L;;;;;N;;;;; +1355;ETHIOPIC SYLLABLE PE;Lo;0;L;;;;;N;;;;; +1356;ETHIOPIC SYLLABLE PO;Lo;0;L;;;;;N;;;;; +1357;ETHIOPIC SYLLABLE PWA;Lo;0;L;;;;;N;;;;; +1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;; +1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;; +135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;; +1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;; +1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;; +1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;; +1364;ETHIOPIC SEMICOLON;Po;0;L;;;;;N;;;;; +1365;ETHIOPIC COLON;Po;0;L;;;;;N;;;;; +1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;; +1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;; +1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; +1369;ETHIOPIC DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +136A;ETHIOPIC DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +136B;ETHIOPIC DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +136C;ETHIOPIC DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +136D;ETHIOPIC DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +136E;ETHIOPIC DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +136F;ETHIOPIC DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1370;ETHIOPIC DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1371;ETHIOPIC DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;; +1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;; +1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;; +1375;ETHIOPIC NUMBER FORTY;No;0;L;;;;40;N;;;;; +1376;ETHIOPIC NUMBER FIFTY;No;0;L;;;;50;N;;;;; +1377;ETHIOPIC NUMBER SIXTY;No;0;L;;;;60;N;;;;; +1378;ETHIOPIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +1379;ETHIOPIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;; +137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;; +137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;; +13A0;CHEROKEE LETTER A;Lo;0;L;;;;;N;;;;; +13A1;CHEROKEE LETTER E;Lo;0;L;;;;;N;;;;; +13A2;CHEROKEE LETTER I;Lo;0;L;;;;;N;;;;; +13A3;CHEROKEE LETTER O;Lo;0;L;;;;;N;;;;; +13A4;CHEROKEE LETTER U;Lo;0;L;;;;;N;;;;; +13A5;CHEROKEE LETTER V;Lo;0;L;;;;;N;;;;; +13A6;CHEROKEE LETTER GA;Lo;0;L;;;;;N;;;;; +13A7;CHEROKEE LETTER KA;Lo;0;L;;;;;N;;;;; +13A8;CHEROKEE LETTER GE;Lo;0;L;;;;;N;;;;; +13A9;CHEROKEE LETTER GI;Lo;0;L;;;;;N;;;;; +13AA;CHEROKEE LETTER GO;Lo;0;L;;;;;N;;;;; +13AB;CHEROKEE LETTER GU;Lo;0;L;;;;;N;;;;; +13AC;CHEROKEE LETTER GV;Lo;0;L;;;;;N;;;;; +13AD;CHEROKEE LETTER HA;Lo;0;L;;;;;N;;;;; +13AE;CHEROKEE LETTER HE;Lo;0;L;;;;;N;;;;; +13AF;CHEROKEE LETTER HI;Lo;0;L;;;;;N;;;;; +13B0;CHEROKEE LETTER HO;Lo;0;L;;;;;N;;;;; +13B1;CHEROKEE LETTER HU;Lo;0;L;;;;;N;;;;; +13B2;CHEROKEE LETTER HV;Lo;0;L;;;;;N;;;;; +13B3;CHEROKEE LETTER LA;Lo;0;L;;;;;N;;;;; +13B4;CHEROKEE LETTER LE;Lo;0;L;;;;;N;;;;; +13B5;CHEROKEE LETTER LI;Lo;0;L;;;;;N;;;;; +13B6;CHEROKEE LETTER LO;Lo;0;L;;;;;N;;;;; +13B7;CHEROKEE LETTER LU;Lo;0;L;;;;;N;;;;; +13B8;CHEROKEE LETTER LV;Lo;0;L;;;;;N;;;;; +13B9;CHEROKEE LETTER MA;Lo;0;L;;;;;N;;;;; +13BA;CHEROKEE LETTER ME;Lo;0;L;;;;;N;;;;; +13BB;CHEROKEE LETTER MI;Lo;0;L;;;;;N;;;;; +13BC;CHEROKEE LETTER MO;Lo;0;L;;;;;N;;;;; +13BD;CHEROKEE LETTER MU;Lo;0;L;;;;;N;;;;; +13BE;CHEROKEE LETTER NA;Lo;0;L;;;;;N;;;;; +13BF;CHEROKEE LETTER HNA;Lo;0;L;;;;;N;;;;; +13C0;CHEROKEE LETTER NAH;Lo;0;L;;;;;N;;;;; +13C1;CHEROKEE LETTER NE;Lo;0;L;;;;;N;;;;; +13C2;CHEROKEE LETTER NI;Lo;0;L;;;;;N;;;;; +13C3;CHEROKEE LETTER NO;Lo;0;L;;;;;N;;;;; +13C4;CHEROKEE LETTER NU;Lo;0;L;;;;;N;;;;; +13C5;CHEROKEE LETTER NV;Lo;0;L;;;;;N;;;;; +13C6;CHEROKEE LETTER QUA;Lo;0;L;;;;;N;;;;; +13C7;CHEROKEE LETTER QUE;Lo;0;L;;;;;N;;;;; +13C8;CHEROKEE LETTER QUI;Lo;0;L;;;;;N;;;;; +13C9;CHEROKEE LETTER QUO;Lo;0;L;;;;;N;;;;; +13CA;CHEROKEE LETTER QUU;Lo;0;L;;;;;N;;;;; +13CB;CHEROKEE LETTER QUV;Lo;0;L;;;;;N;;;;; +13CC;CHEROKEE LETTER SA;Lo;0;L;;;;;N;;;;; +13CD;CHEROKEE LETTER S;Lo;0;L;;;;;N;;;;; +13CE;CHEROKEE LETTER SE;Lo;0;L;;;;;N;;;;; +13CF;CHEROKEE LETTER SI;Lo;0;L;;;;;N;;;;; +13D0;CHEROKEE LETTER SO;Lo;0;L;;;;;N;;;;; +13D1;CHEROKEE LETTER SU;Lo;0;L;;;;;N;;;;; +13D2;CHEROKEE LETTER SV;Lo;0;L;;;;;N;;;;; +13D3;CHEROKEE LETTER DA;Lo;0;L;;;;;N;;;;; +13D4;CHEROKEE LETTER TA;Lo;0;L;;;;;N;;;;; +13D5;CHEROKEE LETTER DE;Lo;0;L;;;;;N;;;;; +13D6;CHEROKEE LETTER TE;Lo;0;L;;;;;N;;;;; +13D7;CHEROKEE LETTER DI;Lo;0;L;;;;;N;;;;; +13D8;CHEROKEE LETTER TI;Lo;0;L;;;;;N;;;;; +13D9;CHEROKEE LETTER DO;Lo;0;L;;;;;N;;;;; +13DA;CHEROKEE LETTER DU;Lo;0;L;;;;;N;;;;; +13DB;CHEROKEE LETTER DV;Lo;0;L;;;;;N;;;;; +13DC;CHEROKEE LETTER DLA;Lo;0;L;;;;;N;;;;; +13DD;CHEROKEE LETTER TLA;Lo;0;L;;;;;N;;;;; +13DE;CHEROKEE LETTER TLE;Lo;0;L;;;;;N;;;;; +13DF;CHEROKEE LETTER TLI;Lo;0;L;;;;;N;;;;; +13E0;CHEROKEE LETTER TLO;Lo;0;L;;;;;N;;;;; +13E1;CHEROKEE LETTER TLU;Lo;0;L;;;;;N;;;;; +13E2;CHEROKEE LETTER TLV;Lo;0;L;;;;;N;;;;; +13E3;CHEROKEE LETTER TSA;Lo;0;L;;;;;N;;;;; +13E4;CHEROKEE LETTER TSE;Lo;0;L;;;;;N;;;;; +13E5;CHEROKEE LETTER TSI;Lo;0;L;;;;;N;;;;; +13E6;CHEROKEE LETTER TSO;Lo;0;L;;;;;N;;;;; +13E7;CHEROKEE LETTER TSU;Lo;0;L;;;;;N;;;;; +13E8;CHEROKEE LETTER TSV;Lo;0;L;;;;;N;;;;; +13E9;CHEROKEE LETTER WA;Lo;0;L;;;;;N;;;;; +13EA;CHEROKEE LETTER WE;Lo;0;L;;;;;N;;;;; +13EB;CHEROKEE LETTER WI;Lo;0;L;;;;;N;;;;; +13EC;CHEROKEE LETTER WO;Lo;0;L;;;;;N;;;;; +13ED;CHEROKEE LETTER WU;Lo;0;L;;;;;N;;;;; +13EE;CHEROKEE LETTER WV;Lo;0;L;;;;;N;;;;; +13EF;CHEROKEE LETTER YA;Lo;0;L;;;;;N;;;;; +13F0;CHEROKEE LETTER YE;Lo;0;L;;;;;N;;;;; +13F1;CHEROKEE LETTER YI;Lo;0;L;;;;;N;;;;; +13F2;CHEROKEE LETTER YO;Lo;0;L;;;;;N;;;;; +13F3;CHEROKEE LETTER YU;Lo;0;L;;;;;N;;;;; +13F4;CHEROKEE LETTER YV;Lo;0;L;;;;;N;;;;; +1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;; +1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;; +1403;CANADIAN SYLLABICS I;Lo;0;L;;;;;N;;;;; +1404;CANADIAN SYLLABICS II;Lo;0;L;;;;;N;;;;; +1405;CANADIAN SYLLABICS O;Lo;0;L;;;;;N;;;;; +1406;CANADIAN SYLLABICS OO;Lo;0;L;;;;;N;;;;; +1407;CANADIAN SYLLABICS Y-CREE OO;Lo;0;L;;;;;N;;;;; +1408;CANADIAN SYLLABICS CARRIER EE;Lo;0;L;;;;;N;;;;; +1409;CANADIAN SYLLABICS CARRIER I;Lo;0;L;;;;;N;;;;; +140A;CANADIAN SYLLABICS A;Lo;0;L;;;;;N;;;;; +140B;CANADIAN SYLLABICS AA;Lo;0;L;;;;;N;;;;; +140C;CANADIAN SYLLABICS WE;Lo;0;L;;;;;N;;;;; +140D;CANADIAN SYLLABICS WEST-CREE WE;Lo;0;L;;;;;N;;;;; +140E;CANADIAN SYLLABICS WI;Lo;0;L;;;;;N;;;;; +140F;CANADIAN SYLLABICS WEST-CREE WI;Lo;0;L;;;;;N;;;;; +1410;CANADIAN SYLLABICS WII;Lo;0;L;;;;;N;;;;; +1411;CANADIAN SYLLABICS WEST-CREE WII;Lo;0;L;;;;;N;;;;; +1412;CANADIAN SYLLABICS WO;Lo;0;L;;;;;N;;;;; +1413;CANADIAN SYLLABICS WEST-CREE WO;Lo;0;L;;;;;N;;;;; +1414;CANADIAN SYLLABICS WOO;Lo;0;L;;;;;N;;;;; +1415;CANADIAN SYLLABICS WEST-CREE WOO;Lo;0;L;;;;;N;;;;; +1416;CANADIAN SYLLABICS NASKAPI WOO;Lo;0;L;;;;;N;;;;; +1417;CANADIAN SYLLABICS WA;Lo;0;L;;;;;N;;;;; +1418;CANADIAN SYLLABICS WEST-CREE WA;Lo;0;L;;;;;N;;;;; +1419;CANADIAN SYLLABICS WAA;Lo;0;L;;;;;N;;;;; +141A;CANADIAN SYLLABICS WEST-CREE WAA;Lo;0;L;;;;;N;;;;; +141B;CANADIAN SYLLABICS NASKAPI WAA;Lo;0;L;;;;;N;;;;; +141C;CANADIAN SYLLABICS AI;Lo;0;L;;;;;N;;;;; +141D;CANADIAN SYLLABICS Y-CREE W;Lo;0;L;;;;;N;;;;; +141E;CANADIAN SYLLABICS GLOTTAL STOP;Lo;0;L;;;;;N;;;;; +141F;CANADIAN SYLLABICS FINAL ACUTE;Lo;0;L;;;;;N;;;;; +1420;CANADIAN SYLLABICS FINAL GRAVE;Lo;0;L;;;;;N;;;;; +1421;CANADIAN SYLLABICS FINAL BOTTOM HALF RING;Lo;0;L;;;;;N;;;;; +1422;CANADIAN SYLLABICS FINAL TOP HALF RING;Lo;0;L;;;;;N;;;;; +1423;CANADIAN SYLLABICS FINAL RIGHT HALF RING;Lo;0;L;;;;;N;;;;; +1424;CANADIAN SYLLABICS FINAL RING;Lo;0;L;;;;;N;;;;; +1425;CANADIAN SYLLABICS FINAL DOUBLE ACUTE;Lo;0;L;;;;;N;;;;; +1426;CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES;Lo;0;L;;;;;N;;;;; +1427;CANADIAN SYLLABICS FINAL MIDDLE DOT;Lo;0;L;;;;;N;;;;; +1428;CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE;Lo;0;L;;;;;N;;;;; +1429;CANADIAN SYLLABICS FINAL PLUS;Lo;0;L;;;;;N;;;;; +142A;CANADIAN SYLLABICS FINAL DOWN TACK;Lo;0;L;;;;;N;;;;; +142B;CANADIAN SYLLABICS EN;Lo;0;L;;;;;N;;;;; +142C;CANADIAN SYLLABICS IN;Lo;0;L;;;;;N;;;;; +142D;CANADIAN SYLLABICS ON;Lo;0;L;;;;;N;;;;; +142E;CANADIAN SYLLABICS AN;Lo;0;L;;;;;N;;;;; +142F;CANADIAN SYLLABICS PE;Lo;0;L;;;;;N;;;;; +1430;CANADIAN SYLLABICS PAAI;Lo;0;L;;;;;N;;;;; +1431;CANADIAN SYLLABICS PI;Lo;0;L;;;;;N;;;;; +1432;CANADIAN SYLLABICS PII;Lo;0;L;;;;;N;;;;; +1433;CANADIAN SYLLABICS PO;Lo;0;L;;;;;N;;;;; +1434;CANADIAN SYLLABICS POO;Lo;0;L;;;;;N;;;;; +1435;CANADIAN SYLLABICS Y-CREE POO;Lo;0;L;;;;;N;;;;; +1436;CANADIAN SYLLABICS CARRIER HEE;Lo;0;L;;;;;N;;;;; +1437;CANADIAN SYLLABICS CARRIER HI;Lo;0;L;;;;;N;;;;; +1438;CANADIAN SYLLABICS PA;Lo;0;L;;;;;N;;;;; +1439;CANADIAN SYLLABICS PAA;Lo;0;L;;;;;N;;;;; +143A;CANADIAN SYLLABICS PWE;Lo;0;L;;;;;N;;;;; +143B;CANADIAN SYLLABICS WEST-CREE PWE;Lo;0;L;;;;;N;;;;; +143C;CANADIAN SYLLABICS PWI;Lo;0;L;;;;;N;;;;; +143D;CANADIAN SYLLABICS WEST-CREE PWI;Lo;0;L;;;;;N;;;;; +143E;CANADIAN SYLLABICS PWII;Lo;0;L;;;;;N;;;;; +143F;CANADIAN SYLLABICS WEST-CREE PWII;Lo;0;L;;;;;N;;;;; +1440;CANADIAN SYLLABICS PWO;Lo;0;L;;;;;N;;;;; +1441;CANADIAN SYLLABICS WEST-CREE PWO;Lo;0;L;;;;;N;;;;; +1442;CANADIAN SYLLABICS PWOO;Lo;0;L;;;;;N;;;;; +1443;CANADIAN SYLLABICS WEST-CREE PWOO;Lo;0;L;;;;;N;;;;; +1444;CANADIAN SYLLABICS PWA;Lo;0;L;;;;;N;;;;; +1445;CANADIAN SYLLABICS WEST-CREE PWA;Lo;0;L;;;;;N;;;;; +1446;CANADIAN SYLLABICS PWAA;Lo;0;L;;;;;N;;;;; +1447;CANADIAN SYLLABICS WEST-CREE PWAA;Lo;0;L;;;;;N;;;;; +1448;CANADIAN SYLLABICS Y-CREE PWAA;Lo;0;L;;;;;N;;;;; +1449;CANADIAN SYLLABICS P;Lo;0;L;;;;;N;;;;; +144A;CANADIAN SYLLABICS WEST-CREE P;Lo;0;L;;;;;N;;;;; +144B;CANADIAN SYLLABICS CARRIER H;Lo;0;L;;;;;N;;;;; +144C;CANADIAN SYLLABICS TE;Lo;0;L;;;;;N;;;;; +144D;CANADIAN SYLLABICS TAAI;Lo;0;L;;;;;N;;;;; +144E;CANADIAN SYLLABICS TI;Lo;0;L;;;;;N;;;;; +144F;CANADIAN SYLLABICS TII;Lo;0;L;;;;;N;;;;; +1450;CANADIAN SYLLABICS TO;Lo;0;L;;;;;N;;;;; +1451;CANADIAN SYLLABICS TOO;Lo;0;L;;;;;N;;;;; +1452;CANADIAN SYLLABICS Y-CREE TOO;Lo;0;L;;;;;N;;;;; +1453;CANADIAN SYLLABICS CARRIER DEE;Lo;0;L;;;;;N;;;;; +1454;CANADIAN SYLLABICS CARRIER DI;Lo;0;L;;;;;N;;;;; +1455;CANADIAN SYLLABICS TA;Lo;0;L;;;;;N;;;;; +1456;CANADIAN SYLLABICS TAA;Lo;0;L;;;;;N;;;;; +1457;CANADIAN SYLLABICS TWE;Lo;0;L;;;;;N;;;;; +1458;CANADIAN SYLLABICS WEST-CREE TWE;Lo;0;L;;;;;N;;;;; +1459;CANADIAN SYLLABICS TWI;Lo;0;L;;;;;N;;;;; +145A;CANADIAN SYLLABICS WEST-CREE TWI;Lo;0;L;;;;;N;;;;; +145B;CANADIAN SYLLABICS TWII;Lo;0;L;;;;;N;;;;; +145C;CANADIAN SYLLABICS WEST-CREE TWII;Lo;0;L;;;;;N;;;;; +145D;CANADIAN SYLLABICS TWO;Lo;0;L;;;;;N;;;;; +145E;CANADIAN SYLLABICS WEST-CREE TWO;Lo;0;L;;;;;N;;;;; +145F;CANADIAN SYLLABICS TWOO;Lo;0;L;;;;;N;;;;; +1460;CANADIAN SYLLABICS WEST-CREE TWOO;Lo;0;L;;;;;N;;;;; +1461;CANADIAN SYLLABICS TWA;Lo;0;L;;;;;N;;;;; +1462;CANADIAN SYLLABICS WEST-CREE TWA;Lo;0;L;;;;;N;;;;; +1463;CANADIAN SYLLABICS TWAA;Lo;0;L;;;;;N;;;;; +1464;CANADIAN SYLLABICS WEST-CREE TWAA;Lo;0;L;;;;;N;;;;; +1465;CANADIAN SYLLABICS NASKAPI TWAA;Lo;0;L;;;;;N;;;;; +1466;CANADIAN SYLLABICS T;Lo;0;L;;;;;N;;;;; +1467;CANADIAN SYLLABICS TTE;Lo;0;L;;;;;N;;;;; +1468;CANADIAN SYLLABICS TTI;Lo;0;L;;;;;N;;;;; +1469;CANADIAN SYLLABICS TTO;Lo;0;L;;;;;N;;;;; +146A;CANADIAN SYLLABICS TTA;Lo;0;L;;;;;N;;;;; +146B;CANADIAN SYLLABICS KE;Lo;0;L;;;;;N;;;;; +146C;CANADIAN SYLLABICS KAAI;Lo;0;L;;;;;N;;;;; +146D;CANADIAN SYLLABICS KI;Lo;0;L;;;;;N;;;;; +146E;CANADIAN SYLLABICS KII;Lo;0;L;;;;;N;;;;; +146F;CANADIAN SYLLABICS KO;Lo;0;L;;;;;N;;;;; +1470;CANADIAN SYLLABICS KOO;Lo;0;L;;;;;N;;;;; +1471;CANADIAN SYLLABICS Y-CREE KOO;Lo;0;L;;;;;N;;;;; +1472;CANADIAN SYLLABICS KA;Lo;0;L;;;;;N;;;;; +1473;CANADIAN SYLLABICS KAA;Lo;0;L;;;;;N;;;;; +1474;CANADIAN SYLLABICS KWE;Lo;0;L;;;;;N;;;;; +1475;CANADIAN SYLLABICS WEST-CREE KWE;Lo;0;L;;;;;N;;;;; +1476;CANADIAN SYLLABICS KWI;Lo;0;L;;;;;N;;;;; +1477;CANADIAN SYLLABICS WEST-CREE KWI;Lo;0;L;;;;;N;;;;; +1478;CANADIAN SYLLABICS KWII;Lo;0;L;;;;;N;;;;; +1479;CANADIAN SYLLABICS WEST-CREE KWII;Lo;0;L;;;;;N;;;;; +147A;CANADIAN SYLLABICS KWO;Lo;0;L;;;;;N;;;;; +147B;CANADIAN SYLLABICS WEST-CREE KWO;Lo;0;L;;;;;N;;;;; +147C;CANADIAN SYLLABICS KWOO;Lo;0;L;;;;;N;;;;; +147D;CANADIAN SYLLABICS WEST-CREE KWOO;Lo;0;L;;;;;N;;;;; +147E;CANADIAN SYLLABICS KWA;Lo;0;L;;;;;N;;;;; +147F;CANADIAN SYLLABICS WEST-CREE KWA;Lo;0;L;;;;;N;;;;; +1480;CANADIAN SYLLABICS KWAA;Lo;0;L;;;;;N;;;;; +1481;CANADIAN SYLLABICS WEST-CREE KWAA;Lo;0;L;;;;;N;;;;; +1482;CANADIAN SYLLABICS NASKAPI KWAA;Lo;0;L;;;;;N;;;;; +1483;CANADIAN SYLLABICS K;Lo;0;L;;;;;N;;;;; +1484;CANADIAN SYLLABICS KW;Lo;0;L;;;;;N;;;;; +1485;CANADIAN SYLLABICS SOUTH-SLAVEY KEH;Lo;0;L;;;;;N;;;;; +1486;CANADIAN SYLLABICS SOUTH-SLAVEY KIH;Lo;0;L;;;;;N;;;;; +1487;CANADIAN SYLLABICS SOUTH-SLAVEY KOH;Lo;0;L;;;;;N;;;;; +1488;CANADIAN SYLLABICS SOUTH-SLAVEY KAH;Lo;0;L;;;;;N;;;;; +1489;CANADIAN SYLLABICS CE;Lo;0;L;;;;;N;;;;; +148A;CANADIAN SYLLABICS CAAI;Lo;0;L;;;;;N;;;;; +148B;CANADIAN SYLLABICS CI;Lo;0;L;;;;;N;;;;; +148C;CANADIAN SYLLABICS CII;Lo;0;L;;;;;N;;;;; +148D;CANADIAN SYLLABICS CO;Lo;0;L;;;;;N;;;;; +148E;CANADIAN SYLLABICS COO;Lo;0;L;;;;;N;;;;; +148F;CANADIAN SYLLABICS Y-CREE COO;Lo;0;L;;;;;N;;;;; +1490;CANADIAN SYLLABICS CA;Lo;0;L;;;;;N;;;;; +1491;CANADIAN SYLLABICS CAA;Lo;0;L;;;;;N;;;;; +1492;CANADIAN SYLLABICS CWE;Lo;0;L;;;;;N;;;;; +1493;CANADIAN SYLLABICS WEST-CREE CWE;Lo;0;L;;;;;N;;;;; +1494;CANADIAN SYLLABICS CWI;Lo;0;L;;;;;N;;;;; +1495;CANADIAN SYLLABICS WEST-CREE CWI;Lo;0;L;;;;;N;;;;; +1496;CANADIAN SYLLABICS CWII;Lo;0;L;;;;;N;;;;; +1497;CANADIAN SYLLABICS WEST-CREE CWII;Lo;0;L;;;;;N;;;;; +1498;CANADIAN SYLLABICS CWO;Lo;0;L;;;;;N;;;;; +1499;CANADIAN SYLLABICS WEST-CREE CWO;Lo;0;L;;;;;N;;;;; +149A;CANADIAN SYLLABICS CWOO;Lo;0;L;;;;;N;;;;; +149B;CANADIAN SYLLABICS WEST-CREE CWOO;Lo;0;L;;;;;N;;;;; +149C;CANADIAN SYLLABICS CWA;Lo;0;L;;;;;N;;;;; +149D;CANADIAN SYLLABICS WEST-CREE CWA;Lo;0;L;;;;;N;;;;; +149E;CANADIAN SYLLABICS CWAA;Lo;0;L;;;;;N;;;;; +149F;CANADIAN SYLLABICS WEST-CREE CWAA;Lo;0;L;;;;;N;;;;; +14A0;CANADIAN SYLLABICS NASKAPI CWAA;Lo;0;L;;;;;N;;;;; +14A1;CANADIAN SYLLABICS C;Lo;0;L;;;;;N;;;;; +14A2;CANADIAN SYLLABICS SAYISI TH;Lo;0;L;;;;;N;;;;; +14A3;CANADIAN SYLLABICS ME;Lo;0;L;;;;;N;;;;; +14A4;CANADIAN SYLLABICS MAAI;Lo;0;L;;;;;N;;;;; +14A5;CANADIAN SYLLABICS MI;Lo;0;L;;;;;N;;;;; +14A6;CANADIAN SYLLABICS MII;Lo;0;L;;;;;N;;;;; +14A7;CANADIAN SYLLABICS MO;Lo;0;L;;;;;N;;;;; +14A8;CANADIAN SYLLABICS MOO;Lo;0;L;;;;;N;;;;; +14A9;CANADIAN SYLLABICS Y-CREE MOO;Lo;0;L;;;;;N;;;;; +14AA;CANADIAN SYLLABICS MA;Lo;0;L;;;;;N;;;;; +14AB;CANADIAN SYLLABICS MAA;Lo;0;L;;;;;N;;;;; +14AC;CANADIAN SYLLABICS MWE;Lo;0;L;;;;;N;;;;; +14AD;CANADIAN SYLLABICS WEST-CREE MWE;Lo;0;L;;;;;N;;;;; +14AE;CANADIAN SYLLABICS MWI;Lo;0;L;;;;;N;;;;; +14AF;CANADIAN SYLLABICS WEST-CREE MWI;Lo;0;L;;;;;N;;;;; +14B0;CANADIAN SYLLABICS MWII;Lo;0;L;;;;;N;;;;; +14B1;CANADIAN SYLLABICS WEST-CREE MWII;Lo;0;L;;;;;N;;;;; +14B2;CANADIAN SYLLABICS MWO;Lo;0;L;;;;;N;;;;; +14B3;CANADIAN SYLLABICS WEST-CREE MWO;Lo;0;L;;;;;N;;;;; +14B4;CANADIAN SYLLABICS MWOO;Lo;0;L;;;;;N;;;;; +14B5;CANADIAN SYLLABICS WEST-CREE MWOO;Lo;0;L;;;;;N;;;;; +14B6;CANADIAN SYLLABICS MWA;Lo;0;L;;;;;N;;;;; +14B7;CANADIAN SYLLABICS WEST-CREE MWA;Lo;0;L;;;;;N;;;;; +14B8;CANADIAN SYLLABICS MWAA;Lo;0;L;;;;;N;;;;; +14B9;CANADIAN SYLLABICS WEST-CREE MWAA;Lo;0;L;;;;;N;;;;; +14BA;CANADIAN SYLLABICS NASKAPI MWAA;Lo;0;L;;;;;N;;;;; +14BB;CANADIAN SYLLABICS M;Lo;0;L;;;;;N;;;;; +14BC;CANADIAN SYLLABICS WEST-CREE M;Lo;0;L;;;;;N;;;;; +14BD;CANADIAN SYLLABICS MH;Lo;0;L;;;;;N;;;;; +14BE;CANADIAN SYLLABICS ATHAPASCAN M;Lo;0;L;;;;;N;;;;; +14BF;CANADIAN SYLLABICS SAYISI M;Lo;0;L;;;;;N;;;;; +14C0;CANADIAN SYLLABICS NE;Lo;0;L;;;;;N;;;;; +14C1;CANADIAN SYLLABICS NAAI;Lo;0;L;;;;;N;;;;; +14C2;CANADIAN SYLLABICS NI;Lo;0;L;;;;;N;;;;; +14C3;CANADIAN SYLLABICS NII;Lo;0;L;;;;;N;;;;; +14C4;CANADIAN SYLLABICS NO;Lo;0;L;;;;;N;;;;; +14C5;CANADIAN SYLLABICS NOO;Lo;0;L;;;;;N;;;;; +14C6;CANADIAN SYLLABICS Y-CREE NOO;Lo;0;L;;;;;N;;;;; +14C7;CANADIAN SYLLABICS NA;Lo;0;L;;;;;N;;;;; +14C8;CANADIAN SYLLABICS NAA;Lo;0;L;;;;;N;;;;; +14C9;CANADIAN SYLLABICS NWE;Lo;0;L;;;;;N;;;;; +14CA;CANADIAN SYLLABICS WEST-CREE NWE;Lo;0;L;;;;;N;;;;; +14CB;CANADIAN SYLLABICS NWA;Lo;0;L;;;;;N;;;;; +14CC;CANADIAN SYLLABICS WEST-CREE NWA;Lo;0;L;;;;;N;;;;; +14CD;CANADIAN SYLLABICS NWAA;Lo;0;L;;;;;N;;;;; +14CE;CANADIAN SYLLABICS WEST-CREE NWAA;Lo;0;L;;;;;N;;;;; +14CF;CANADIAN SYLLABICS NASKAPI NWAA;Lo;0;L;;;;;N;;;;; +14D0;CANADIAN SYLLABICS N;Lo;0;L;;;;;N;;;;; +14D1;CANADIAN SYLLABICS CARRIER NG;Lo;0;L;;;;;N;;;;; +14D2;CANADIAN SYLLABICS NH;Lo;0;L;;;;;N;;;;; +14D3;CANADIAN SYLLABICS LE;Lo;0;L;;;;;N;;;;; +14D4;CANADIAN SYLLABICS LAAI;Lo;0;L;;;;;N;;;;; +14D5;CANADIAN SYLLABICS LI;Lo;0;L;;;;;N;;;;; +14D6;CANADIAN SYLLABICS LII;Lo;0;L;;;;;N;;;;; +14D7;CANADIAN SYLLABICS LO;Lo;0;L;;;;;N;;;;; +14D8;CANADIAN SYLLABICS LOO;Lo;0;L;;;;;N;;;;; +14D9;CANADIAN SYLLABICS Y-CREE LOO;Lo;0;L;;;;;N;;;;; +14DA;CANADIAN SYLLABICS LA;Lo;0;L;;;;;N;;;;; +14DB;CANADIAN SYLLABICS LAA;Lo;0;L;;;;;N;;;;; +14DC;CANADIAN SYLLABICS LWE;Lo;0;L;;;;;N;;;;; +14DD;CANADIAN SYLLABICS WEST-CREE LWE;Lo;0;L;;;;;N;;;;; +14DE;CANADIAN SYLLABICS LWI;Lo;0;L;;;;;N;;;;; +14DF;CANADIAN SYLLABICS WEST-CREE LWI;Lo;0;L;;;;;N;;;;; +14E0;CANADIAN SYLLABICS LWII;Lo;0;L;;;;;N;;;;; +14E1;CANADIAN SYLLABICS WEST-CREE LWII;Lo;0;L;;;;;N;;;;; +14E2;CANADIAN SYLLABICS LWO;Lo;0;L;;;;;N;;;;; +14E3;CANADIAN SYLLABICS WEST-CREE LWO;Lo;0;L;;;;;N;;;;; +14E4;CANADIAN SYLLABICS LWOO;Lo;0;L;;;;;N;;;;; +14E5;CANADIAN SYLLABICS WEST-CREE LWOO;Lo;0;L;;;;;N;;;;; +14E6;CANADIAN SYLLABICS LWA;Lo;0;L;;;;;N;;;;; +14E7;CANADIAN SYLLABICS WEST-CREE LWA;Lo;0;L;;;;;N;;;;; +14E8;CANADIAN SYLLABICS LWAA;Lo;0;L;;;;;N;;;;; +14E9;CANADIAN SYLLABICS WEST-CREE LWAA;Lo;0;L;;;;;N;;;;; +14EA;CANADIAN SYLLABICS L;Lo;0;L;;;;;N;;;;; +14EB;CANADIAN SYLLABICS WEST-CREE L;Lo;0;L;;;;;N;;;;; +14EC;CANADIAN SYLLABICS MEDIAL L;Lo;0;L;;;;;N;;;;; +14ED;CANADIAN SYLLABICS SE;Lo;0;L;;;;;N;;;;; +14EE;CANADIAN SYLLABICS SAAI;Lo;0;L;;;;;N;;;;; +14EF;CANADIAN SYLLABICS SI;Lo;0;L;;;;;N;;;;; +14F0;CANADIAN SYLLABICS SII;Lo;0;L;;;;;N;;;;; +14F1;CANADIAN SYLLABICS SO;Lo;0;L;;;;;N;;;;; +14F2;CANADIAN SYLLABICS SOO;Lo;0;L;;;;;N;;;;; +14F3;CANADIAN SYLLABICS Y-CREE SOO;Lo;0;L;;;;;N;;;;; +14F4;CANADIAN SYLLABICS SA;Lo;0;L;;;;;N;;;;; +14F5;CANADIAN SYLLABICS SAA;Lo;0;L;;;;;N;;;;; +14F6;CANADIAN SYLLABICS SWE;Lo;0;L;;;;;N;;;;; +14F7;CANADIAN SYLLABICS WEST-CREE SWE;Lo;0;L;;;;;N;;;;; +14F8;CANADIAN SYLLABICS SWI;Lo;0;L;;;;;N;;;;; +14F9;CANADIAN SYLLABICS WEST-CREE SWI;Lo;0;L;;;;;N;;;;; +14FA;CANADIAN SYLLABICS SWII;Lo;0;L;;;;;N;;;;; +14FB;CANADIAN SYLLABICS WEST-CREE SWII;Lo;0;L;;;;;N;;;;; +14FC;CANADIAN SYLLABICS SWO;Lo;0;L;;;;;N;;;;; +14FD;CANADIAN SYLLABICS WEST-CREE SWO;Lo;0;L;;;;;N;;;;; +14FE;CANADIAN SYLLABICS SWOO;Lo;0;L;;;;;N;;;;; +14FF;CANADIAN SYLLABICS WEST-CREE SWOO;Lo;0;L;;;;;N;;;;; +1500;CANADIAN SYLLABICS SWA;Lo;0;L;;;;;N;;;;; +1501;CANADIAN SYLLABICS WEST-CREE SWA;Lo;0;L;;;;;N;;;;; +1502;CANADIAN SYLLABICS SWAA;Lo;0;L;;;;;N;;;;; +1503;CANADIAN SYLLABICS WEST-CREE SWAA;Lo;0;L;;;;;N;;;;; +1504;CANADIAN SYLLABICS NASKAPI SWAA;Lo;0;L;;;;;N;;;;; +1505;CANADIAN SYLLABICS S;Lo;0;L;;;;;N;;;;; +1506;CANADIAN SYLLABICS ATHAPASCAN S;Lo;0;L;;;;;N;;;;; +1507;CANADIAN SYLLABICS SW;Lo;0;L;;;;;N;;;;; +1508;CANADIAN SYLLABICS BLACKFOOT S;Lo;0;L;;;;;N;;;;; +1509;CANADIAN SYLLABICS MOOSE-CREE SK;Lo;0;L;;;;;N;;;;; +150A;CANADIAN SYLLABICS NASKAPI SKW;Lo;0;L;;;;;N;;;;; +150B;CANADIAN SYLLABICS NASKAPI S-W;Lo;0;L;;;;;N;;;;; +150C;CANADIAN SYLLABICS NASKAPI SPWA;Lo;0;L;;;;;N;;;;; +150D;CANADIAN SYLLABICS NASKAPI STWA;Lo;0;L;;;;;N;;;;; +150E;CANADIAN SYLLABICS NASKAPI SKWA;Lo;0;L;;;;;N;;;;; +150F;CANADIAN SYLLABICS NASKAPI SCWA;Lo;0;L;;;;;N;;;;; +1510;CANADIAN SYLLABICS SHE;Lo;0;L;;;;;N;;;;; +1511;CANADIAN SYLLABICS SHI;Lo;0;L;;;;;N;;;;; +1512;CANADIAN SYLLABICS SHII;Lo;0;L;;;;;N;;;;; +1513;CANADIAN SYLLABICS SHO;Lo;0;L;;;;;N;;;;; +1514;CANADIAN SYLLABICS SHOO;Lo;0;L;;;;;N;;;;; +1515;CANADIAN SYLLABICS SHA;Lo;0;L;;;;;N;;;;; +1516;CANADIAN SYLLABICS SHAA;Lo;0;L;;;;;N;;;;; +1517;CANADIAN SYLLABICS SHWE;Lo;0;L;;;;;N;;;;; +1518;CANADIAN SYLLABICS WEST-CREE SHWE;Lo;0;L;;;;;N;;;;; +1519;CANADIAN SYLLABICS SHWI;Lo;0;L;;;;;N;;;;; +151A;CANADIAN SYLLABICS WEST-CREE SHWI;Lo;0;L;;;;;N;;;;; +151B;CANADIAN SYLLABICS SHWII;Lo;0;L;;;;;N;;;;; +151C;CANADIAN SYLLABICS WEST-CREE SHWII;Lo;0;L;;;;;N;;;;; +151D;CANADIAN SYLLABICS SHWO;Lo;0;L;;;;;N;;;;; +151E;CANADIAN SYLLABICS WEST-CREE SHWO;Lo;0;L;;;;;N;;;;; +151F;CANADIAN SYLLABICS SHWOO;Lo;0;L;;;;;N;;;;; +1520;CANADIAN SYLLABICS WEST-CREE SHWOO;Lo;0;L;;;;;N;;;;; +1521;CANADIAN SYLLABICS SHWA;Lo;0;L;;;;;N;;;;; +1522;CANADIAN SYLLABICS WEST-CREE SHWA;Lo;0;L;;;;;N;;;;; +1523;CANADIAN SYLLABICS SHWAA;Lo;0;L;;;;;N;;;;; +1524;CANADIAN SYLLABICS WEST-CREE SHWAA;Lo;0;L;;;;;N;;;;; +1525;CANADIAN SYLLABICS SH;Lo;0;L;;;;;N;;;;; +1526;CANADIAN SYLLABICS YE;Lo;0;L;;;;;N;;;;; +1527;CANADIAN SYLLABICS YAAI;Lo;0;L;;;;;N;;;;; +1528;CANADIAN SYLLABICS YI;Lo;0;L;;;;;N;;;;; +1529;CANADIAN SYLLABICS YII;Lo;0;L;;;;;N;;;;; +152A;CANADIAN SYLLABICS YO;Lo;0;L;;;;;N;;;;; +152B;CANADIAN SYLLABICS YOO;Lo;0;L;;;;;N;;;;; +152C;CANADIAN SYLLABICS Y-CREE YOO;Lo;0;L;;;;;N;;;;; +152D;CANADIAN SYLLABICS YA;Lo;0;L;;;;;N;;;;; +152E;CANADIAN SYLLABICS YAA;Lo;0;L;;;;;N;;;;; +152F;CANADIAN SYLLABICS YWE;Lo;0;L;;;;;N;;;;; +1530;CANADIAN SYLLABICS WEST-CREE YWE;Lo;0;L;;;;;N;;;;; +1531;CANADIAN SYLLABICS YWI;Lo;0;L;;;;;N;;;;; +1532;CANADIAN SYLLABICS WEST-CREE YWI;Lo;0;L;;;;;N;;;;; +1533;CANADIAN SYLLABICS YWII;Lo;0;L;;;;;N;;;;; +1534;CANADIAN SYLLABICS WEST-CREE YWII;Lo;0;L;;;;;N;;;;; +1535;CANADIAN SYLLABICS YWO;Lo;0;L;;;;;N;;;;; +1536;CANADIAN SYLLABICS WEST-CREE YWO;Lo;0;L;;;;;N;;;;; +1537;CANADIAN SYLLABICS YWOO;Lo;0;L;;;;;N;;;;; +1538;CANADIAN SYLLABICS WEST-CREE YWOO;Lo;0;L;;;;;N;;;;; +1539;CANADIAN SYLLABICS YWA;Lo;0;L;;;;;N;;;;; +153A;CANADIAN SYLLABICS WEST-CREE YWA;Lo;0;L;;;;;N;;;;; +153B;CANADIAN SYLLABICS YWAA;Lo;0;L;;;;;N;;;;; +153C;CANADIAN SYLLABICS WEST-CREE YWAA;Lo;0;L;;;;;N;;;;; +153D;CANADIAN SYLLABICS NASKAPI YWAA;Lo;0;L;;;;;N;;;;; +153E;CANADIAN SYLLABICS Y;Lo;0;L;;;;;N;;;;; +153F;CANADIAN SYLLABICS BIBLE-CREE Y;Lo;0;L;;;;;N;;;;; +1540;CANADIAN SYLLABICS WEST-CREE Y;Lo;0;L;;;;;N;;;;; +1541;CANADIAN SYLLABICS SAYISI YI;Lo;0;L;;;;;N;;;;; +1542;CANADIAN SYLLABICS RE;Lo;0;L;;;;;N;;;;; +1543;CANADIAN SYLLABICS R-CREE RE;Lo;0;L;;;;;N;;;;; +1544;CANADIAN SYLLABICS WEST-CREE LE;Lo;0;L;;;;;N;;;;; +1545;CANADIAN SYLLABICS RAAI;Lo;0;L;;;;;N;;;;; +1546;CANADIAN SYLLABICS RI;Lo;0;L;;;;;N;;;;; +1547;CANADIAN SYLLABICS RII;Lo;0;L;;;;;N;;;;; +1548;CANADIAN SYLLABICS RO;Lo;0;L;;;;;N;;;;; +1549;CANADIAN SYLLABICS ROO;Lo;0;L;;;;;N;;;;; +154A;CANADIAN SYLLABICS WEST-CREE LO;Lo;0;L;;;;;N;;;;; +154B;CANADIAN SYLLABICS RA;Lo;0;L;;;;;N;;;;; +154C;CANADIAN SYLLABICS RAA;Lo;0;L;;;;;N;;;;; +154D;CANADIAN SYLLABICS WEST-CREE LA;Lo;0;L;;;;;N;;;;; +154E;CANADIAN SYLLABICS RWAA;Lo;0;L;;;;;N;;;;; +154F;CANADIAN SYLLABICS WEST-CREE RWAA;Lo;0;L;;;;;N;;;;; +1550;CANADIAN SYLLABICS R;Lo;0;L;;;;;N;;;;; +1551;CANADIAN SYLLABICS WEST-CREE R;Lo;0;L;;;;;N;;;;; +1552;CANADIAN SYLLABICS MEDIAL R;Lo;0;L;;;;;N;;;;; +1553;CANADIAN SYLLABICS FE;Lo;0;L;;;;;N;;;;; +1554;CANADIAN SYLLABICS FAAI;Lo;0;L;;;;;N;;;;; +1555;CANADIAN SYLLABICS FI;Lo;0;L;;;;;N;;;;; +1556;CANADIAN SYLLABICS FII;Lo;0;L;;;;;N;;;;; +1557;CANADIAN SYLLABICS FO;Lo;0;L;;;;;N;;;;; +1558;CANADIAN SYLLABICS FOO;Lo;0;L;;;;;N;;;;; +1559;CANADIAN SYLLABICS FA;Lo;0;L;;;;;N;;;;; +155A;CANADIAN SYLLABICS FAA;Lo;0;L;;;;;N;;;;; +155B;CANADIAN SYLLABICS FWAA;Lo;0;L;;;;;N;;;;; +155C;CANADIAN SYLLABICS WEST-CREE FWAA;Lo;0;L;;;;;N;;;;; +155D;CANADIAN SYLLABICS F;Lo;0;L;;;;;N;;;;; +155E;CANADIAN SYLLABICS THE;Lo;0;L;;;;;N;;;;; +155F;CANADIAN SYLLABICS N-CREE THE;Lo;0;L;;;;;N;;;;; +1560;CANADIAN SYLLABICS THI;Lo;0;L;;;;;N;;;;; +1561;CANADIAN SYLLABICS N-CREE THI;Lo;0;L;;;;;N;;;;; +1562;CANADIAN SYLLABICS THII;Lo;0;L;;;;;N;;;;; +1563;CANADIAN SYLLABICS N-CREE THII;Lo;0;L;;;;;N;;;;; +1564;CANADIAN SYLLABICS THO;Lo;0;L;;;;;N;;;;; +1565;CANADIAN SYLLABICS THOO;Lo;0;L;;;;;N;;;;; +1566;CANADIAN SYLLABICS THA;Lo;0;L;;;;;N;;;;; +1567;CANADIAN SYLLABICS THAA;Lo;0;L;;;;;N;;;;; +1568;CANADIAN SYLLABICS THWAA;Lo;0;L;;;;;N;;;;; +1569;CANADIAN SYLLABICS WEST-CREE THWAA;Lo;0;L;;;;;N;;;;; +156A;CANADIAN SYLLABICS TH;Lo;0;L;;;;;N;;;;; +156B;CANADIAN SYLLABICS TTHE;Lo;0;L;;;;;N;;;;; +156C;CANADIAN SYLLABICS TTHI;Lo;0;L;;;;;N;;;;; +156D;CANADIAN SYLLABICS TTHO;Lo;0;L;;;;;N;;;;; +156E;CANADIAN SYLLABICS TTHA;Lo;0;L;;;;;N;;;;; +156F;CANADIAN SYLLABICS TTH;Lo;0;L;;;;;N;;;;; +1570;CANADIAN SYLLABICS TYE;Lo;0;L;;;;;N;;;;; +1571;CANADIAN SYLLABICS TYI;Lo;0;L;;;;;N;;;;; +1572;CANADIAN SYLLABICS TYO;Lo;0;L;;;;;N;;;;; +1573;CANADIAN SYLLABICS TYA;Lo;0;L;;;;;N;;;;; +1574;CANADIAN SYLLABICS NUNAVIK HE;Lo;0;L;;;;;N;;;;; +1575;CANADIAN SYLLABICS NUNAVIK HI;Lo;0;L;;;;;N;;;;; +1576;CANADIAN SYLLABICS NUNAVIK HII;Lo;0;L;;;;;N;;;;; +1577;CANADIAN SYLLABICS NUNAVIK HO;Lo;0;L;;;;;N;;;;; +1578;CANADIAN SYLLABICS NUNAVIK HOO;Lo;0;L;;;;;N;;;;; +1579;CANADIAN SYLLABICS NUNAVIK HA;Lo;0;L;;;;;N;;;;; +157A;CANADIAN SYLLABICS NUNAVIK HAA;Lo;0;L;;;;;N;;;;; +157B;CANADIAN SYLLABICS NUNAVIK H;Lo;0;L;;;;;N;;;;; +157C;CANADIAN SYLLABICS NUNAVUT H;Lo;0;L;;;;;N;;;;; +157D;CANADIAN SYLLABICS HK;Lo;0;L;;;;;N;;;;; +157E;CANADIAN SYLLABICS QAAI;Lo;0;L;;;;;N;;;;; +157F;CANADIAN SYLLABICS QI;Lo;0;L;;;;;N;;;;; +1580;CANADIAN SYLLABICS QII;Lo;0;L;;;;;N;;;;; +1581;CANADIAN SYLLABICS QO;Lo;0;L;;;;;N;;;;; +1582;CANADIAN SYLLABICS QOO;Lo;0;L;;;;;N;;;;; +1583;CANADIAN SYLLABICS QA;Lo;0;L;;;;;N;;;;; +1584;CANADIAN SYLLABICS QAA;Lo;0;L;;;;;N;;;;; +1585;CANADIAN SYLLABICS Q;Lo;0;L;;;;;N;;;;; +1586;CANADIAN SYLLABICS TLHE;Lo;0;L;;;;;N;;;;; +1587;CANADIAN SYLLABICS TLHI;Lo;0;L;;;;;N;;;;; +1588;CANADIAN SYLLABICS TLHO;Lo;0;L;;;;;N;;;;; +1589;CANADIAN SYLLABICS TLHA;Lo;0;L;;;;;N;;;;; +158A;CANADIAN SYLLABICS WEST-CREE RE;Lo;0;L;;;;;N;;;;; +158B;CANADIAN SYLLABICS WEST-CREE RI;Lo;0;L;;;;;N;;;;; +158C;CANADIAN SYLLABICS WEST-CREE RO;Lo;0;L;;;;;N;;;;; +158D;CANADIAN SYLLABICS WEST-CREE RA;Lo;0;L;;;;;N;;;;; +158E;CANADIAN SYLLABICS NGAAI;Lo;0;L;;;;;N;;;;; +158F;CANADIAN SYLLABICS NGI;Lo;0;L;;;;;N;;;;; +1590;CANADIAN SYLLABICS NGII;Lo;0;L;;;;;N;;;;; +1591;CANADIAN SYLLABICS NGO;Lo;0;L;;;;;N;;;;; +1592;CANADIAN SYLLABICS NGOO;Lo;0;L;;;;;N;;;;; +1593;CANADIAN SYLLABICS NGA;Lo;0;L;;;;;N;;;;; +1594;CANADIAN SYLLABICS NGAA;Lo;0;L;;;;;N;;;;; +1595;CANADIAN SYLLABICS NG;Lo;0;L;;;;;N;;;;; +1596;CANADIAN SYLLABICS NNG;Lo;0;L;;;;;N;;;;; +1597;CANADIAN SYLLABICS SAYISI SHE;Lo;0;L;;;;;N;;;;; +1598;CANADIAN SYLLABICS SAYISI SHI;Lo;0;L;;;;;N;;;;; +1599;CANADIAN SYLLABICS SAYISI SHO;Lo;0;L;;;;;N;;;;; +159A;CANADIAN SYLLABICS SAYISI SHA;Lo;0;L;;;;;N;;;;; +159B;CANADIAN SYLLABICS WOODS-CREE THE;Lo;0;L;;;;;N;;;;; +159C;CANADIAN SYLLABICS WOODS-CREE THI;Lo;0;L;;;;;N;;;;; +159D;CANADIAN SYLLABICS WOODS-CREE THO;Lo;0;L;;;;;N;;;;; +159E;CANADIAN SYLLABICS WOODS-CREE THA;Lo;0;L;;;;;N;;;;; +159F;CANADIAN SYLLABICS WOODS-CREE TH;Lo;0;L;;;;;N;;;;; +15A0;CANADIAN SYLLABICS LHI;Lo;0;L;;;;;N;;;;; +15A1;CANADIAN SYLLABICS LHII;Lo;0;L;;;;;N;;;;; +15A2;CANADIAN SYLLABICS LHO;Lo;0;L;;;;;N;;;;; +15A3;CANADIAN SYLLABICS LHOO;Lo;0;L;;;;;N;;;;; +15A4;CANADIAN SYLLABICS LHA;Lo;0;L;;;;;N;;;;; +15A5;CANADIAN SYLLABICS LHAA;Lo;0;L;;;;;N;;;;; +15A6;CANADIAN SYLLABICS LH;Lo;0;L;;;;;N;;;;; +15A7;CANADIAN SYLLABICS TH-CREE THE;Lo;0;L;;;;;N;;;;; +15A8;CANADIAN SYLLABICS TH-CREE THI;Lo;0;L;;;;;N;;;;; +15A9;CANADIAN SYLLABICS TH-CREE THII;Lo;0;L;;;;;N;;;;; +15AA;CANADIAN SYLLABICS TH-CREE THO;Lo;0;L;;;;;N;;;;; +15AB;CANADIAN SYLLABICS TH-CREE THOO;Lo;0;L;;;;;N;;;;; +15AC;CANADIAN SYLLABICS TH-CREE THA;Lo;0;L;;;;;N;;;;; +15AD;CANADIAN SYLLABICS TH-CREE THAA;Lo;0;L;;;;;N;;;;; +15AE;CANADIAN SYLLABICS TH-CREE TH;Lo;0;L;;;;;N;;;;; +15AF;CANADIAN SYLLABICS AIVILIK B;Lo;0;L;;;;;N;;;;; +15B0;CANADIAN SYLLABICS BLACKFOOT E;Lo;0;L;;;;;N;;;;; +15B1;CANADIAN SYLLABICS BLACKFOOT I;Lo;0;L;;;;;N;;;;; +15B2;CANADIAN SYLLABICS BLACKFOOT O;Lo;0;L;;;;;N;;;;; +15B3;CANADIAN SYLLABICS BLACKFOOT A;Lo;0;L;;;;;N;;;;; +15B4;CANADIAN SYLLABICS BLACKFOOT WE;Lo;0;L;;;;;N;;;;; +15B5;CANADIAN SYLLABICS BLACKFOOT WI;Lo;0;L;;;;;N;;;;; +15B6;CANADIAN SYLLABICS BLACKFOOT WO;Lo;0;L;;;;;N;;;;; +15B7;CANADIAN SYLLABICS BLACKFOOT WA;Lo;0;L;;;;;N;;;;; +15B8;CANADIAN SYLLABICS BLACKFOOT NE;Lo;0;L;;;;;N;;;;; +15B9;CANADIAN SYLLABICS BLACKFOOT NI;Lo;0;L;;;;;N;;;;; +15BA;CANADIAN SYLLABICS BLACKFOOT NO;Lo;0;L;;;;;N;;;;; +15BB;CANADIAN SYLLABICS BLACKFOOT NA;Lo;0;L;;;;;N;;;;; +15BC;CANADIAN SYLLABICS BLACKFOOT KE;Lo;0;L;;;;;N;;;;; +15BD;CANADIAN SYLLABICS BLACKFOOT KI;Lo;0;L;;;;;N;;;;; +15BE;CANADIAN SYLLABICS BLACKFOOT KO;Lo;0;L;;;;;N;;;;; +15BF;CANADIAN SYLLABICS BLACKFOOT KA;Lo;0;L;;;;;N;;;;; +15C0;CANADIAN SYLLABICS SAYISI HE;Lo;0;L;;;;;N;;;;; +15C1;CANADIAN SYLLABICS SAYISI HI;Lo;0;L;;;;;N;;;;; +15C2;CANADIAN SYLLABICS SAYISI HO;Lo;0;L;;;;;N;;;;; +15C3;CANADIAN SYLLABICS SAYISI HA;Lo;0;L;;;;;N;;;;; +15C4;CANADIAN SYLLABICS CARRIER GHU;Lo;0;L;;;;;N;;;;; +15C5;CANADIAN SYLLABICS CARRIER GHO;Lo;0;L;;;;;N;;;;; +15C6;CANADIAN SYLLABICS CARRIER GHE;Lo;0;L;;;;;N;;;;; +15C7;CANADIAN SYLLABICS CARRIER GHEE;Lo;0;L;;;;;N;;;;; +15C8;CANADIAN SYLLABICS CARRIER GHI;Lo;0;L;;;;;N;;;;; +15C9;CANADIAN SYLLABICS CARRIER GHA;Lo;0;L;;;;;N;;;;; +15CA;CANADIAN SYLLABICS CARRIER RU;Lo;0;L;;;;;N;;;;; +15CB;CANADIAN SYLLABICS CARRIER RO;Lo;0;L;;;;;N;;;;; +15CC;CANADIAN SYLLABICS CARRIER RE;Lo;0;L;;;;;N;;;;; +15CD;CANADIAN SYLLABICS CARRIER REE;Lo;0;L;;;;;N;;;;; +15CE;CANADIAN SYLLABICS CARRIER RI;Lo;0;L;;;;;N;;;;; +15CF;CANADIAN SYLLABICS CARRIER RA;Lo;0;L;;;;;N;;;;; +15D0;CANADIAN SYLLABICS CARRIER WU;Lo;0;L;;;;;N;;;;; +15D1;CANADIAN SYLLABICS CARRIER WO;Lo;0;L;;;;;N;;;;; +15D2;CANADIAN SYLLABICS CARRIER WE;Lo;0;L;;;;;N;;;;; +15D3;CANADIAN SYLLABICS CARRIER WEE;Lo;0;L;;;;;N;;;;; +15D4;CANADIAN SYLLABICS CARRIER WI;Lo;0;L;;;;;N;;;;; +15D5;CANADIAN SYLLABICS CARRIER WA;Lo;0;L;;;;;N;;;;; +15D6;CANADIAN SYLLABICS CARRIER HWU;Lo;0;L;;;;;N;;;;; +15D7;CANADIAN SYLLABICS CARRIER HWO;Lo;0;L;;;;;N;;;;; +15D8;CANADIAN SYLLABICS CARRIER HWE;Lo;0;L;;;;;N;;;;; +15D9;CANADIAN SYLLABICS CARRIER HWEE;Lo;0;L;;;;;N;;;;; +15DA;CANADIAN SYLLABICS CARRIER HWI;Lo;0;L;;;;;N;;;;; +15DB;CANADIAN SYLLABICS CARRIER HWA;Lo;0;L;;;;;N;;;;; +15DC;CANADIAN SYLLABICS CARRIER THU;Lo;0;L;;;;;N;;;;; +15DD;CANADIAN SYLLABICS CARRIER THO;Lo;0;L;;;;;N;;;;; +15DE;CANADIAN SYLLABICS CARRIER THE;Lo;0;L;;;;;N;;;;; +15DF;CANADIAN SYLLABICS CARRIER THEE;Lo;0;L;;;;;N;;;;; +15E0;CANADIAN SYLLABICS CARRIER THI;Lo;0;L;;;;;N;;;;; +15E1;CANADIAN SYLLABICS CARRIER THA;Lo;0;L;;;;;N;;;;; +15E2;CANADIAN SYLLABICS CARRIER TTU;Lo;0;L;;;;;N;;;;; +15E3;CANADIAN SYLLABICS CARRIER TTO;Lo;0;L;;;;;N;;;;; +15E4;CANADIAN SYLLABICS CARRIER TTE;Lo;0;L;;;;;N;;;;; +15E5;CANADIAN SYLLABICS CARRIER TTEE;Lo;0;L;;;;;N;;;;; +15E6;CANADIAN SYLLABICS CARRIER TTI;Lo;0;L;;;;;N;;;;; +15E7;CANADIAN SYLLABICS CARRIER TTA;Lo;0;L;;;;;N;;;;; +15E8;CANADIAN SYLLABICS CARRIER PU;Lo;0;L;;;;;N;;;;; +15E9;CANADIAN SYLLABICS CARRIER PO;Lo;0;L;;;;;N;;;;; +15EA;CANADIAN SYLLABICS CARRIER PE;Lo;0;L;;;;;N;;;;; +15EB;CANADIAN SYLLABICS CARRIER PEE;Lo;0;L;;;;;N;;;;; +15EC;CANADIAN SYLLABICS CARRIER PI;Lo;0;L;;;;;N;;;;; +15ED;CANADIAN SYLLABICS CARRIER PA;Lo;0;L;;;;;N;;;;; +15EE;CANADIAN SYLLABICS CARRIER P;Lo;0;L;;;;;N;;;;; +15EF;CANADIAN SYLLABICS CARRIER GU;Lo;0;L;;;;;N;;;;; +15F0;CANADIAN SYLLABICS CARRIER GO;Lo;0;L;;;;;N;;;;; +15F1;CANADIAN SYLLABICS CARRIER GE;Lo;0;L;;;;;N;;;;; +15F2;CANADIAN SYLLABICS CARRIER GEE;Lo;0;L;;;;;N;;;;; +15F3;CANADIAN SYLLABICS CARRIER GI;Lo;0;L;;;;;N;;;;; +15F4;CANADIAN SYLLABICS CARRIER GA;Lo;0;L;;;;;N;;;;; +15F5;CANADIAN SYLLABICS CARRIER KHU;Lo;0;L;;;;;N;;;;; +15F6;CANADIAN SYLLABICS CARRIER KHO;Lo;0;L;;;;;N;;;;; +15F7;CANADIAN SYLLABICS CARRIER KHE;Lo;0;L;;;;;N;;;;; +15F8;CANADIAN SYLLABICS CARRIER KHEE;Lo;0;L;;;;;N;;;;; +15F9;CANADIAN SYLLABICS CARRIER KHI;Lo;0;L;;;;;N;;;;; +15FA;CANADIAN SYLLABICS CARRIER KHA;Lo;0;L;;;;;N;;;;; +15FB;CANADIAN SYLLABICS CARRIER KKU;Lo;0;L;;;;;N;;;;; +15FC;CANADIAN SYLLABICS CARRIER KKO;Lo;0;L;;;;;N;;;;; +15FD;CANADIAN SYLLABICS CARRIER KKE;Lo;0;L;;;;;N;;;;; +15FE;CANADIAN SYLLABICS CARRIER KKEE;Lo;0;L;;;;;N;;;;; +15FF;CANADIAN SYLLABICS CARRIER KKI;Lo;0;L;;;;;N;;;;; +1600;CANADIAN SYLLABICS CARRIER KKA;Lo;0;L;;;;;N;;;;; +1601;CANADIAN SYLLABICS CARRIER KK;Lo;0;L;;;;;N;;;;; +1602;CANADIAN SYLLABICS CARRIER NU;Lo;0;L;;;;;N;;;;; +1603;CANADIAN SYLLABICS CARRIER NO;Lo;0;L;;;;;N;;;;; +1604;CANADIAN SYLLABICS CARRIER NE;Lo;0;L;;;;;N;;;;; +1605;CANADIAN SYLLABICS CARRIER NEE;Lo;0;L;;;;;N;;;;; +1606;CANADIAN SYLLABICS CARRIER NI;Lo;0;L;;;;;N;;;;; +1607;CANADIAN SYLLABICS CARRIER NA;Lo;0;L;;;;;N;;;;; +1608;CANADIAN SYLLABICS CARRIER MU;Lo;0;L;;;;;N;;;;; +1609;CANADIAN SYLLABICS CARRIER MO;Lo;0;L;;;;;N;;;;; +160A;CANADIAN SYLLABICS CARRIER ME;Lo;0;L;;;;;N;;;;; +160B;CANADIAN SYLLABICS CARRIER MEE;Lo;0;L;;;;;N;;;;; +160C;CANADIAN SYLLABICS CARRIER MI;Lo;0;L;;;;;N;;;;; +160D;CANADIAN SYLLABICS CARRIER MA;Lo;0;L;;;;;N;;;;; +160E;CANADIAN SYLLABICS CARRIER YU;Lo;0;L;;;;;N;;;;; +160F;CANADIAN SYLLABICS CARRIER YO;Lo;0;L;;;;;N;;;;; +1610;CANADIAN SYLLABICS CARRIER YE;Lo;0;L;;;;;N;;;;; +1611;CANADIAN SYLLABICS CARRIER YEE;Lo;0;L;;;;;N;;;;; +1612;CANADIAN SYLLABICS CARRIER YI;Lo;0;L;;;;;N;;;;; +1613;CANADIAN SYLLABICS CARRIER YA;Lo;0;L;;;;;N;;;;; +1614;CANADIAN SYLLABICS CARRIER JU;Lo;0;L;;;;;N;;;;; +1615;CANADIAN SYLLABICS SAYISI JU;Lo;0;L;;;;;N;;;;; +1616;CANADIAN SYLLABICS CARRIER JO;Lo;0;L;;;;;N;;;;; +1617;CANADIAN SYLLABICS CARRIER JE;Lo;0;L;;;;;N;;;;; +1618;CANADIAN SYLLABICS CARRIER JEE;Lo;0;L;;;;;N;;;;; +1619;CANADIAN SYLLABICS CARRIER JI;Lo;0;L;;;;;N;;;;; +161A;CANADIAN SYLLABICS SAYISI JI;Lo;0;L;;;;;N;;;;; +161B;CANADIAN SYLLABICS CARRIER JA;Lo;0;L;;;;;N;;;;; +161C;CANADIAN SYLLABICS CARRIER JJU;Lo;0;L;;;;;N;;;;; +161D;CANADIAN SYLLABICS CARRIER JJO;Lo;0;L;;;;;N;;;;; +161E;CANADIAN SYLLABICS CARRIER JJE;Lo;0;L;;;;;N;;;;; +161F;CANADIAN SYLLABICS CARRIER JJEE;Lo;0;L;;;;;N;;;;; +1620;CANADIAN SYLLABICS CARRIER JJI;Lo;0;L;;;;;N;;;;; +1621;CANADIAN SYLLABICS CARRIER JJA;Lo;0;L;;;;;N;;;;; +1622;CANADIAN SYLLABICS CARRIER LU;Lo;0;L;;;;;N;;;;; +1623;CANADIAN SYLLABICS CARRIER LO;Lo;0;L;;;;;N;;;;; +1624;CANADIAN SYLLABICS CARRIER LE;Lo;0;L;;;;;N;;;;; +1625;CANADIAN SYLLABICS CARRIER LEE;Lo;0;L;;;;;N;;;;; +1626;CANADIAN SYLLABICS CARRIER LI;Lo;0;L;;;;;N;;;;; +1627;CANADIAN SYLLABICS CARRIER LA;Lo;0;L;;;;;N;;;;; +1628;CANADIAN SYLLABICS CARRIER DLU;Lo;0;L;;;;;N;;;;; +1629;CANADIAN SYLLABICS CARRIER DLO;Lo;0;L;;;;;N;;;;; +162A;CANADIAN SYLLABICS CARRIER DLE;Lo;0;L;;;;;N;;;;; +162B;CANADIAN SYLLABICS CARRIER DLEE;Lo;0;L;;;;;N;;;;; +162C;CANADIAN SYLLABICS CARRIER DLI;Lo;0;L;;;;;N;;;;; +162D;CANADIAN SYLLABICS CARRIER DLA;Lo;0;L;;;;;N;;;;; +162E;CANADIAN SYLLABICS CARRIER LHU;Lo;0;L;;;;;N;;;;; +162F;CANADIAN SYLLABICS CARRIER LHO;Lo;0;L;;;;;N;;;;; +1630;CANADIAN SYLLABICS CARRIER LHE;Lo;0;L;;;;;N;;;;; +1631;CANADIAN SYLLABICS CARRIER LHEE;Lo;0;L;;;;;N;;;;; +1632;CANADIAN SYLLABICS CARRIER LHI;Lo;0;L;;;;;N;;;;; +1633;CANADIAN SYLLABICS CARRIER LHA;Lo;0;L;;;;;N;;;;; +1634;CANADIAN SYLLABICS CARRIER TLHU;Lo;0;L;;;;;N;;;;; +1635;CANADIAN SYLLABICS CARRIER TLHO;Lo;0;L;;;;;N;;;;; +1636;CANADIAN SYLLABICS CARRIER TLHE;Lo;0;L;;;;;N;;;;; +1637;CANADIAN SYLLABICS CARRIER TLHEE;Lo;0;L;;;;;N;;;;; +1638;CANADIAN SYLLABICS CARRIER TLHI;Lo;0;L;;;;;N;;;;; +1639;CANADIAN SYLLABICS CARRIER TLHA;Lo;0;L;;;;;N;;;;; +163A;CANADIAN SYLLABICS CARRIER TLU;Lo;0;L;;;;;N;;;;; +163B;CANADIAN SYLLABICS CARRIER TLO;Lo;0;L;;;;;N;;;;; +163C;CANADIAN SYLLABICS CARRIER TLE;Lo;0;L;;;;;N;;;;; +163D;CANADIAN SYLLABICS CARRIER TLEE;Lo;0;L;;;;;N;;;;; +163E;CANADIAN SYLLABICS CARRIER TLI;Lo;0;L;;;;;N;;;;; +163F;CANADIAN SYLLABICS CARRIER TLA;Lo;0;L;;;;;N;;;;; +1640;CANADIAN SYLLABICS CARRIER ZU;Lo;0;L;;;;;N;;;;; +1641;CANADIAN SYLLABICS CARRIER ZO;Lo;0;L;;;;;N;;;;; +1642;CANADIAN SYLLABICS CARRIER ZE;Lo;0;L;;;;;N;;;;; +1643;CANADIAN SYLLABICS CARRIER ZEE;Lo;0;L;;;;;N;;;;; +1644;CANADIAN SYLLABICS CARRIER ZI;Lo;0;L;;;;;N;;;;; +1645;CANADIAN SYLLABICS CARRIER ZA;Lo;0;L;;;;;N;;;;; +1646;CANADIAN SYLLABICS CARRIER Z;Lo;0;L;;;;;N;;;;; +1647;CANADIAN SYLLABICS CARRIER INITIAL Z;Lo;0;L;;;;;N;;;;; +1648;CANADIAN SYLLABICS CARRIER DZU;Lo;0;L;;;;;N;;;;; +1649;CANADIAN SYLLABICS CARRIER DZO;Lo;0;L;;;;;N;;;;; +164A;CANADIAN SYLLABICS CARRIER DZE;Lo;0;L;;;;;N;;;;; +164B;CANADIAN SYLLABICS CARRIER DZEE;Lo;0;L;;;;;N;;;;; +164C;CANADIAN SYLLABICS CARRIER DZI;Lo;0;L;;;;;N;;;;; +164D;CANADIAN SYLLABICS CARRIER DZA;Lo;0;L;;;;;N;;;;; +164E;CANADIAN SYLLABICS CARRIER SU;Lo;0;L;;;;;N;;;;; +164F;CANADIAN SYLLABICS CARRIER SO;Lo;0;L;;;;;N;;;;; +1650;CANADIAN SYLLABICS CARRIER SE;Lo;0;L;;;;;N;;;;; +1651;CANADIAN SYLLABICS CARRIER SEE;Lo;0;L;;;;;N;;;;; +1652;CANADIAN SYLLABICS CARRIER SI;Lo;0;L;;;;;N;;;;; +1653;CANADIAN SYLLABICS CARRIER SA;Lo;0;L;;;;;N;;;;; +1654;CANADIAN SYLLABICS CARRIER SHU;Lo;0;L;;;;;N;;;;; +1655;CANADIAN SYLLABICS CARRIER SHO;Lo;0;L;;;;;N;;;;; +1656;CANADIAN SYLLABICS CARRIER SHE;Lo;0;L;;;;;N;;;;; +1657;CANADIAN SYLLABICS CARRIER SHEE;Lo;0;L;;;;;N;;;;; +1658;CANADIAN SYLLABICS CARRIER SHI;Lo;0;L;;;;;N;;;;; +1659;CANADIAN SYLLABICS CARRIER SHA;Lo;0;L;;;;;N;;;;; +165A;CANADIAN SYLLABICS CARRIER SH;Lo;0;L;;;;;N;;;;; +165B;CANADIAN SYLLABICS CARRIER TSU;Lo;0;L;;;;;N;;;;; +165C;CANADIAN SYLLABICS CARRIER TSO;Lo;0;L;;;;;N;;;;; +165D;CANADIAN SYLLABICS CARRIER TSE;Lo;0;L;;;;;N;;;;; +165E;CANADIAN SYLLABICS CARRIER TSEE;Lo;0;L;;;;;N;;;;; +165F;CANADIAN SYLLABICS CARRIER TSI;Lo;0;L;;;;;N;;;;; +1660;CANADIAN SYLLABICS CARRIER TSA;Lo;0;L;;;;;N;;;;; +1661;CANADIAN SYLLABICS CARRIER CHU;Lo;0;L;;;;;N;;;;; +1662;CANADIAN SYLLABICS CARRIER CHO;Lo;0;L;;;;;N;;;;; +1663;CANADIAN SYLLABICS CARRIER CHE;Lo;0;L;;;;;N;;;;; +1664;CANADIAN SYLLABICS CARRIER CHEE;Lo;0;L;;;;;N;;;;; +1665;CANADIAN SYLLABICS CARRIER CHI;Lo;0;L;;;;;N;;;;; +1666;CANADIAN SYLLABICS CARRIER CHA;Lo;0;L;;;;;N;;;;; +1667;CANADIAN SYLLABICS CARRIER TTSU;Lo;0;L;;;;;N;;;;; +1668;CANADIAN SYLLABICS CARRIER TTSO;Lo;0;L;;;;;N;;;;; +1669;CANADIAN SYLLABICS CARRIER TTSE;Lo;0;L;;;;;N;;;;; +166A;CANADIAN SYLLABICS CARRIER TTSEE;Lo;0;L;;;;;N;;;;; +166B;CANADIAN SYLLABICS CARRIER TTSI;Lo;0;L;;;;;N;;;;; +166C;CANADIAN SYLLABICS CARRIER TTSA;Lo;0;L;;;;;N;;;;; +166D;CANADIAN SYLLABICS CHI SIGN;Po;0;L;;;;;N;;;;; +166E;CANADIAN SYLLABICS FULL STOP;Po;0;L;;;;;N;;;;; +166F;CANADIAN SYLLABICS QAI;Lo;0;L;;;;;N;;;;; +1670;CANADIAN SYLLABICS NGAI;Lo;0;L;;;;;N;;;;; +1671;CANADIAN SYLLABICS NNGI;Lo;0;L;;;;;N;;;;; +1672;CANADIAN SYLLABICS NNGII;Lo;0;L;;;;;N;;;;; +1673;CANADIAN SYLLABICS NNGO;Lo;0;L;;;;;N;;;;; +1674;CANADIAN SYLLABICS NNGOO;Lo;0;L;;;;;N;;;;; +1675;CANADIAN SYLLABICS NNGA;Lo;0;L;;;;;N;;;;; +1676;CANADIAN SYLLABICS NNGAA;Lo;0;L;;;;;N;;;;; +1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;; +1681;OGHAM LETTER BEITH;Lo;0;L;;;;;N;;;;; +1682;OGHAM LETTER LUIS;Lo;0;L;;;;;N;;;;; +1683;OGHAM LETTER FEARN;Lo;0;L;;;;;N;;;;; +1684;OGHAM LETTER SAIL;Lo;0;L;;;;;N;;;;; +1685;OGHAM LETTER NION;Lo;0;L;;;;;N;;;;; +1686;OGHAM LETTER UATH;Lo;0;L;;;;;N;;;;; +1687;OGHAM LETTER DAIR;Lo;0;L;;;;;N;;;;; +1688;OGHAM LETTER TINNE;Lo;0;L;;;;;N;;;;; +1689;OGHAM LETTER COLL;Lo;0;L;;;;;N;;;;; +168A;OGHAM LETTER CEIRT;Lo;0;L;;;;;N;;;;; +168B;OGHAM LETTER MUIN;Lo;0;L;;;;;N;;;;; +168C;OGHAM LETTER GORT;Lo;0;L;;;;;N;;;;; +168D;OGHAM LETTER NGEADAL;Lo;0;L;;;;;N;;;;; +168E;OGHAM LETTER STRAIF;Lo;0;L;;;;;N;;;;; +168F;OGHAM LETTER RUIS;Lo;0;L;;;;;N;;;;; +1690;OGHAM LETTER AILM;Lo;0;L;;;;;N;;;;; +1691;OGHAM LETTER ONN;Lo;0;L;;;;;N;;;;; +1692;OGHAM LETTER UR;Lo;0;L;;;;;N;;;;; +1693;OGHAM LETTER EADHADH;Lo;0;L;;;;;N;;;;; +1694;OGHAM LETTER IODHADH;Lo;0;L;;;;;N;;;;; +1695;OGHAM LETTER EABHADH;Lo;0;L;;;;;N;;;;; +1696;OGHAM LETTER OR;Lo;0;L;;;;;N;;;;; +1697;OGHAM LETTER UILLEANN;Lo;0;L;;;;;N;;;;; +1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;; +1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;; +169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;; +169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;N;;;;; +169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;N;;;;; +16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;; +16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;; +16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;; +16A3;RUNIC LETTER YR;Lo;0;L;;;;;N;;;;; +16A4;RUNIC LETTER Y;Lo;0;L;;;;;N;;;;; +16A5;RUNIC LETTER W;Lo;0;L;;;;;N;;;;; +16A6;RUNIC LETTER THURISAZ THURS THORN;Lo;0;L;;;;;N;;;;; +16A7;RUNIC LETTER ETH;Lo;0;L;;;;;N;;;;; +16A8;RUNIC LETTER ANSUZ A;Lo;0;L;;;;;N;;;;; +16A9;RUNIC LETTER OS O;Lo;0;L;;;;;N;;;;; +16AA;RUNIC LETTER AC A;Lo;0;L;;;;;N;;;;; +16AB;RUNIC LETTER AESC;Lo;0;L;;;;;N;;;;; +16AC;RUNIC LETTER LONG-BRANCH-OSS O;Lo;0;L;;;;;N;;;;; +16AD;RUNIC LETTER SHORT-TWIG-OSS O;Lo;0;L;;;;;N;;;;; +16AE;RUNIC LETTER O;Lo;0;L;;;;;N;;;;; +16AF;RUNIC LETTER OE;Lo;0;L;;;;;N;;;;; +16B0;RUNIC LETTER ON;Lo;0;L;;;;;N;;;;; +16B1;RUNIC LETTER RAIDO RAD REID R;Lo;0;L;;;;;N;;;;; +16B2;RUNIC LETTER KAUNA;Lo;0;L;;;;;N;;;;; +16B3;RUNIC LETTER CEN;Lo;0;L;;;;;N;;;;; +16B4;RUNIC LETTER KAUN K;Lo;0;L;;;;;N;;;;; +16B5;RUNIC LETTER G;Lo;0;L;;;;;N;;;;; +16B6;RUNIC LETTER ENG;Lo;0;L;;;;;N;;;;; +16B7;RUNIC LETTER GEBO GYFU G;Lo;0;L;;;;;N;;;;; +16B8;RUNIC LETTER GAR;Lo;0;L;;;;;N;;;;; +16B9;RUNIC LETTER WUNJO WYNN W;Lo;0;L;;;;;N;;;;; +16BA;RUNIC LETTER HAGLAZ H;Lo;0;L;;;;;N;;;;; +16BB;RUNIC LETTER HAEGL H;Lo;0;L;;;;;N;;;;; +16BC;RUNIC LETTER LONG-BRANCH-HAGALL H;Lo;0;L;;;;;N;;;;; +16BD;RUNIC LETTER SHORT-TWIG-HAGALL H;Lo;0;L;;;;;N;;;;; +16BE;RUNIC LETTER NAUDIZ NYD NAUD N;Lo;0;L;;;;;N;;;;; +16BF;RUNIC LETTER SHORT-TWIG-NAUD N;Lo;0;L;;;;;N;;;;; +16C0;RUNIC LETTER DOTTED-N;Lo;0;L;;;;;N;;;;; +16C1;RUNIC LETTER ISAZ IS ISS I;Lo;0;L;;;;;N;;;;; +16C2;RUNIC LETTER E;Lo;0;L;;;;;N;;;;; +16C3;RUNIC LETTER JERAN J;Lo;0;L;;;;;N;;;;; +16C4;RUNIC LETTER GER;Lo;0;L;;;;;N;;;;; +16C5;RUNIC LETTER LONG-BRANCH-AR AE;Lo;0;L;;;;;N;;;;; +16C6;RUNIC LETTER SHORT-TWIG-AR A;Lo;0;L;;;;;N;;;;; +16C7;RUNIC LETTER IWAZ EOH;Lo;0;L;;;;;N;;;;; +16C8;RUNIC LETTER PERTHO PEORTH P;Lo;0;L;;;;;N;;;;; +16C9;RUNIC LETTER ALGIZ EOLHX;Lo;0;L;;;;;N;;;;; +16CA;RUNIC LETTER SOWILO S;Lo;0;L;;;;;N;;;;; +16CB;RUNIC LETTER SIGEL LONG-BRANCH-SOL S;Lo;0;L;;;;;N;;;;; +16CC;RUNIC LETTER SHORT-TWIG-SOL S;Lo;0;L;;;;;N;;;;; +16CD;RUNIC LETTER C;Lo;0;L;;;;;N;;;;; +16CE;RUNIC LETTER Z;Lo;0;L;;;;;N;;;;; +16CF;RUNIC LETTER TIWAZ TIR TYR T;Lo;0;L;;;;;N;;;;; +16D0;RUNIC LETTER SHORT-TWIG-TYR T;Lo;0;L;;;;;N;;;;; +16D1;RUNIC LETTER D;Lo;0;L;;;;;N;;;;; +16D2;RUNIC LETTER BERKANAN BEORC BJARKAN B;Lo;0;L;;;;;N;;;;; +16D3;RUNIC LETTER SHORT-TWIG-BJARKAN B;Lo;0;L;;;;;N;;;;; +16D4;RUNIC LETTER DOTTED-P;Lo;0;L;;;;;N;;;;; +16D5;RUNIC LETTER OPEN-P;Lo;0;L;;;;;N;;;;; +16D6;RUNIC LETTER EHWAZ EH E;Lo;0;L;;;;;N;;;;; +16D7;RUNIC LETTER MANNAZ MAN M;Lo;0;L;;;;;N;;;;; +16D8;RUNIC LETTER LONG-BRANCH-MADR M;Lo;0;L;;;;;N;;;;; +16D9;RUNIC LETTER SHORT-TWIG-MADR M;Lo;0;L;;;;;N;;;;; +16DA;RUNIC LETTER LAUKAZ LAGU LOGR L;Lo;0;L;;;;;N;;;;; +16DB;RUNIC LETTER DOTTED-L;Lo;0;L;;;;;N;;;;; +16DC;RUNIC LETTER INGWAZ;Lo;0;L;;;;;N;;;;; +16DD;RUNIC LETTER ING;Lo;0;L;;;;;N;;;;; +16DE;RUNIC LETTER DAGAZ DAEG D;Lo;0;L;;;;;N;;;;; +16DF;RUNIC LETTER OTHALAN ETHEL O;Lo;0;L;;;;;N;;;;; +16E0;RUNIC LETTER EAR;Lo;0;L;;;;;N;;;;; +16E1;RUNIC LETTER IOR;Lo;0;L;;;;;N;;;;; +16E2;RUNIC LETTER CWEORTH;Lo;0;L;;;;;N;;;;; +16E3;RUNIC LETTER CALC;Lo;0;L;;;;;N;;;;; +16E4;RUNIC LETTER CEALC;Lo;0;L;;;;;N;;;;; +16E5;RUNIC LETTER STAN;Lo;0;L;;;;;N;;;;; +16E6;RUNIC LETTER LONG-BRANCH-YR;Lo;0;L;;;;;N;;;;; +16E7;RUNIC LETTER SHORT-TWIG-YR;Lo;0;L;;;;;N;;;;; +16E8;RUNIC LETTER ICELANDIC-YR;Lo;0;L;;;;;N;;;;; +16E9;RUNIC LETTER Q;Lo;0;L;;;;;N;;;;; +16EA;RUNIC LETTER X;Lo;0;L;;;;;N;;;;; +16EB;RUNIC SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;; +16EC;RUNIC MULTIPLE PUNCTUATION;Po;0;L;;;;;N;;;;; +16ED;RUNIC CROSS PUNCTUATION;Po;0;L;;;;;N;;;;; +16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;golden number 17;;; +16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;golden number 18;;; +16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;golden number 19;;; +1700;TAGALOG LETTER A;Lo;0;L;;;;;N;;;;; +1701;TAGALOG LETTER I;Lo;0;L;;;;;N;;;;; +1702;TAGALOG LETTER U;Lo;0;L;;;;;N;;;;; +1703;TAGALOG LETTER KA;Lo;0;L;;;;;N;;;;; +1704;TAGALOG LETTER GA;Lo;0;L;;;;;N;;;;; +1705;TAGALOG LETTER NGA;Lo;0;L;;;;;N;;;;; +1706;TAGALOG LETTER TA;Lo;0;L;;;;;N;;;;; +1707;TAGALOG LETTER DA;Lo;0;L;;;;;N;;;;; +1708;TAGALOG LETTER NA;Lo;0;L;;;;;N;;;;; +1709;TAGALOG LETTER PA;Lo;0;L;;;;;N;;;;; +170A;TAGALOG LETTER BA;Lo;0;L;;;;;N;;;;; +170B;TAGALOG LETTER MA;Lo;0;L;;;;;N;;;;; +170C;TAGALOG LETTER YA;Lo;0;L;;;;;N;;;;; +170E;TAGALOG LETTER LA;Lo;0;L;;;;;N;;;;; +170F;TAGALOG LETTER WA;Lo;0;L;;;;;N;;;;; +1710;TAGALOG LETTER SA;Lo;0;L;;;;;N;;;;; +1711;TAGALOG LETTER HA;Lo;0;L;;;;;N;;;;; +1712;TAGALOG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1713;TAGALOG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1714;TAGALOG SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +1720;HANUNOO LETTER A;Lo;0;L;;;;;N;;;;; +1721;HANUNOO LETTER I;Lo;0;L;;;;;N;;;;; +1722;HANUNOO LETTER U;Lo;0;L;;;;;N;;;;; +1723;HANUNOO LETTER KA;Lo;0;L;;;;;N;;;;; +1724;HANUNOO LETTER GA;Lo;0;L;;;;;N;;;;; +1725;HANUNOO LETTER NGA;Lo;0;L;;;;;N;;;;; +1726;HANUNOO LETTER TA;Lo;0;L;;;;;N;;;;; +1727;HANUNOO LETTER DA;Lo;0;L;;;;;N;;;;; +1728;HANUNOO LETTER NA;Lo;0;L;;;;;N;;;;; +1729;HANUNOO LETTER PA;Lo;0;L;;;;;N;;;;; +172A;HANUNOO LETTER BA;Lo;0;L;;;;;N;;;;; +172B;HANUNOO LETTER MA;Lo;0;L;;;;;N;;;;; +172C;HANUNOO LETTER YA;Lo;0;L;;;;;N;;;;; +172D;HANUNOO LETTER RA;Lo;0;L;;;;;N;;;;; +172E;HANUNOO LETTER LA;Lo;0;L;;;;;N;;;;; +172F;HANUNOO LETTER WA;Lo;0;L;;;;;N;;;;; +1730;HANUNOO LETTER SA;Lo;0;L;;;;;N;;;;; +1731;HANUNOO LETTER HA;Lo;0;L;;;;;N;;;;; +1732;HANUNOO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1733;HANUNOO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1734;HANUNOO SIGN PAMUDPOD;Mn;9;NSM;;;;;N;;;;; +1735;PHILIPPINE SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;; +1736;PHILIPPINE DOUBLE PUNCTUATION;Po;0;L;;;;;N;;;;; +1740;BUHID LETTER A;Lo;0;L;;;;;N;;;;; +1741;BUHID LETTER I;Lo;0;L;;;;;N;;;;; +1742;BUHID LETTER U;Lo;0;L;;;;;N;;;;; +1743;BUHID LETTER KA;Lo;0;L;;;;;N;;;;; +1744;BUHID LETTER GA;Lo;0;L;;;;;N;;;;; +1745;BUHID LETTER NGA;Lo;0;L;;;;;N;;;;; +1746;BUHID LETTER TA;Lo;0;L;;;;;N;;;;; +1747;BUHID LETTER DA;Lo;0;L;;;;;N;;;;; +1748;BUHID LETTER NA;Lo;0;L;;;;;N;;;;; +1749;BUHID LETTER PA;Lo;0;L;;;;;N;;;;; +174A;BUHID LETTER BA;Lo;0;L;;;;;N;;;;; +174B;BUHID LETTER MA;Lo;0;L;;;;;N;;;;; +174C;BUHID LETTER YA;Lo;0;L;;;;;N;;;;; +174D;BUHID LETTER RA;Lo;0;L;;;;;N;;;;; +174E;BUHID LETTER LA;Lo;0;L;;;;;N;;;;; +174F;BUHID LETTER WA;Lo;0;L;;;;;N;;;;; +1750;BUHID LETTER SA;Lo;0;L;;;;;N;;;;; +1751;BUHID LETTER HA;Lo;0;L;;;;;N;;;;; +1752;BUHID VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1753;BUHID VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1760;TAGBANWA LETTER A;Lo;0;L;;;;;N;;;;; +1761;TAGBANWA LETTER I;Lo;0;L;;;;;N;;;;; +1762;TAGBANWA LETTER U;Lo;0;L;;;;;N;;;;; +1763;TAGBANWA LETTER KA;Lo;0;L;;;;;N;;;;; +1764;TAGBANWA LETTER GA;Lo;0;L;;;;;N;;;;; +1765;TAGBANWA LETTER NGA;Lo;0;L;;;;;N;;;;; +1766;TAGBANWA LETTER TA;Lo;0;L;;;;;N;;;;; +1767;TAGBANWA LETTER DA;Lo;0;L;;;;;N;;;;; +1768;TAGBANWA LETTER NA;Lo;0;L;;;;;N;;;;; +1769;TAGBANWA LETTER PA;Lo;0;L;;;;;N;;;;; +176A;TAGBANWA LETTER BA;Lo;0;L;;;;;N;;;;; +176B;TAGBANWA LETTER MA;Lo;0;L;;;;;N;;;;; +176C;TAGBANWA LETTER YA;Lo;0;L;;;;;N;;;;; +176E;TAGBANWA LETTER LA;Lo;0;L;;;;;N;;;;; +176F;TAGBANWA LETTER WA;Lo;0;L;;;;;N;;;;; +1770;TAGBANWA LETTER SA;Lo;0;L;;;;;N;;;;; +1772;TAGBANWA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1773;TAGBANWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1780;KHMER LETTER KA;Lo;0;L;;;;;N;;;;; +1781;KHMER LETTER KHA;Lo;0;L;;;;;N;;;;; +1782;KHMER LETTER KO;Lo;0;L;;;;;N;;;;; +1783;KHMER LETTER KHO;Lo;0;L;;;;;N;;;;; +1784;KHMER LETTER NGO;Lo;0;L;;;;;N;;;;; +1785;KHMER LETTER CA;Lo;0;L;;;;;N;;;;; +1786;KHMER LETTER CHA;Lo;0;L;;;;;N;;;;; +1787;KHMER LETTER CO;Lo;0;L;;;;;N;;;;; +1788;KHMER LETTER CHO;Lo;0;L;;;;;N;;;;; +1789;KHMER LETTER NYO;Lo;0;L;;;;;N;;;;; +178A;KHMER LETTER DA;Lo;0;L;;;;;N;;;;; +178B;KHMER LETTER TTHA;Lo;0;L;;;;;N;;;;; +178C;KHMER LETTER DO;Lo;0;L;;;;;N;;;;; +178D;KHMER LETTER TTHO;Lo;0;L;;;;;N;;;;; +178E;KHMER LETTER NNO;Lo;0;L;;;;;N;;;;; +178F;KHMER LETTER TA;Lo;0;L;;;;;N;;;;; +1790;KHMER LETTER THA;Lo;0;L;;;;;N;;;;; +1791;KHMER LETTER TO;Lo;0;L;;;;;N;;;;; +1792;KHMER LETTER THO;Lo;0;L;;;;;N;;;;; +1793;KHMER LETTER NO;Lo;0;L;;;;;N;;;;; +1794;KHMER LETTER BA;Lo;0;L;;;;;N;;;;; +1795;KHMER LETTER PHA;Lo;0;L;;;;;N;;;;; +1796;KHMER LETTER PO;Lo;0;L;;;;;N;;;;; +1797;KHMER LETTER PHO;Lo;0;L;;;;;N;;;;; +1798;KHMER LETTER MO;Lo;0;L;;;;;N;;;;; +1799;KHMER LETTER YO;Lo;0;L;;;;;N;;;;; +179A;KHMER LETTER RO;Lo;0;L;;;;;N;;;;; +179B;KHMER LETTER LO;Lo;0;L;;;;;N;;;;; +179C;KHMER LETTER VO;Lo;0;L;;;;;N;;;;; +179D;KHMER LETTER SHA;Lo;0;L;;;;;N;;;;; +179E;KHMER LETTER SSO;Lo;0;L;;;;;N;;;;; +179F;KHMER LETTER SA;Lo;0;L;;;;;N;;;;; +17A0;KHMER LETTER HA;Lo;0;L;;;;;N;;;;; +17A1;KHMER LETTER LA;Lo;0;L;;;;;N;;;;; +17A2;KHMER LETTER QA;Lo;0;L;;;;;N;;;;; +17A3;KHMER INDEPENDENT VOWEL QAQ;Lo;0;L;;;;;N;;*;;; +17A4;KHMER INDEPENDENT VOWEL QAA;Lo;0;L;;;;;N;;*;;; +17A5;KHMER INDEPENDENT VOWEL QI;Lo;0;L;;;;;N;;;;; +17A6;KHMER INDEPENDENT VOWEL QII;Lo;0;L;;;;;N;;;;; +17A7;KHMER INDEPENDENT VOWEL QU;Lo;0;L;;;;;N;;;;; +17A8;KHMER INDEPENDENT VOWEL QUK;Lo;0;L;;;;;N;;;;; +17A9;KHMER INDEPENDENT VOWEL QUU;Lo;0;L;;;;;N;;;;; +17AA;KHMER INDEPENDENT VOWEL QUUV;Lo;0;L;;;;;N;;;;; +17AB;KHMER INDEPENDENT VOWEL RY;Lo;0;L;;;;;N;;;;; +17AC;KHMER INDEPENDENT VOWEL RYY;Lo;0;L;;;;;N;;;;; +17AD;KHMER INDEPENDENT VOWEL LY;Lo;0;L;;;;;N;;;;; +17AE;KHMER INDEPENDENT VOWEL LYY;Lo;0;L;;;;;N;;;;; +17AF;KHMER INDEPENDENT VOWEL QE;Lo;0;L;;;;;N;;;;; +17B0;KHMER INDEPENDENT VOWEL QAI;Lo;0;L;;;;;N;;;;; +17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;; +17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;; +17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;; +17B4;KHMER VOWEL INHERENT AQ;Cf;0;L;;;;;N;;*;;; +17B5;KHMER VOWEL INHERENT AA;Cf;0;L;;;;;N;;*;;; +17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +17B9;KHMER VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;; +17BA;KHMER VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;; +17BB;KHMER VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +17BC;KHMER VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +17BD;KHMER VOWEL SIGN UA;Mn;0;NSM;;;;;N;;;;; +17BE;KHMER VOWEL SIGN OE;Mc;0;L;;;;;N;;;;; +17BF;KHMER VOWEL SIGN YA;Mc;0;L;;;;;N;;;;; +17C0;KHMER VOWEL SIGN IE;Mc;0;L;;;;;N;;;;; +17C1;KHMER VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +17C2;KHMER VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; +17C3;KHMER VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +17C4;KHMER VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +17C5;KHMER VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +17C6;KHMER SIGN NIKAHIT;Mn;0;NSM;;;;;N;;;;; +17C7;KHMER SIGN REAHMUK;Mc;0;L;;;;;N;;;;; +17C8;KHMER SIGN YUUKALEAPINTU;Mc;0;L;;;;;N;;;;; +17C9;KHMER SIGN MUUSIKATOAN;Mn;0;NSM;;;;;N;;;;; +17CA;KHMER SIGN TRIISAP;Mn;0;NSM;;;;;N;;;;; +17CB;KHMER SIGN BANTOC;Mn;0;NSM;;;;;N;;;;; +17CC;KHMER SIGN ROBAT;Mn;0;NSM;;;;;N;;;;; +17CD;KHMER SIGN TOANDAKHIAT;Mn;0;NSM;;;;;N;;;;; +17CE;KHMER SIGN KAKABAT;Mn;0;NSM;;;;;N;;;;; +17CF;KHMER SIGN AHSDA;Mn;0;NSM;;;;;N;;;;; +17D0;KHMER SIGN SAMYOK SANNYA;Mn;0;NSM;;;;;N;;;;; +17D1;KHMER SIGN VIRIAM;Mn;0;NSM;;;;;N;;;;; +17D2;KHMER SIGN COENG;Mn;9;NSM;;;;;N;;;;; +17D3;KHMER SIGN BATHAMASAT;Mn;0;NSM;;;;;N;;*;;; +17D4;KHMER SIGN KHAN;Po;0;L;;;;;N;;;;; +17D5;KHMER SIGN BARIYOOSAN;Po;0;L;;;;;N;;;;; +17D6;KHMER SIGN CAMNUC PII KUUH;Po;0;L;;;;;N;;;;; +17D7;KHMER SIGN LEK TOO;Lm;0;L;;;;;N;;;;; +17D8;KHMER SIGN BEYYAL;Po;0;L;;;;;N;;*;;; +17D9;KHMER SIGN PHNAEK MUAN;Po;0;L;;;;;N;;;;; +17DA;KHMER SIGN KOOMUUT;Po;0;L;;;;;N;;;;; +17DB;KHMER CURRENCY SYMBOL RIEL;Sc;0;ET;;;;;N;;;;; +17DC;KHMER SIGN AVAKRAHASANYA;Lo;0;L;;;;;N;;;;; +17DD;KHMER SIGN ATTHACAN;Mn;230;NSM;;;;;N;;;;; +17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +17F0;KHMER SYMBOL LEK ATTAK SON;No;0;ON;;;;0;N;;;;; +17F1;KHMER SYMBOL LEK ATTAK MUOY;No;0;ON;;;;1;N;;;;; +17F2;KHMER SYMBOL LEK ATTAK PII;No;0;ON;;;;2;N;;;;; +17F3;KHMER SYMBOL LEK ATTAK BEI;No;0;ON;;;;3;N;;;;; +17F4;KHMER SYMBOL LEK ATTAK BUON;No;0;ON;;;;4;N;;;;; +17F5;KHMER SYMBOL LEK ATTAK PRAM;No;0;ON;;;;5;N;;;;; +17F6;KHMER SYMBOL LEK ATTAK PRAM-MUOY;No;0;ON;;;;6;N;;;;; +17F7;KHMER SYMBOL LEK ATTAK PRAM-PII;No;0;ON;;;;7;N;;;;; +17F8;KHMER SYMBOL LEK ATTAK PRAM-BEI;No;0;ON;;;;8;N;;;;; +17F9;KHMER SYMBOL LEK ATTAK PRAM-BUON;No;0;ON;;;;9;N;;;;; +1800;MONGOLIAN BIRGA;Po;0;ON;;;;;N;;;;; +1801;MONGOLIAN ELLIPSIS;Po;0;ON;;;;;N;;;;; +1802;MONGOLIAN COMMA;Po;0;ON;;;;;N;;;;; +1803;MONGOLIAN FULL STOP;Po;0;ON;;;;;N;;;;; +1804;MONGOLIAN COLON;Po;0;ON;;;;;N;;;;; +1805;MONGOLIAN FOUR DOTS;Po;0;ON;;;;;N;;;;; +1806;MONGOLIAN TODO SOFT HYPHEN;Pd;0;ON;;;;;N;;;;; +1807;MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER;Po;0;ON;;;;;N;;;;; +1808;MONGOLIAN MANCHU COMMA;Po;0;ON;;;;;N;;;;; +1809;MONGOLIAN MANCHU FULL STOP;Po;0;ON;;;;;N;;;;; +180A;MONGOLIAN NIRUGU;Po;0;ON;;;;;N;;;;; +180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Mn;0;NSM;;;;;N;;;;; +180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Mn;0;NSM;;;;;N;;;;; +180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Mn;0;NSM;;;;;N;;;;; +180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;; +1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1820;MONGOLIAN LETTER A;Lo;0;L;;;;;N;;;;; +1821;MONGOLIAN LETTER E;Lo;0;L;;;;;N;;;;; +1822;MONGOLIAN LETTER I;Lo;0;L;;;;;N;;;;; +1823;MONGOLIAN LETTER O;Lo;0;L;;;;;N;;;;; +1824;MONGOLIAN LETTER U;Lo;0;L;;;;;N;;;;; +1825;MONGOLIAN LETTER OE;Lo;0;L;;;;;N;;;;; +1826;MONGOLIAN LETTER UE;Lo;0;L;;;;;N;;;;; +1827;MONGOLIAN LETTER EE;Lo;0;L;;;;;N;;;;; +1828;MONGOLIAN LETTER NA;Lo;0;L;;;;;N;;;;; +1829;MONGOLIAN LETTER ANG;Lo;0;L;;;;;N;;;;; +182A;MONGOLIAN LETTER BA;Lo;0;L;;;;;N;;;;; +182B;MONGOLIAN LETTER PA;Lo;0;L;;;;;N;;;;; +182C;MONGOLIAN LETTER QA;Lo;0;L;;;;;N;;;;; +182D;MONGOLIAN LETTER GA;Lo;0;L;;;;;N;;;;; +182E;MONGOLIAN LETTER MA;Lo;0;L;;;;;N;;;;; +182F;MONGOLIAN LETTER LA;Lo;0;L;;;;;N;;;;; +1830;MONGOLIAN LETTER SA;Lo;0;L;;;;;N;;;;; +1831;MONGOLIAN LETTER SHA;Lo;0;L;;;;;N;;;;; +1832;MONGOLIAN LETTER TA;Lo;0;L;;;;;N;;;;; +1833;MONGOLIAN LETTER DA;Lo;0;L;;;;;N;;;;; +1834;MONGOLIAN LETTER CHA;Lo;0;L;;;;;N;;;;; +1835;MONGOLIAN LETTER JA;Lo;0;L;;;;;N;;;;; +1836;MONGOLIAN LETTER YA;Lo;0;L;;;;;N;;;;; +1837;MONGOLIAN LETTER RA;Lo;0;L;;;;;N;;;;; +1838;MONGOLIAN LETTER WA;Lo;0;L;;;;;N;;;;; +1839;MONGOLIAN LETTER FA;Lo;0;L;;;;;N;;;;; +183A;MONGOLIAN LETTER KA;Lo;0;L;;;;;N;;;;; +183B;MONGOLIAN LETTER KHA;Lo;0;L;;;;;N;;;;; +183C;MONGOLIAN LETTER TSA;Lo;0;L;;;;;N;;;;; +183D;MONGOLIAN LETTER ZA;Lo;0;L;;;;;N;;;;; +183E;MONGOLIAN LETTER HAA;Lo;0;L;;;;;N;;;;; +183F;MONGOLIAN LETTER ZRA;Lo;0;L;;;;;N;;;;; +1840;MONGOLIAN LETTER LHA;Lo;0;L;;;;;N;;;;; +1841;MONGOLIAN LETTER ZHI;Lo;0;L;;;;;N;;;;; +1842;MONGOLIAN LETTER CHI;Lo;0;L;;;;;N;;;;; +1843;MONGOLIAN LETTER TODO LONG VOWEL SIGN;Lm;0;L;;;;;N;;;;; +1844;MONGOLIAN LETTER TODO E;Lo;0;L;;;;;N;;;;; +1845;MONGOLIAN LETTER TODO I;Lo;0;L;;;;;N;;;;; +1846;MONGOLIAN LETTER TODO O;Lo;0;L;;;;;N;;;;; +1847;MONGOLIAN LETTER TODO U;Lo;0;L;;;;;N;;;;; +1848;MONGOLIAN LETTER TODO OE;Lo;0;L;;;;;N;;;;; +1849;MONGOLIAN LETTER TODO UE;Lo;0;L;;;;;N;;;;; +184A;MONGOLIAN LETTER TODO ANG;Lo;0;L;;;;;N;;;;; +184B;MONGOLIAN LETTER TODO BA;Lo;0;L;;;;;N;;;;; +184C;MONGOLIAN LETTER TODO PA;Lo;0;L;;;;;N;;;;; +184D;MONGOLIAN LETTER TODO QA;Lo;0;L;;;;;N;;;;; +184E;MONGOLIAN LETTER TODO GA;Lo;0;L;;;;;N;;;;; +184F;MONGOLIAN LETTER TODO MA;Lo;0;L;;;;;N;;;;; +1850;MONGOLIAN LETTER TODO TA;Lo;0;L;;;;;N;;;;; +1851;MONGOLIAN LETTER TODO DA;Lo;0;L;;;;;N;;;;; +1852;MONGOLIAN LETTER TODO CHA;Lo;0;L;;;;;N;;;;; +1853;MONGOLIAN LETTER TODO JA;Lo;0;L;;;;;N;;;;; +1854;MONGOLIAN LETTER TODO TSA;Lo;0;L;;;;;N;;;;; +1855;MONGOLIAN LETTER TODO YA;Lo;0;L;;;;;N;;;;; +1856;MONGOLIAN LETTER TODO WA;Lo;0;L;;;;;N;;;;; +1857;MONGOLIAN LETTER TODO KA;Lo;0;L;;;;;N;;;;; +1858;MONGOLIAN LETTER TODO GAA;Lo;0;L;;;;;N;;;;; +1859;MONGOLIAN LETTER TODO HAA;Lo;0;L;;;;;N;;;;; +185A;MONGOLIAN LETTER TODO JIA;Lo;0;L;;;;;N;;;;; +185B;MONGOLIAN LETTER TODO NIA;Lo;0;L;;;;;N;;;;; +185C;MONGOLIAN LETTER TODO DZA;Lo;0;L;;;;;N;;;;; +185D;MONGOLIAN LETTER SIBE E;Lo;0;L;;;;;N;;;;; +185E;MONGOLIAN LETTER SIBE I;Lo;0;L;;;;;N;;;;; +185F;MONGOLIAN LETTER SIBE IY;Lo;0;L;;;;;N;;;;; +1860;MONGOLIAN LETTER SIBE UE;Lo;0;L;;;;;N;;;;; +1861;MONGOLIAN LETTER SIBE U;Lo;0;L;;;;;N;;;;; +1862;MONGOLIAN LETTER SIBE ANG;Lo;0;L;;;;;N;;;;; +1863;MONGOLIAN LETTER SIBE KA;Lo;0;L;;;;;N;;;;; +1864;MONGOLIAN LETTER SIBE GA;Lo;0;L;;;;;N;;;;; +1865;MONGOLIAN LETTER SIBE HA;Lo;0;L;;;;;N;;;;; +1866;MONGOLIAN LETTER SIBE PA;Lo;0;L;;;;;N;;;;; +1867;MONGOLIAN LETTER SIBE SHA;Lo;0;L;;;;;N;;;;; +1868;MONGOLIAN LETTER SIBE TA;Lo;0;L;;;;;N;;;;; +1869;MONGOLIAN LETTER SIBE DA;Lo;0;L;;;;;N;;;;; +186A;MONGOLIAN LETTER SIBE JA;Lo;0;L;;;;;N;;;;; +186B;MONGOLIAN LETTER SIBE FA;Lo;0;L;;;;;N;;;;; +186C;MONGOLIAN LETTER SIBE GAA;Lo;0;L;;;;;N;;;;; +186D;MONGOLIAN LETTER SIBE HAA;Lo;0;L;;;;;N;;;;; +186E;MONGOLIAN LETTER SIBE TSA;Lo;0;L;;;;;N;;;;; +186F;MONGOLIAN LETTER SIBE ZA;Lo;0;L;;;;;N;;;;; +1870;MONGOLIAN LETTER SIBE RAA;Lo;0;L;;;;;N;;;;; +1871;MONGOLIAN LETTER SIBE CHA;Lo;0;L;;;;;N;;;;; +1872;MONGOLIAN LETTER SIBE ZHA;Lo;0;L;;;;;N;;;;; +1873;MONGOLIAN LETTER MANCHU I;Lo;0;L;;;;;N;;;;; +1874;MONGOLIAN LETTER MANCHU KA;Lo;0;L;;;;;N;;;;; +1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;; +1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;; +1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;; +1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;; +1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;; +1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;; +1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;; +1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;; +1885;MONGOLIAN LETTER ALI GALI BALUDA;Lo;0;L;;;;;N;;;;; +1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Lo;0;L;;;;;N;;;;; +1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;; +1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;; +1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;; +188A;MONGOLIAN LETTER ALI GALI NGA;Lo;0;L;;;;;N;;;;; +188B;MONGOLIAN LETTER ALI GALI CA;Lo;0;L;;;;;N;;;;; +188C;MONGOLIAN LETTER ALI GALI TTA;Lo;0;L;;;;;N;;;;; +188D;MONGOLIAN LETTER ALI GALI TTHA;Lo;0;L;;;;;N;;;;; +188E;MONGOLIAN LETTER ALI GALI DDA;Lo;0;L;;;;;N;;;;; +188F;MONGOLIAN LETTER ALI GALI NNA;Lo;0;L;;;;;N;;;;; +1890;MONGOLIAN LETTER ALI GALI TA;Lo;0;L;;;;;N;;;;; +1891;MONGOLIAN LETTER ALI GALI DA;Lo;0;L;;;;;N;;;;; +1892;MONGOLIAN LETTER ALI GALI PA;Lo;0;L;;;;;N;;;;; +1893;MONGOLIAN LETTER ALI GALI PHA;Lo;0;L;;;;;N;;;;; +1894;MONGOLIAN LETTER ALI GALI SSA;Lo;0;L;;;;;N;;;;; +1895;MONGOLIAN LETTER ALI GALI ZHA;Lo;0;L;;;;;N;;;;; +1896;MONGOLIAN LETTER ALI GALI ZA;Lo;0;L;;;;;N;;;;; +1897;MONGOLIAN LETTER ALI GALI AH;Lo;0;L;;;;;N;;;;; +1898;MONGOLIAN LETTER TODO ALI GALI TA;Lo;0;L;;;;;N;;;;; +1899;MONGOLIAN LETTER TODO ALI GALI ZHA;Lo;0;L;;;;;N;;;;; +189A;MONGOLIAN LETTER MANCHU ALI GALI GHA;Lo;0;L;;;;;N;;;;; +189B;MONGOLIAN LETTER MANCHU ALI GALI NGA;Lo;0;L;;;;;N;;;;; +189C;MONGOLIAN LETTER MANCHU ALI GALI CA;Lo;0;L;;;;;N;;;;; +189D;MONGOLIAN LETTER MANCHU ALI GALI JHA;Lo;0;L;;;;;N;;;;; +189E;MONGOLIAN LETTER MANCHU ALI GALI TTA;Lo;0;L;;;;;N;;;;; +189F;MONGOLIAN LETTER MANCHU ALI GALI DDHA;Lo;0;L;;;;;N;;;;; +18A0;MONGOLIAN LETTER MANCHU ALI GALI TA;Lo;0;L;;;;;N;;;;; +18A1;MONGOLIAN LETTER MANCHU ALI GALI DHA;Lo;0;L;;;;;N;;;;; +18A2;MONGOLIAN LETTER MANCHU ALI GALI SSA;Lo;0;L;;;;;N;;;;; +18A3;MONGOLIAN LETTER MANCHU ALI GALI CYA;Lo;0;L;;;;;N;;;;; +18A4;MONGOLIAN LETTER MANCHU ALI GALI ZHA;Lo;0;L;;;;;N;;;;; +18A5;MONGOLIAN LETTER MANCHU ALI GALI ZA;Lo;0;L;;;;;N;;;;; +18A6;MONGOLIAN LETTER ALI GALI HALF U;Lo;0;L;;;;;N;;;;; +18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;; +18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;; +18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;; +1900;LIMBU VOWEL-CARRIER LETTER;Lo;0;L;;;;;N;;;;; +1901;LIMBU LETTER KA;Lo;0;L;;;;;N;;;;; +1902;LIMBU LETTER KHA;Lo;0;L;;;;;N;;;;; +1903;LIMBU LETTER GA;Lo;0;L;;;;;N;;;;; +1904;LIMBU LETTER GHA;Lo;0;L;;;;;N;;;;; +1905;LIMBU LETTER NGA;Lo;0;L;;;;;N;;;;; +1906;LIMBU LETTER CA;Lo;0;L;;;;;N;;;;; +1907;LIMBU LETTER CHA;Lo;0;L;;;;;N;;;;; +1908;LIMBU LETTER JA;Lo;0;L;;;;;N;;;;; +1909;LIMBU LETTER JHA;Lo;0;L;;;;;N;;;;; +190A;LIMBU LETTER YAN;Lo;0;L;;;;;N;;;;; +190B;LIMBU LETTER TA;Lo;0;L;;;;;N;;;;; +190C;LIMBU LETTER THA;Lo;0;L;;;;;N;;;;; +190D;LIMBU LETTER DA;Lo;0;L;;;;;N;;;;; +190E;LIMBU LETTER DHA;Lo;0;L;;;;;N;;;;; +190F;LIMBU LETTER NA;Lo;0;L;;;;;N;;;;; +1910;LIMBU LETTER PA;Lo;0;L;;;;;N;;;;; +1911;LIMBU LETTER PHA;Lo;0;L;;;;;N;;;;; +1912;LIMBU LETTER BA;Lo;0;L;;;;;N;;;;; +1913;LIMBU LETTER BHA;Lo;0;L;;;;;N;;;;; +1914;LIMBU LETTER MA;Lo;0;L;;;;;N;;;;; +1915;LIMBU LETTER YA;Lo;0;L;;;;;N;;;;; +1916;LIMBU LETTER RA;Lo;0;L;;;;;N;;;;; +1917;LIMBU LETTER LA;Lo;0;L;;;;;N;;;;; +1918;LIMBU LETTER WA;Lo;0;L;;;;;N;;;;; +1919;LIMBU LETTER SHA;Lo;0;L;;;;;N;;;;; +191A;LIMBU LETTER SSA;Lo;0;L;;;;;N;;;;; +191B;LIMBU LETTER SA;Lo;0;L;;;;;N;;;;; +191C;LIMBU LETTER HA;Lo;0;L;;;;;N;;;;; +1920;LIMBU VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;; +1921;LIMBU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +1922;LIMBU VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1923;LIMBU VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +1924;LIMBU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +1925;LIMBU VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +1926;LIMBU VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +1927;LIMBU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +1928;LIMBU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +1929;LIMBU SUBJOINED LETTER YA;Mc;0;NSM;;;;;N;;;;; +192A;LIMBU SUBJOINED LETTER RA;Mc;0;NSM;;;;;N;;;;; +192B;LIMBU SUBJOINED LETTER WA;Mc;0;NSM;;;;;N;;;;; +1930;LIMBU SMALL LETTER KA;Mc;0;L;;;;;N;;;;; +1931;LIMBU SMALL LETTER NGA;Mc;0;L;;;;;N;;;;; +1932;LIMBU SMALL LETTER ANUSVARA;Mn;0;NSM;;;;;N;;;;; +1933;LIMBU SMALL LETTER TA;Mc;0;L;;;;;N;;;;; +1934;LIMBU SMALL LETTER NA;Mc;0;L;;;;;N;;;;; +1935;LIMBU SMALL LETTER PA;Mc;0;L;;;;;N;;;;; +1936;LIMBU SMALL LETTER MA;Mc;0;L;;;;;N;;;;; +1937;LIMBU SMALL LETTER RA;Mc;0;L;;;;;N;;;;; +1938;LIMBU SMALL LETTER LA;Mc;0;L;;;;;N;;;;; +1939;LIMBU SIGN MUKPHRENG;Mn;222;NSM;;;;;N;;;;; +193A;LIMBU SIGN KEMPHRENG;Mn;230;NSM;;;;;N;;;;; +193B;LIMBU SIGN SA-I;Mn;220;NSM;;;;;N;;;;; +1940;LIMBU SIGN LOO;So;0;ON;;;;;N;;;;; +1944;LIMBU EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +1945;LIMBU QUESTION MARK;Po;0;ON;;;;;N;;;;; +1946;LIMBU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1947;LIMBU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1948;LIMBU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1949;LIMBU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +194A;LIMBU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +194B;LIMBU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +194C;LIMBU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +194D;LIMBU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +194E;LIMBU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +194F;LIMBU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1950;TAI LE LETTER KA;Lo;0;L;;;;;N;;;;; +1951;TAI LE LETTER XA;Lo;0;L;;;;;N;;;;; +1952;TAI LE LETTER NGA;Lo;0;L;;;;;N;;;;; +1953;TAI LE LETTER TSA;Lo;0;L;;;;;N;;;;; +1954;TAI LE LETTER SA;Lo;0;L;;;;;N;;;;; +1955;TAI LE LETTER YA;Lo;0;L;;;;;N;;;;; +1956;TAI LE LETTER TA;Lo;0;L;;;;;N;;;;; +1957;TAI LE LETTER THA;Lo;0;L;;;;;N;;;;; +1958;TAI LE LETTER LA;Lo;0;L;;;;;N;;;;; +1959;TAI LE LETTER PA;Lo;0;L;;;;;N;;;;; +195A;TAI LE LETTER PHA;Lo;0;L;;;;;N;;;;; +195B;TAI LE LETTER MA;Lo;0;L;;;;;N;;;;; +195C;TAI LE LETTER FA;Lo;0;L;;;;;N;;;;; +195D;TAI LE LETTER VA;Lo;0;L;;;;;N;;;;; +195E;TAI LE LETTER HA;Lo;0;L;;;;;N;;;;; +195F;TAI LE LETTER QA;Lo;0;L;;;;;N;;;;; +1960;TAI LE LETTER KHA;Lo;0;L;;;;;N;;;;; +1961;TAI LE LETTER TSHA;Lo;0;L;;;;;N;;;;; +1962;TAI LE LETTER NA;Lo;0;L;;;;;N;;;;; +1963;TAI LE LETTER A;Lo;0;L;;;;;N;;;;; +1964;TAI LE LETTER I;Lo;0;L;;;;;N;;;;; +1965;TAI LE LETTER EE;Lo;0;L;;;;;N;;;;; +1966;TAI LE LETTER EH;Lo;0;L;;;;;N;;;;; +1967;TAI LE LETTER U;Lo;0;L;;;;;N;;;;; +1968;TAI LE LETTER OO;Lo;0;L;;;;;N;;;;; +1969;TAI LE LETTER O;Lo;0;L;;;;;N;;;;; +196A;TAI LE LETTER UE;Lo;0;L;;;;;N;;;;; +196B;TAI LE LETTER E;Lo;0;L;;;;;N;;;;; +196C;TAI LE LETTER AUE;Lo;0;L;;;;;N;;;;; +196D;TAI LE LETTER AI;Lo;0;L;;;;;N;;;;; +1970;TAI LE LETTER TONE-2;Lo;0;L;;;;;N;;;;; +1971;TAI LE LETTER TONE-3;Lo;0;L;;;;;N;;;;; +1972;TAI LE LETTER TONE-4;Lo;0;L;;;;;N;;;;; +1973;TAI LE LETTER TONE-5;Lo;0;L;;;;;N;;;;; +1974;TAI LE LETTER TONE-6;Lo;0;L;;;;;N;;;;; +19E0;KHMER SYMBOL PATHAMASAT;So;0;ON;;;;;N;;;;; +19E1;KHMER SYMBOL MUOY KOET;So;0;ON;;;;;N;;;;; +19E2;KHMER SYMBOL PII KOET;So;0;ON;;;;;N;;;;; +19E3;KHMER SYMBOL BEI KOET;So;0;ON;;;;;N;;;;; +19E4;KHMER SYMBOL BUON KOET;So;0;ON;;;;;N;;;;; +19E5;KHMER SYMBOL PRAM KOET;So;0;ON;;;;;N;;;;; +19E6;KHMER SYMBOL PRAM-MUOY KOET;So;0;ON;;;;;N;;;;; +19E7;KHMER SYMBOL PRAM-PII KOET;So;0;ON;;;;;N;;;;; +19E8;KHMER SYMBOL PRAM-BEI KOET;So;0;ON;;;;;N;;;;; +19E9;KHMER SYMBOL PRAM-BUON KOET;So;0;ON;;;;;N;;;;; +19EA;KHMER SYMBOL DAP KOET;So;0;ON;;;;;N;;;;; +19EB;KHMER SYMBOL DAP-MUOY KOET;So;0;ON;;;;;N;;;;; +19EC;KHMER SYMBOL DAP-PII KOET;So;0;ON;;;;;N;;;;; +19ED;KHMER SYMBOL DAP-BEI KOET;So;0;ON;;;;;N;;;;; +19EE;KHMER SYMBOL DAP-BUON KOET;So;0;ON;;;;;N;;;;; +19EF;KHMER SYMBOL DAP-PRAM KOET;So;0;ON;;;;;N;;;;; +19F0;KHMER SYMBOL TUTEYASAT;So;0;ON;;;;;N;;;;; +19F1;KHMER SYMBOL MUOY ROC;So;0;ON;;;;;N;;;;; +19F2;KHMER SYMBOL PII ROC;So;0;ON;;;;;N;;;;; +19F3;KHMER SYMBOL BEI ROC;So;0;ON;;;;;N;;;;; +19F4;KHMER SYMBOL BUON ROC;So;0;ON;;;;;N;;;;; +19F5;KHMER SYMBOL PRAM ROC;So;0;ON;;;;;N;;;;; +19F6;KHMER SYMBOL PRAM-MUOY ROC;So;0;ON;;;;;N;;;;; +19F7;KHMER SYMBOL PRAM-PII ROC;So;0;ON;;;;;N;;;;; +19F8;KHMER SYMBOL PRAM-BEI ROC;So;0;ON;;;;;N;;;;; +19F9;KHMER SYMBOL PRAM-BUON ROC;So;0;ON;;;;;N;;;;; +19FA;KHMER SYMBOL DAP ROC;So;0;ON;;;;;N;;;;; +19FB;KHMER SYMBOL DAP-MUOY ROC;So;0;ON;;;;;N;;;;; +19FC;KHMER SYMBOL DAP-PII ROC;So;0;ON;;;;;N;;;;; +19FD;KHMER SYMBOL DAP-BEI ROC;So;0;ON;;;;;N;;;;; +19FE;KHMER SYMBOL DAP-BUON ROC;So;0;ON;;;;;N;;;;; +19FF;KHMER SYMBOL DAP-PRAM ROC;So;0;ON;;;;;N;;;;; +1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;; +1D01;LATIN LETTER SMALL CAPITAL AE;Ll;0;L;;;;;N;;;;; +1D02;LATIN SMALL LETTER TURNED AE;Ll;0;L;;;;;N;;;;; +1D03;LATIN LETTER SMALL CAPITAL BARRED B;Ll;0;L;;;;;N;;;;; +1D04;LATIN LETTER SMALL CAPITAL C;Ll;0;L;;;;;N;;;;; +1D05;LATIN LETTER SMALL CAPITAL D;Ll;0;L;;;;;N;;;;; +1D06;LATIN LETTER SMALL CAPITAL ETH;Ll;0;L;;;;;N;;;;; +1D07;LATIN LETTER SMALL CAPITAL E;Ll;0;L;;;;;N;;;;; +1D08;LATIN SMALL LETTER TURNED OPEN E;Ll;0;L;;;;;N;;;;; +1D09;LATIN SMALL LETTER TURNED I;Ll;0;L;;;;;N;;;;; +1D0A;LATIN LETTER SMALL CAPITAL J;Ll;0;L;;;;;N;;;;; +1D0B;LATIN LETTER SMALL CAPITAL K;Ll;0;L;;;;;N;;;;; +1D0C;LATIN LETTER SMALL CAPITAL L WITH STROKE;Ll;0;L;;;;;N;;;;; +1D0D;LATIN LETTER SMALL CAPITAL M;Ll;0;L;;;;;N;;;;; +1D0E;LATIN LETTER SMALL CAPITAL REVERSED N;Ll;0;L;;;;;N;;;;; +1D0F;LATIN LETTER SMALL CAPITAL O;Ll;0;L;;;;;N;;;;; +1D10;LATIN LETTER SMALL CAPITAL OPEN O;Ll;0;L;;;;;N;;;;; +1D11;LATIN SMALL LETTER SIDEWAYS O;Ll;0;L;;;;;N;;;;; +1D12;LATIN SMALL LETTER SIDEWAYS OPEN O;Ll;0;L;;;;;N;;;;; +1D13;LATIN SMALL LETTER SIDEWAYS O WITH STROKE;Ll;0;L;;;;;N;;;;; +1D14;LATIN SMALL LETTER TURNED OE;Ll;0;L;;;;;N;;;;; +1D15;LATIN LETTER SMALL CAPITAL OU;Ll;0;L;;;;;N;;;;; +1D16;LATIN SMALL LETTER TOP HALF O;Ll;0;L;;;;;N;;;;; +1D17;LATIN SMALL LETTER BOTTOM HALF O;Ll;0;L;;;;;N;;;;; +1D18;LATIN LETTER SMALL CAPITAL P;Ll;0;L;;;;;N;;;;; +1D19;LATIN LETTER SMALL CAPITAL REVERSED R;Ll;0;L;;;;;N;;;;; +1D1A;LATIN LETTER SMALL CAPITAL TURNED R;Ll;0;L;;;;;N;;;;; +1D1B;LATIN LETTER SMALL CAPITAL T;Ll;0;L;;;;;N;;;;; +1D1C;LATIN LETTER SMALL CAPITAL U;Ll;0;L;;;;;N;;;;; +1D1D;LATIN SMALL LETTER SIDEWAYS U;Ll;0;L;;;;;N;;;;; +1D1E;LATIN SMALL LETTER SIDEWAYS DIAERESIZED U;Ll;0;L;;;;;N;;;;; +1D1F;LATIN SMALL LETTER SIDEWAYS TURNED M;Ll;0;L;;;;;N;;;;; +1D20;LATIN LETTER SMALL CAPITAL V;Ll;0;L;;;;;N;;;;; +1D21;LATIN LETTER SMALL CAPITAL W;Ll;0;L;;;;;N;;;;; +1D22;LATIN LETTER SMALL CAPITAL Z;Ll;0;L;;;;;N;;;;; +1D23;LATIN LETTER SMALL CAPITAL EZH;Ll;0;L;;;;;N;;;;; +1D24;LATIN LETTER VOICED LARYNGEAL SPIRANT;Ll;0;L;;;;;N;;;;; +1D25;LATIN LETTER AIN;Ll;0;L;;;;;N;;;;; +1D26;GREEK LETTER SMALL CAPITAL GAMMA;Ll;0;L;;;;;N;;;;; +1D27;GREEK LETTER SMALL CAPITAL LAMDA;Ll;0;L;;;;;N;;;;; +1D28;GREEK LETTER SMALL CAPITAL PI;Ll;0;L;;;;;N;;;;; +1D29;GREEK LETTER SMALL CAPITAL RHO;Ll;0;L;;;;;N;;;;; +1D2A;GREEK LETTER SMALL CAPITAL PSI;Ll;0;L;;;;;N;;;;; +1D2B;CYRILLIC LETTER SMALL CAPITAL EL;Ll;0;L;;;;;N;;;;; +1D2C;MODIFIER LETTER CAPITAL A;Lm;0;L;<super> 0041;;;;N;;;;; +1D2D;MODIFIER LETTER CAPITAL AE;Lm;0;L;<super> 00C6;;;;N;;;;; +1D2E;MODIFIER LETTER CAPITAL B;Lm;0;L;<super> 0042;;;;N;;;;; +1D2F;MODIFIER LETTER CAPITAL BARRED B;Lm;0;L;;;;;N;;;;; +1D30;MODIFIER LETTER CAPITAL D;Lm;0;L;<super> 0044;;;;N;;;;; +1D31;MODIFIER LETTER CAPITAL E;Lm;0;L;<super> 0045;;;;N;;;;; +1D32;MODIFIER LETTER CAPITAL REVERSED E;Lm;0;L;<super> 018E;;;;N;;;;; +1D33;MODIFIER LETTER CAPITAL G;Lm;0;L;<super> 0047;;;;N;;;;; +1D34;MODIFIER LETTER CAPITAL H;Lm;0;L;<super> 0048;;;;N;;;;; +1D35;MODIFIER LETTER CAPITAL I;Lm;0;L;<super> 0049;;;;N;;;;; +1D36;MODIFIER LETTER CAPITAL J;Lm;0;L;<super> 004A;;;;N;;;;; +1D37;MODIFIER LETTER CAPITAL K;Lm;0;L;<super> 004B;;;;N;;;;; +1D38;MODIFIER LETTER CAPITAL L;Lm;0;L;<super> 004C;;;;N;;;;; +1D39;MODIFIER LETTER CAPITAL M;Lm;0;L;<super> 004D;;;;N;;;;; +1D3A;MODIFIER LETTER CAPITAL N;Lm;0;L;<super> 004E;;;;N;;;;; +1D3B;MODIFIER LETTER CAPITAL REVERSED N;Lm;0;L;;;;;N;;;;; +1D3C;MODIFIER LETTER CAPITAL O;Lm;0;L;<super> 004F;;;;N;;;;; +1D3D;MODIFIER LETTER CAPITAL OU;Lm;0;L;<super> 0222;;;;N;;;;; +1D3E;MODIFIER LETTER CAPITAL P;Lm;0;L;<super> 0050;;;;N;;;;; +1D3F;MODIFIER LETTER CAPITAL R;Lm;0;L;<super> 0052;;;;N;;;;; +1D40;MODIFIER LETTER CAPITAL T;Lm;0;L;<super> 0054;;;;N;;;;; +1D41;MODIFIER LETTER CAPITAL U;Lm;0;L;<super> 0055;;;;N;;;;; +1D42;MODIFIER LETTER CAPITAL W;Lm;0;L;<super> 0057;;;;N;;;;; +1D43;MODIFIER LETTER SMALL A;Lm;0;L;<super> 0061;;;;N;;;;; +1D44;MODIFIER LETTER SMALL TURNED A;Lm;0;L;<super> 0250;;;;N;;;;; +1D45;MODIFIER LETTER SMALL ALPHA;Lm;0;L;<super> 0251;;;;N;;;;; +1D46;MODIFIER LETTER SMALL TURNED AE;Lm;0;L;<super> 1D02;;;;N;;;;; +1D47;MODIFIER LETTER SMALL B;Lm;0;L;<super> 0062;;;;N;;;;; +1D48;MODIFIER LETTER SMALL D;Lm;0;L;<super> 0064;;;;N;;;;; +1D49;MODIFIER LETTER SMALL E;Lm;0;L;<super> 0065;;;;N;;;;; +1D4A;MODIFIER LETTER SMALL SCHWA;Lm;0;L;<super> 0259;;;;N;;;;; +1D4B;MODIFIER LETTER SMALL OPEN E;Lm;0;L;<super> 025B;;;;N;;;;; +1D4C;MODIFIER LETTER SMALL TURNED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;; +1D4D;MODIFIER LETTER SMALL G;Lm;0;L;<super> 0067;;;;N;;;;; +1D4E;MODIFIER LETTER SMALL TURNED I;Lm;0;L;;;;;N;;;;; +1D4F;MODIFIER LETTER SMALL K;Lm;0;L;<super> 006B;;;;N;;;;; +1D50;MODIFIER LETTER SMALL M;Lm;0;L;<super> 006D;;;;N;;;;; +1D51;MODIFIER LETTER SMALL ENG;Lm;0;L;<super> 014B;;;;N;;;;; +1D52;MODIFIER LETTER SMALL O;Lm;0;L;<super> 006F;;;;N;;;;; +1D53;MODIFIER LETTER SMALL OPEN O;Lm;0;L;<super> 0254;;;;N;;;;; +1D54;MODIFIER LETTER SMALL TOP HALF O;Lm;0;L;<super> 1D16;;;;N;;;;; +1D55;MODIFIER LETTER SMALL BOTTOM HALF O;Lm;0;L;<super> 1D17;;;;N;;;;; +1D56;MODIFIER LETTER SMALL P;Lm;0;L;<super> 0070;;;;N;;;;; +1D57;MODIFIER LETTER SMALL T;Lm;0;L;<super> 0074;;;;N;;;;; +1D58;MODIFIER LETTER SMALL U;Lm;0;L;<super> 0075;;;;N;;;;; +1D59;MODIFIER LETTER SMALL SIDEWAYS U;Lm;0;L;<super> 1D1D;;;;N;;;;; +1D5A;MODIFIER LETTER SMALL TURNED M;Lm;0;L;<super> 026F;;;;N;;;;; +1D5B;MODIFIER LETTER SMALL V;Lm;0;L;<super> 0076;;;;N;;;;; +1D5C;MODIFIER LETTER SMALL AIN;Lm;0;L;<super> 1D25;;;;N;;;;; +1D5D;MODIFIER LETTER SMALL BETA;Lm;0;L;<super> 03B2;;;;N;;;;; +1D5E;MODIFIER LETTER SMALL GREEK GAMMA;Lm;0;L;<super> 03B3;;;;N;;;;; +1D5F;MODIFIER LETTER SMALL DELTA;Lm;0;L;<super> 03B4;;;;N;;;;; +1D60;MODIFIER LETTER SMALL GREEK PHI;Lm;0;L;<super> 03C6;;;;N;;;;; +1D61;MODIFIER LETTER SMALL CHI;Lm;0;L;<super> 03C7;;;;N;;;;; +1D62;LATIN SUBSCRIPT SMALL LETTER I;Ll;0;L;<sub> 0069;;;;N;;;;; +1D63;LATIN SUBSCRIPT SMALL LETTER R;Ll;0;L;<sub> 0072;;;;N;;;;; +1D64;LATIN SUBSCRIPT SMALL LETTER U;Ll;0;L;<sub> 0075;;;;N;;;;; +1D65;LATIN SUBSCRIPT SMALL LETTER V;Ll;0;L;<sub> 0076;;;;N;;;;; +1D66;GREEK SUBSCRIPT SMALL LETTER BETA;Ll;0;L;<sub> 03B2;;;;N;;;;; +1D67;GREEK SUBSCRIPT SMALL LETTER GAMMA;Ll;0;L;<sub> 03B3;;;;N;;;;; +1D68;GREEK SUBSCRIPT SMALL LETTER RHO;Ll;0;L;<sub> 03C1;;;;N;;;;; +1D69;GREEK SUBSCRIPT SMALL LETTER PHI;Ll;0;L;<sub> 03C6;;;;N;;;;; +1D6A;GREEK SUBSCRIPT SMALL LETTER CHI;Ll;0;L;<sub> 03C7;;;;N;;;;; +1D6B;LATIN SMALL LETTER UE;Ll;0;L;;;;;N;;;;; +1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01; +1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00 +1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03; +1E03;LATIN SMALL LETTER B WITH DOT ABOVE;Ll;0;L;0062 0307;;;;N;;;1E02;;1E02 +1E04;LATIN CAPITAL LETTER B WITH DOT BELOW;Lu;0;L;0042 0323;;;;N;;;;1E05; +1E05;LATIN SMALL LETTER B WITH DOT BELOW;Ll;0;L;0062 0323;;;;N;;;1E04;;1E04 +1E06;LATIN CAPITAL LETTER B WITH LINE BELOW;Lu;0;L;0042 0331;;;;N;;;;1E07; +1E07;LATIN SMALL LETTER B WITH LINE BELOW;Ll;0;L;0062 0331;;;;N;;;1E06;;1E06 +1E08;LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE;Lu;0;L;00C7 0301;;;;N;;;;1E09; +1E09;LATIN SMALL LETTER C WITH CEDILLA AND ACUTE;Ll;0;L;00E7 0301;;;;N;;;1E08;;1E08 +1E0A;LATIN CAPITAL LETTER D WITH DOT ABOVE;Lu;0;L;0044 0307;;;;N;;;;1E0B; +1E0B;LATIN SMALL LETTER D WITH DOT ABOVE;Ll;0;L;0064 0307;;;;N;;;1E0A;;1E0A +1E0C;LATIN CAPITAL LETTER D WITH DOT BELOW;Lu;0;L;0044 0323;;;;N;;;;1E0D; +1E0D;LATIN SMALL LETTER D WITH DOT BELOW;Ll;0;L;0064 0323;;;;N;;;1E0C;;1E0C +1E0E;LATIN CAPITAL LETTER D WITH LINE BELOW;Lu;0;L;0044 0331;;;;N;;;;1E0F; +1E0F;LATIN SMALL LETTER D WITH LINE BELOW;Ll;0;L;0064 0331;;;;N;;;1E0E;;1E0E +1E10;LATIN CAPITAL LETTER D WITH CEDILLA;Lu;0;L;0044 0327;;;;N;;;;1E11; +1E11;LATIN SMALL LETTER D WITH CEDILLA;Ll;0;L;0064 0327;;;;N;;;1E10;;1E10 +1E12;LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW;Lu;0;L;0044 032D;;;;N;;;;1E13; +1E13;LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW;Ll;0;L;0064 032D;;;;N;;;1E12;;1E12 +1E14;LATIN CAPITAL LETTER E WITH MACRON AND GRAVE;Lu;0;L;0112 0300;;;;N;;;;1E15; +1E15;LATIN SMALL LETTER E WITH MACRON AND GRAVE;Ll;0;L;0113 0300;;;;N;;;1E14;;1E14 +1E16;LATIN CAPITAL LETTER E WITH MACRON AND ACUTE;Lu;0;L;0112 0301;;;;N;;;;1E17; +1E17;LATIN SMALL LETTER E WITH MACRON AND ACUTE;Ll;0;L;0113 0301;;;;N;;;1E16;;1E16 +1E18;LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW;Lu;0;L;0045 032D;;;;N;;;;1E19; +1E19;LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW;Ll;0;L;0065 032D;;;;N;;;1E18;;1E18 +1E1A;LATIN CAPITAL LETTER E WITH TILDE BELOW;Lu;0;L;0045 0330;;;;N;;;;1E1B; +1E1B;LATIN SMALL LETTER E WITH TILDE BELOW;Ll;0;L;0065 0330;;;;N;;;1E1A;;1E1A +1E1C;LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE;Lu;0;L;0228 0306;;;;N;;;;1E1D; +1E1D;LATIN SMALL LETTER E WITH CEDILLA AND BREVE;Ll;0;L;0229 0306;;;;N;;;1E1C;;1E1C +1E1E;LATIN CAPITAL LETTER F WITH DOT ABOVE;Lu;0;L;0046 0307;;;;N;;;;1E1F; +1E1F;LATIN SMALL LETTER F WITH DOT ABOVE;Ll;0;L;0066 0307;;;;N;;;1E1E;;1E1E +1E20;LATIN CAPITAL LETTER G WITH MACRON;Lu;0;L;0047 0304;;;;N;;;;1E21; +1E21;LATIN SMALL LETTER G WITH MACRON;Ll;0;L;0067 0304;;;;N;;;1E20;;1E20 +1E22;LATIN CAPITAL LETTER H WITH DOT ABOVE;Lu;0;L;0048 0307;;;;N;;;;1E23; +1E23;LATIN SMALL LETTER H WITH DOT ABOVE;Ll;0;L;0068 0307;;;;N;;;1E22;;1E22 +1E24;LATIN CAPITAL LETTER H WITH DOT BELOW;Lu;0;L;0048 0323;;;;N;;;;1E25; +1E25;LATIN SMALL LETTER H WITH DOT BELOW;Ll;0;L;0068 0323;;;;N;;;1E24;;1E24 +1E26;LATIN CAPITAL LETTER H WITH DIAERESIS;Lu;0;L;0048 0308;;;;N;;;;1E27; +1E27;LATIN SMALL LETTER H WITH DIAERESIS;Ll;0;L;0068 0308;;;;N;;;1E26;;1E26 +1E28;LATIN CAPITAL LETTER H WITH CEDILLA;Lu;0;L;0048 0327;;;;N;;;;1E29; +1E29;LATIN SMALL LETTER H WITH CEDILLA;Ll;0;L;0068 0327;;;;N;;;1E28;;1E28 +1E2A;LATIN CAPITAL LETTER H WITH BREVE BELOW;Lu;0;L;0048 032E;;;;N;;;;1E2B; +1E2B;LATIN SMALL LETTER H WITH BREVE BELOW;Ll;0;L;0068 032E;;;;N;;;1E2A;;1E2A +1E2C;LATIN CAPITAL LETTER I WITH TILDE BELOW;Lu;0;L;0049 0330;;;;N;;;;1E2D; +1E2D;LATIN SMALL LETTER I WITH TILDE BELOW;Ll;0;L;0069 0330;;;;N;;;1E2C;;1E2C +1E2E;LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE;Lu;0;L;00CF 0301;;;;N;;;;1E2F; +1E2F;LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE;Ll;0;L;00EF 0301;;;;N;;;1E2E;;1E2E +1E30;LATIN CAPITAL LETTER K WITH ACUTE;Lu;0;L;004B 0301;;;;N;;;;1E31; +1E31;LATIN SMALL LETTER K WITH ACUTE;Ll;0;L;006B 0301;;;;N;;;1E30;;1E30 +1E32;LATIN CAPITAL LETTER K WITH DOT BELOW;Lu;0;L;004B 0323;;;;N;;;;1E33; +1E33;LATIN SMALL LETTER K WITH DOT BELOW;Ll;0;L;006B 0323;;;;N;;;1E32;;1E32 +1E34;LATIN CAPITAL LETTER K WITH LINE BELOW;Lu;0;L;004B 0331;;;;N;;;;1E35; +1E35;LATIN SMALL LETTER K WITH LINE BELOW;Ll;0;L;006B 0331;;;;N;;;1E34;;1E34 +1E36;LATIN CAPITAL LETTER L WITH DOT BELOW;Lu;0;L;004C 0323;;;;N;;;;1E37; +1E37;LATIN SMALL LETTER L WITH DOT BELOW;Ll;0;L;006C 0323;;;;N;;;1E36;;1E36 +1E38;LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON;Lu;0;L;1E36 0304;;;;N;;;;1E39; +1E39;LATIN SMALL LETTER L WITH DOT BELOW AND MACRON;Ll;0;L;1E37 0304;;;;N;;;1E38;;1E38 +1E3A;LATIN CAPITAL LETTER L WITH LINE BELOW;Lu;0;L;004C 0331;;;;N;;;;1E3B; +1E3B;LATIN SMALL LETTER L WITH LINE BELOW;Ll;0;L;006C 0331;;;;N;;;1E3A;;1E3A +1E3C;LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW;Lu;0;L;004C 032D;;;;N;;;;1E3D; +1E3D;LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW;Ll;0;L;006C 032D;;;;N;;;1E3C;;1E3C +1E3E;LATIN CAPITAL LETTER M WITH ACUTE;Lu;0;L;004D 0301;;;;N;;;;1E3F; +1E3F;LATIN SMALL LETTER M WITH ACUTE;Ll;0;L;006D 0301;;;;N;;;1E3E;;1E3E +1E40;LATIN CAPITAL LETTER M WITH DOT ABOVE;Lu;0;L;004D 0307;;;;N;;;;1E41; +1E41;LATIN SMALL LETTER M WITH DOT ABOVE;Ll;0;L;006D 0307;;;;N;;;1E40;;1E40 +1E42;LATIN CAPITAL LETTER M WITH DOT BELOW;Lu;0;L;004D 0323;;;;N;;;;1E43; +1E43;LATIN SMALL LETTER M WITH DOT BELOW;Ll;0;L;006D 0323;;;;N;;;1E42;;1E42 +1E44;LATIN CAPITAL LETTER N WITH DOT ABOVE;Lu;0;L;004E 0307;;;;N;;;;1E45; +1E45;LATIN SMALL LETTER N WITH DOT ABOVE;Ll;0;L;006E 0307;;;;N;;;1E44;;1E44 +1E46;LATIN CAPITAL LETTER N WITH DOT BELOW;Lu;0;L;004E 0323;;;;N;;;;1E47; +1E47;LATIN SMALL LETTER N WITH DOT BELOW;Ll;0;L;006E 0323;;;;N;;;1E46;;1E46 +1E48;LATIN CAPITAL LETTER N WITH LINE BELOW;Lu;0;L;004E 0331;;;;N;;;;1E49; +1E49;LATIN SMALL LETTER N WITH LINE BELOW;Ll;0;L;006E 0331;;;;N;;;1E48;;1E48 +1E4A;LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW;Lu;0;L;004E 032D;;;;N;;;;1E4B; +1E4B;LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW;Ll;0;L;006E 032D;;;;N;;;1E4A;;1E4A +1E4C;LATIN CAPITAL LETTER O WITH TILDE AND ACUTE;Lu;0;L;00D5 0301;;;;N;;;;1E4D; +1E4D;LATIN SMALL LETTER O WITH TILDE AND ACUTE;Ll;0;L;00F5 0301;;;;N;;;1E4C;;1E4C +1E4E;LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS;Lu;0;L;00D5 0308;;;;N;;;;1E4F; +1E4F;LATIN SMALL LETTER O WITH TILDE AND DIAERESIS;Ll;0;L;00F5 0308;;;;N;;;1E4E;;1E4E +1E50;LATIN CAPITAL LETTER O WITH MACRON AND GRAVE;Lu;0;L;014C 0300;;;;N;;;;1E51; +1E51;LATIN SMALL LETTER O WITH MACRON AND GRAVE;Ll;0;L;014D 0300;;;;N;;;1E50;;1E50 +1E52;LATIN CAPITAL LETTER O WITH MACRON AND ACUTE;Lu;0;L;014C 0301;;;;N;;;;1E53; +1E53;LATIN SMALL LETTER O WITH MACRON AND ACUTE;Ll;0;L;014D 0301;;;;N;;;1E52;;1E52 +1E54;LATIN CAPITAL LETTER P WITH ACUTE;Lu;0;L;0050 0301;;;;N;;;;1E55; +1E55;LATIN SMALL LETTER P WITH ACUTE;Ll;0;L;0070 0301;;;;N;;;1E54;;1E54 +1E56;LATIN CAPITAL LETTER P WITH DOT ABOVE;Lu;0;L;0050 0307;;;;N;;;;1E57; +1E57;LATIN SMALL LETTER P WITH DOT ABOVE;Ll;0;L;0070 0307;;;;N;;;1E56;;1E56 +1E58;LATIN CAPITAL LETTER R WITH DOT ABOVE;Lu;0;L;0052 0307;;;;N;;;;1E59; +1E59;LATIN SMALL LETTER R WITH DOT ABOVE;Ll;0;L;0072 0307;;;;N;;;1E58;;1E58 +1E5A;LATIN CAPITAL LETTER R WITH DOT BELOW;Lu;0;L;0052 0323;;;;N;;;;1E5B; +1E5B;LATIN SMALL LETTER R WITH DOT BELOW;Ll;0;L;0072 0323;;;;N;;;1E5A;;1E5A +1E5C;LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON;Lu;0;L;1E5A 0304;;;;N;;;;1E5D; +1E5D;LATIN SMALL LETTER R WITH DOT BELOW AND MACRON;Ll;0;L;1E5B 0304;;;;N;;;1E5C;;1E5C +1E5E;LATIN CAPITAL LETTER R WITH LINE BELOW;Lu;0;L;0052 0331;;;;N;;;;1E5F; +1E5F;LATIN SMALL LETTER R WITH LINE BELOW;Ll;0;L;0072 0331;;;;N;;;1E5E;;1E5E +1E60;LATIN CAPITAL LETTER S WITH DOT ABOVE;Lu;0;L;0053 0307;;;;N;;;;1E61; +1E61;LATIN SMALL LETTER S WITH DOT ABOVE;Ll;0;L;0073 0307;;;;N;;;1E60;;1E60 +1E62;LATIN CAPITAL LETTER S WITH DOT BELOW;Lu;0;L;0053 0323;;;;N;;;;1E63; +1E63;LATIN SMALL LETTER S WITH DOT BELOW;Ll;0;L;0073 0323;;;;N;;;1E62;;1E62 +1E64;LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE;Lu;0;L;015A 0307;;;;N;;;;1E65; +1E65;LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE;Ll;0;L;015B 0307;;;;N;;;1E64;;1E64 +1E66;LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE;Lu;0;L;0160 0307;;;;N;;;;1E67; +1E67;LATIN SMALL LETTER S WITH CARON AND DOT ABOVE;Ll;0;L;0161 0307;;;;N;;;1E66;;1E66 +1E68;LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE;Lu;0;L;1E62 0307;;;;N;;;;1E69; +1E69;LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE;Ll;0;L;1E63 0307;;;;N;;;1E68;;1E68 +1E6A;LATIN CAPITAL LETTER T WITH DOT ABOVE;Lu;0;L;0054 0307;;;;N;;;;1E6B; +1E6B;LATIN SMALL LETTER T WITH DOT ABOVE;Ll;0;L;0074 0307;;;;N;;;1E6A;;1E6A +1E6C;LATIN CAPITAL LETTER T WITH DOT BELOW;Lu;0;L;0054 0323;;;;N;;;;1E6D; +1E6D;LATIN SMALL LETTER T WITH DOT BELOW;Ll;0;L;0074 0323;;;;N;;;1E6C;;1E6C +1E6E;LATIN CAPITAL LETTER T WITH LINE BELOW;Lu;0;L;0054 0331;;;;N;;;;1E6F; +1E6F;LATIN SMALL LETTER T WITH LINE BELOW;Ll;0;L;0074 0331;;;;N;;;1E6E;;1E6E +1E70;LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW;Lu;0;L;0054 032D;;;;N;;;;1E71; +1E71;LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW;Ll;0;L;0074 032D;;;;N;;;1E70;;1E70 +1E72;LATIN CAPITAL LETTER U WITH DIAERESIS BELOW;Lu;0;L;0055 0324;;;;N;;;;1E73; +1E73;LATIN SMALL LETTER U WITH DIAERESIS BELOW;Ll;0;L;0075 0324;;;;N;;;1E72;;1E72 +1E74;LATIN CAPITAL LETTER U WITH TILDE BELOW;Lu;0;L;0055 0330;;;;N;;;;1E75; +1E75;LATIN SMALL LETTER U WITH TILDE BELOW;Ll;0;L;0075 0330;;;;N;;;1E74;;1E74 +1E76;LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW;Lu;0;L;0055 032D;;;;N;;;;1E77; +1E77;LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW;Ll;0;L;0075 032D;;;;N;;;1E76;;1E76 +1E78;LATIN CAPITAL LETTER U WITH TILDE AND ACUTE;Lu;0;L;0168 0301;;;;N;;;;1E79; +1E79;LATIN SMALL LETTER U WITH TILDE AND ACUTE;Ll;0;L;0169 0301;;;;N;;;1E78;;1E78 +1E7A;LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS;Lu;0;L;016A 0308;;;;N;;;;1E7B; +1E7B;LATIN SMALL LETTER U WITH MACRON AND DIAERESIS;Ll;0;L;016B 0308;;;;N;;;1E7A;;1E7A +1E7C;LATIN CAPITAL LETTER V WITH TILDE;Lu;0;L;0056 0303;;;;N;;;;1E7D; +1E7D;LATIN SMALL LETTER V WITH TILDE;Ll;0;L;0076 0303;;;;N;;;1E7C;;1E7C +1E7E;LATIN CAPITAL LETTER V WITH DOT BELOW;Lu;0;L;0056 0323;;;;N;;;;1E7F; +1E7F;LATIN SMALL LETTER V WITH DOT BELOW;Ll;0;L;0076 0323;;;;N;;;1E7E;;1E7E +1E80;LATIN CAPITAL LETTER W WITH GRAVE;Lu;0;L;0057 0300;;;;N;;;;1E81; +1E81;LATIN SMALL LETTER W WITH GRAVE;Ll;0;L;0077 0300;;;;N;;;1E80;;1E80 +1E82;LATIN CAPITAL LETTER W WITH ACUTE;Lu;0;L;0057 0301;;;;N;;;;1E83; +1E83;LATIN SMALL LETTER W WITH ACUTE;Ll;0;L;0077 0301;;;;N;;;1E82;;1E82 +1E84;LATIN CAPITAL LETTER W WITH DIAERESIS;Lu;0;L;0057 0308;;;;N;;;;1E85; +1E85;LATIN SMALL LETTER W WITH DIAERESIS;Ll;0;L;0077 0308;;;;N;;;1E84;;1E84 +1E86;LATIN CAPITAL LETTER W WITH DOT ABOVE;Lu;0;L;0057 0307;;;;N;;;;1E87; +1E87;LATIN SMALL LETTER W WITH DOT ABOVE;Ll;0;L;0077 0307;;;;N;;;1E86;;1E86 +1E88;LATIN CAPITAL LETTER W WITH DOT BELOW;Lu;0;L;0057 0323;;;;N;;;;1E89; +1E89;LATIN SMALL LETTER W WITH DOT BELOW;Ll;0;L;0077 0323;;;;N;;;1E88;;1E88 +1E8A;LATIN CAPITAL LETTER X WITH DOT ABOVE;Lu;0;L;0058 0307;;;;N;;;;1E8B; +1E8B;LATIN SMALL LETTER X WITH DOT ABOVE;Ll;0;L;0078 0307;;;;N;;;1E8A;;1E8A +1E8C;LATIN CAPITAL LETTER X WITH DIAERESIS;Lu;0;L;0058 0308;;;;N;;;;1E8D; +1E8D;LATIN SMALL LETTER X WITH DIAERESIS;Ll;0;L;0078 0308;;;;N;;;1E8C;;1E8C +1E8E;LATIN CAPITAL LETTER Y WITH DOT ABOVE;Lu;0;L;0059 0307;;;;N;;;;1E8F; +1E8F;LATIN SMALL LETTER Y WITH DOT ABOVE;Ll;0;L;0079 0307;;;;N;;;1E8E;;1E8E +1E90;LATIN CAPITAL LETTER Z WITH CIRCUMFLEX;Lu;0;L;005A 0302;;;;N;;;;1E91; +1E91;LATIN SMALL LETTER Z WITH CIRCUMFLEX;Ll;0;L;007A 0302;;;;N;;;1E90;;1E90 +1E92;LATIN CAPITAL LETTER Z WITH DOT BELOW;Lu;0;L;005A 0323;;;;N;;;;1E93; +1E93;LATIN SMALL LETTER Z WITH DOT BELOW;Ll;0;L;007A 0323;;;;N;;;1E92;;1E92 +1E94;LATIN CAPITAL LETTER Z WITH LINE BELOW;Lu;0;L;005A 0331;;;;N;;;;1E95; +1E95;LATIN SMALL LETTER Z WITH LINE BELOW;Ll;0;L;007A 0331;;;;N;;;1E94;;1E94 +1E96;LATIN SMALL LETTER H WITH LINE BELOW;Ll;0;L;0068 0331;;;;N;;;;; +1E97;LATIN SMALL LETTER T WITH DIAERESIS;Ll;0;L;0074 0308;;;;N;;;;; +1E98;LATIN SMALL LETTER W WITH RING ABOVE;Ll;0;L;0077 030A;;;;N;;;;; +1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;; +1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L;<compat> 0061 02BE;;;;N;;;;; +1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60 +1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1; +1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0 +1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3; +1EA3;LATIN SMALL LETTER A WITH HOOK ABOVE;Ll;0;L;0061 0309;;;;N;;;1EA2;;1EA2 +1EA4;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00C2 0301;;;;N;;;;1EA5; +1EA5;LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00E2 0301;;;;N;;;1EA4;;1EA4 +1EA6;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00C2 0300;;;;N;;;;1EA7; +1EA7;LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00E2 0300;;;;N;;;1EA6;;1EA6 +1EA8;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00C2 0309;;;;N;;;;1EA9; +1EA9;LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00E2 0309;;;;N;;;1EA8;;1EA8 +1EAA;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE;Lu;0;L;00C2 0303;;;;N;;;;1EAB; +1EAB;LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE;Ll;0;L;00E2 0303;;;;N;;;1EAA;;1EAA +1EAC;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EA0 0302;;;;N;;;;1EAD; +1EAD;LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EA1 0302;;;;N;;;1EAC;;1EAC +1EAE;LATIN CAPITAL LETTER A WITH BREVE AND ACUTE;Lu;0;L;0102 0301;;;;N;;;;1EAF; +1EAF;LATIN SMALL LETTER A WITH BREVE AND ACUTE;Ll;0;L;0103 0301;;;;N;;;1EAE;;1EAE +1EB0;LATIN CAPITAL LETTER A WITH BREVE AND GRAVE;Lu;0;L;0102 0300;;;;N;;;;1EB1; +1EB1;LATIN SMALL LETTER A WITH BREVE AND GRAVE;Ll;0;L;0103 0300;;;;N;;;1EB0;;1EB0 +1EB2;LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE;Lu;0;L;0102 0309;;;;N;;;;1EB3; +1EB3;LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE;Ll;0;L;0103 0309;;;;N;;;1EB2;;1EB2 +1EB4;LATIN CAPITAL LETTER A WITH BREVE AND TILDE;Lu;0;L;0102 0303;;;;N;;;;1EB5; +1EB5;LATIN SMALL LETTER A WITH BREVE AND TILDE;Ll;0;L;0103 0303;;;;N;;;1EB4;;1EB4 +1EB6;LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW;Lu;0;L;1EA0 0306;;;;N;;;;1EB7; +1EB7;LATIN SMALL LETTER A WITH BREVE AND DOT BELOW;Ll;0;L;1EA1 0306;;;;N;;;1EB6;;1EB6 +1EB8;LATIN CAPITAL LETTER E WITH DOT BELOW;Lu;0;L;0045 0323;;;;N;;;;1EB9; +1EB9;LATIN SMALL LETTER E WITH DOT BELOW;Ll;0;L;0065 0323;;;;N;;;1EB8;;1EB8 +1EBA;LATIN CAPITAL LETTER E WITH HOOK ABOVE;Lu;0;L;0045 0309;;;;N;;;;1EBB; +1EBB;LATIN SMALL LETTER E WITH HOOK ABOVE;Ll;0;L;0065 0309;;;;N;;;1EBA;;1EBA +1EBC;LATIN CAPITAL LETTER E WITH TILDE;Lu;0;L;0045 0303;;;;N;;;;1EBD; +1EBD;LATIN SMALL LETTER E WITH TILDE;Ll;0;L;0065 0303;;;;N;;;1EBC;;1EBC +1EBE;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00CA 0301;;;;N;;;;1EBF; +1EBF;LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00EA 0301;;;;N;;;1EBE;;1EBE +1EC0;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00CA 0300;;;;N;;;;1EC1; +1EC1;LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00EA 0300;;;;N;;;1EC0;;1EC0 +1EC2;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00CA 0309;;;;N;;;;1EC3; +1EC3;LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00EA 0309;;;;N;;;1EC2;;1EC2 +1EC4;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE;Lu;0;L;00CA 0303;;;;N;;;;1EC5; +1EC5;LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE;Ll;0;L;00EA 0303;;;;N;;;1EC4;;1EC4 +1EC6;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EB8 0302;;;;N;;;;1EC7; +1EC7;LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EB9 0302;;;;N;;;1EC6;;1EC6 +1EC8;LATIN CAPITAL LETTER I WITH HOOK ABOVE;Lu;0;L;0049 0309;;;;N;;;;1EC9; +1EC9;LATIN SMALL LETTER I WITH HOOK ABOVE;Ll;0;L;0069 0309;;;;N;;;1EC8;;1EC8 +1ECA;LATIN CAPITAL LETTER I WITH DOT BELOW;Lu;0;L;0049 0323;;;;N;;;;1ECB; +1ECB;LATIN SMALL LETTER I WITH DOT BELOW;Ll;0;L;0069 0323;;;;N;;;1ECA;;1ECA +1ECC;LATIN CAPITAL LETTER O WITH DOT BELOW;Lu;0;L;004F 0323;;;;N;;;;1ECD; +1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC +1ECE;LATIN CAPITAL LETTER O WITH HOOK ABOVE;Lu;0;L;004F 0309;;;;N;;;;1ECF; +1ECF;LATIN SMALL LETTER O WITH HOOK ABOVE;Ll;0;L;006F 0309;;;;N;;;1ECE;;1ECE +1ED0;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00D4 0301;;;;N;;;;1ED1; +1ED1;LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00F4 0301;;;;N;;;1ED0;;1ED0 +1ED2;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00D4 0300;;;;N;;;;1ED3; +1ED3;LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00F4 0300;;;;N;;;1ED2;;1ED2 +1ED4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00D4 0309;;;;N;;;;1ED5; +1ED5;LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00F4 0309;;;;N;;;1ED4;;1ED4 +1ED6;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE;Lu;0;L;00D4 0303;;;;N;;;;1ED7; +1ED7;LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE;Ll;0;L;00F4 0303;;;;N;;;1ED6;;1ED6 +1ED8;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1ECC 0302;;;;N;;;;1ED9; +1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8 +1EDA;LATIN CAPITAL LETTER O WITH HORN AND ACUTE;Lu;0;L;01A0 0301;;;;N;;;;1EDB; +1EDB;LATIN SMALL LETTER O WITH HORN AND ACUTE;Ll;0;L;01A1 0301;;;;N;;;1EDA;;1EDA +1EDC;LATIN CAPITAL LETTER O WITH HORN AND GRAVE;Lu;0;L;01A0 0300;;;;N;;;;1EDD; +1EDD;LATIN SMALL LETTER O WITH HORN AND GRAVE;Ll;0;L;01A1 0300;;;;N;;;1EDC;;1EDC +1EDE;LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE;Lu;0;L;01A0 0309;;;;N;;;;1EDF; +1EDF;LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE;Ll;0;L;01A1 0309;;;;N;;;1EDE;;1EDE +1EE0;LATIN CAPITAL LETTER O WITH HORN AND TILDE;Lu;0;L;01A0 0303;;;;N;;;;1EE1; +1EE1;LATIN SMALL LETTER O WITH HORN AND TILDE;Ll;0;L;01A1 0303;;;;N;;;1EE0;;1EE0 +1EE2;LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW;Lu;0;L;01A0 0323;;;;N;;;;1EE3; +1EE3;LATIN SMALL LETTER O WITH HORN AND DOT BELOW;Ll;0;L;01A1 0323;;;;N;;;1EE2;;1EE2 +1EE4;LATIN CAPITAL LETTER U WITH DOT BELOW;Lu;0;L;0055 0323;;;;N;;;;1EE5; +1EE5;LATIN SMALL LETTER U WITH DOT BELOW;Ll;0;L;0075 0323;;;;N;;;1EE4;;1EE4 +1EE6;LATIN CAPITAL LETTER U WITH HOOK ABOVE;Lu;0;L;0055 0309;;;;N;;;;1EE7; +1EE7;LATIN SMALL LETTER U WITH HOOK ABOVE;Ll;0;L;0075 0309;;;;N;;;1EE6;;1EE6 +1EE8;LATIN CAPITAL LETTER U WITH HORN AND ACUTE;Lu;0;L;01AF 0301;;;;N;;;;1EE9; +1EE9;LATIN SMALL LETTER U WITH HORN AND ACUTE;Ll;0;L;01B0 0301;;;;N;;;1EE8;;1EE8 +1EEA;LATIN CAPITAL LETTER U WITH HORN AND GRAVE;Lu;0;L;01AF 0300;;;;N;;;;1EEB; +1EEB;LATIN SMALL LETTER U WITH HORN AND GRAVE;Ll;0;L;01B0 0300;;;;N;;;1EEA;;1EEA +1EEC;LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE;Lu;0;L;01AF 0309;;;;N;;;;1EED; +1EED;LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE;Ll;0;L;01B0 0309;;;;N;;;1EEC;;1EEC +1EEE;LATIN CAPITAL LETTER U WITH HORN AND TILDE;Lu;0;L;01AF 0303;;;;N;;;;1EEF; +1EEF;LATIN SMALL LETTER U WITH HORN AND TILDE;Ll;0;L;01B0 0303;;;;N;;;1EEE;;1EEE +1EF0;LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW;Lu;0;L;01AF 0323;;;;N;;;;1EF1; +1EF1;LATIN SMALL LETTER U WITH HORN AND DOT BELOW;Ll;0;L;01B0 0323;;;;N;;;1EF0;;1EF0 +1EF2;LATIN CAPITAL LETTER Y WITH GRAVE;Lu;0;L;0059 0300;;;;N;;;;1EF3; +1EF3;LATIN SMALL LETTER Y WITH GRAVE;Ll;0;L;0079 0300;;;;N;;;1EF2;;1EF2 +1EF4;LATIN CAPITAL LETTER Y WITH DOT BELOW;Lu;0;L;0059 0323;;;;N;;;;1EF5; +1EF5;LATIN SMALL LETTER Y WITH DOT BELOW;Ll;0;L;0079 0323;;;;N;;;1EF4;;1EF4 +1EF6;LATIN CAPITAL LETTER Y WITH HOOK ABOVE;Lu;0;L;0059 0309;;;;N;;;;1EF7; +1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6 +1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9; +1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8 +1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08 +1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09 +1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A +1F03;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA;Ll;0;L;1F01 0300;;;;N;;;1F0B;;1F0B +1F04;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA;Ll;0;L;1F00 0301;;;;N;;;1F0C;;1F0C +1F05;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA;Ll;0;L;1F01 0301;;;;N;;;1F0D;;1F0D +1F06;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI;Ll;0;L;1F00 0342;;;;N;;;1F0E;;1F0E +1F07;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI;Ll;0;L;1F01 0342;;;;N;;;1F0F;;1F0F +1F08;GREEK CAPITAL LETTER ALPHA WITH PSILI;Lu;0;L;0391 0313;;;;N;;;;1F00; +1F09;GREEK CAPITAL LETTER ALPHA WITH DASIA;Lu;0;L;0391 0314;;;;N;;;;1F01; +1F0A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA;Lu;0;L;1F08 0300;;;;N;;;;1F02; +1F0B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA;Lu;0;L;1F09 0300;;;;N;;;;1F03; +1F0C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA;Lu;0;L;1F08 0301;;;;N;;;;1F04; +1F0D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA;Lu;0;L;1F09 0301;;;;N;;;;1F05; +1F0E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI;Lu;0;L;1F08 0342;;;;N;;;;1F06; +1F0F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI;Lu;0;L;1F09 0342;;;;N;;;;1F07; +1F10;GREEK SMALL LETTER EPSILON WITH PSILI;Ll;0;L;03B5 0313;;;;N;;;1F18;;1F18 +1F11;GREEK SMALL LETTER EPSILON WITH DASIA;Ll;0;L;03B5 0314;;;;N;;;1F19;;1F19 +1F12;GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA;Ll;0;L;1F10 0300;;;;N;;;1F1A;;1F1A +1F13;GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA;Ll;0;L;1F11 0300;;;;N;;;1F1B;;1F1B +1F14;GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA;Ll;0;L;1F10 0301;;;;N;;;1F1C;;1F1C +1F15;GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA;Ll;0;L;1F11 0301;;;;N;;;1F1D;;1F1D +1F18;GREEK CAPITAL LETTER EPSILON WITH PSILI;Lu;0;L;0395 0313;;;;N;;;;1F10; +1F19;GREEK CAPITAL LETTER EPSILON WITH DASIA;Lu;0;L;0395 0314;;;;N;;;;1F11; +1F1A;GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA;Lu;0;L;1F18 0300;;;;N;;;;1F12; +1F1B;GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA;Lu;0;L;1F19 0300;;;;N;;;;1F13; +1F1C;GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA;Lu;0;L;1F18 0301;;;;N;;;;1F14; +1F1D;GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA;Lu;0;L;1F19 0301;;;;N;;;;1F15; +1F20;GREEK SMALL LETTER ETA WITH PSILI;Ll;0;L;03B7 0313;;;;N;;;1F28;;1F28 +1F21;GREEK SMALL LETTER ETA WITH DASIA;Ll;0;L;03B7 0314;;;;N;;;1F29;;1F29 +1F22;GREEK SMALL LETTER ETA WITH PSILI AND VARIA;Ll;0;L;1F20 0300;;;;N;;;1F2A;;1F2A +1F23;GREEK SMALL LETTER ETA WITH DASIA AND VARIA;Ll;0;L;1F21 0300;;;;N;;;1F2B;;1F2B +1F24;GREEK SMALL LETTER ETA WITH PSILI AND OXIA;Ll;0;L;1F20 0301;;;;N;;;1F2C;;1F2C +1F25;GREEK SMALL LETTER ETA WITH DASIA AND OXIA;Ll;0;L;1F21 0301;;;;N;;;1F2D;;1F2D +1F26;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI;Ll;0;L;1F20 0342;;;;N;;;1F2E;;1F2E +1F27;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI;Ll;0;L;1F21 0342;;;;N;;;1F2F;;1F2F +1F28;GREEK CAPITAL LETTER ETA WITH PSILI;Lu;0;L;0397 0313;;;;N;;;;1F20; +1F29;GREEK CAPITAL LETTER ETA WITH DASIA;Lu;0;L;0397 0314;;;;N;;;;1F21; +1F2A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA;Lu;0;L;1F28 0300;;;;N;;;;1F22; +1F2B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA;Lu;0;L;1F29 0300;;;;N;;;;1F23; +1F2C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA;Lu;0;L;1F28 0301;;;;N;;;;1F24; +1F2D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA;Lu;0;L;1F29 0301;;;;N;;;;1F25; +1F2E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI;Lu;0;L;1F28 0342;;;;N;;;;1F26; +1F2F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI;Lu;0;L;1F29 0342;;;;N;;;;1F27; +1F30;GREEK SMALL LETTER IOTA WITH PSILI;Ll;0;L;03B9 0313;;;;N;;;1F38;;1F38 +1F31;GREEK SMALL LETTER IOTA WITH DASIA;Ll;0;L;03B9 0314;;;;N;;;1F39;;1F39 +1F32;GREEK SMALL LETTER IOTA WITH PSILI AND VARIA;Ll;0;L;1F30 0300;;;;N;;;1F3A;;1F3A +1F33;GREEK SMALL LETTER IOTA WITH DASIA AND VARIA;Ll;0;L;1F31 0300;;;;N;;;1F3B;;1F3B +1F34;GREEK SMALL LETTER IOTA WITH PSILI AND OXIA;Ll;0;L;1F30 0301;;;;N;;;1F3C;;1F3C +1F35;GREEK SMALL LETTER IOTA WITH DASIA AND OXIA;Ll;0;L;1F31 0301;;;;N;;;1F3D;;1F3D +1F36;GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI;Ll;0;L;1F30 0342;;;;N;;;1F3E;;1F3E +1F37;GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI;Ll;0;L;1F31 0342;;;;N;;;1F3F;;1F3F +1F38;GREEK CAPITAL LETTER IOTA WITH PSILI;Lu;0;L;0399 0313;;;;N;;;;1F30; +1F39;GREEK CAPITAL LETTER IOTA WITH DASIA;Lu;0;L;0399 0314;;;;N;;;;1F31; +1F3A;GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA;Lu;0;L;1F38 0300;;;;N;;;;1F32; +1F3B;GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA;Lu;0;L;1F39 0300;;;;N;;;;1F33; +1F3C;GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA;Lu;0;L;1F38 0301;;;;N;;;;1F34; +1F3D;GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA;Lu;0;L;1F39 0301;;;;N;;;;1F35; +1F3E;GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI;Lu;0;L;1F38 0342;;;;N;;;;1F36; +1F3F;GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI;Lu;0;L;1F39 0342;;;;N;;;;1F37; +1F40;GREEK SMALL LETTER OMICRON WITH PSILI;Ll;0;L;03BF 0313;;;;N;;;1F48;;1F48 +1F41;GREEK SMALL LETTER OMICRON WITH DASIA;Ll;0;L;03BF 0314;;;;N;;;1F49;;1F49 +1F42;GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA;Ll;0;L;1F40 0300;;;;N;;;1F4A;;1F4A +1F43;GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA;Ll;0;L;1F41 0300;;;;N;;;1F4B;;1F4B +1F44;GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA;Ll;0;L;1F40 0301;;;;N;;;1F4C;;1F4C +1F45;GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA;Ll;0;L;1F41 0301;;;;N;;;1F4D;;1F4D +1F48;GREEK CAPITAL LETTER OMICRON WITH PSILI;Lu;0;L;039F 0313;;;;N;;;;1F40; +1F49;GREEK CAPITAL LETTER OMICRON WITH DASIA;Lu;0;L;039F 0314;;;;N;;;;1F41; +1F4A;GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA;Lu;0;L;1F48 0300;;;;N;;;;1F42; +1F4B;GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA;Lu;0;L;1F49 0300;;;;N;;;;1F43; +1F4C;GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA;Lu;0;L;1F48 0301;;;;N;;;;1F44; +1F4D;GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA;Lu;0;L;1F49 0301;;;;N;;;;1F45; +1F50;GREEK SMALL LETTER UPSILON WITH PSILI;Ll;0;L;03C5 0313;;;;N;;;;; +1F51;GREEK SMALL LETTER UPSILON WITH DASIA;Ll;0;L;03C5 0314;;;;N;;;1F59;;1F59 +1F52;GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA;Ll;0;L;1F50 0300;;;;N;;;;; +1F53;GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA;Ll;0;L;1F51 0300;;;;N;;;1F5B;;1F5B +1F54;GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA;Ll;0;L;1F50 0301;;;;N;;;;; +1F55;GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA;Ll;0;L;1F51 0301;;;;N;;;1F5D;;1F5D +1F56;GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI;Ll;0;L;1F50 0342;;;;N;;;;; +1F57;GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI;Ll;0;L;1F51 0342;;;;N;;;1F5F;;1F5F +1F59;GREEK CAPITAL LETTER UPSILON WITH DASIA;Lu;0;L;03A5 0314;;;;N;;;;1F51; +1F5B;GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA;Lu;0;L;1F59 0300;;;;N;;;;1F53; +1F5D;GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA;Lu;0;L;1F59 0301;;;;N;;;;1F55; +1F5F;GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI;Lu;0;L;1F59 0342;;;;N;;;;1F57; +1F60;GREEK SMALL LETTER OMEGA WITH PSILI;Ll;0;L;03C9 0313;;;;N;;;1F68;;1F68 +1F61;GREEK SMALL LETTER OMEGA WITH DASIA;Ll;0;L;03C9 0314;;;;N;;;1F69;;1F69 +1F62;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA;Ll;0;L;1F60 0300;;;;N;;;1F6A;;1F6A +1F63;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA;Ll;0;L;1F61 0300;;;;N;;;1F6B;;1F6B +1F64;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA;Ll;0;L;1F60 0301;;;;N;;;1F6C;;1F6C +1F65;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA;Ll;0;L;1F61 0301;;;;N;;;1F6D;;1F6D +1F66;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI;Ll;0;L;1F60 0342;;;;N;;;1F6E;;1F6E +1F67;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI;Ll;0;L;1F61 0342;;;;N;;;1F6F;;1F6F +1F68;GREEK CAPITAL LETTER OMEGA WITH PSILI;Lu;0;L;03A9 0313;;;;N;;;;1F60; +1F69;GREEK CAPITAL LETTER OMEGA WITH DASIA;Lu;0;L;03A9 0314;;;;N;;;;1F61; +1F6A;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA;Lu;0;L;1F68 0300;;;;N;;;;1F62; +1F6B;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA;Lu;0;L;1F69 0300;;;;N;;;;1F63; +1F6C;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA;Lu;0;L;1F68 0301;;;;N;;;;1F64; +1F6D;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA;Lu;0;L;1F69 0301;;;;N;;;;1F65; +1F6E;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI;Lu;0;L;1F68 0342;;;;N;;;;1F66; +1F6F;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI;Lu;0;L;1F69 0342;;;;N;;;;1F67; +1F70;GREEK SMALL LETTER ALPHA WITH VARIA;Ll;0;L;03B1 0300;;;;N;;;1FBA;;1FBA +1F71;GREEK SMALL LETTER ALPHA WITH OXIA;Ll;0;L;03AC;;;;N;;;1FBB;;1FBB +1F72;GREEK SMALL LETTER EPSILON WITH VARIA;Ll;0;L;03B5 0300;;;;N;;;1FC8;;1FC8 +1F73;GREEK SMALL LETTER EPSILON WITH OXIA;Ll;0;L;03AD;;;;N;;;1FC9;;1FC9 +1F74;GREEK SMALL LETTER ETA WITH VARIA;Ll;0;L;03B7 0300;;;;N;;;1FCA;;1FCA +1F75;GREEK SMALL LETTER ETA WITH OXIA;Ll;0;L;03AE;;;;N;;;1FCB;;1FCB +1F76;GREEK SMALL LETTER IOTA WITH VARIA;Ll;0;L;03B9 0300;;;;N;;;1FDA;;1FDA +1F77;GREEK SMALL LETTER IOTA WITH OXIA;Ll;0;L;03AF;;;;N;;;1FDB;;1FDB +1F78;GREEK SMALL LETTER OMICRON WITH VARIA;Ll;0;L;03BF 0300;;;;N;;;1FF8;;1FF8 +1F79;GREEK SMALL LETTER OMICRON WITH OXIA;Ll;0;L;03CC;;;;N;;;1FF9;;1FF9 +1F7A;GREEK SMALL LETTER UPSILON WITH VARIA;Ll;0;L;03C5 0300;;;;N;;;1FEA;;1FEA +1F7B;GREEK SMALL LETTER UPSILON WITH OXIA;Ll;0;L;03CD;;;;N;;;1FEB;;1FEB +1F7C;GREEK SMALL LETTER OMEGA WITH VARIA;Ll;0;L;03C9 0300;;;;N;;;1FFA;;1FFA +1F7D;GREEK SMALL LETTER OMEGA WITH OXIA;Ll;0;L;03CE;;;;N;;;1FFB;;1FFB +1F80;GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F00 0345;;;;N;;;1F88;;1F88 +1F81;GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F01 0345;;;;N;;;1F89;;1F89 +1F82;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F02 0345;;;;N;;;1F8A;;1F8A +1F83;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F03 0345;;;;N;;;1F8B;;1F8B +1F84;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F04 0345;;;;N;;;1F8C;;1F8C +1F85;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F05 0345;;;;N;;;1F8D;;1F8D +1F86;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F06 0345;;;;N;;;1F8E;;1F8E +1F87;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F07 0345;;;;N;;;1F8F;;1F8F +1F88;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F08 0345;;;;N;;;;1F80; +1F89;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F09 0345;;;;N;;;;1F81; +1F8A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0A 0345;;;;N;;;;1F82; +1F8B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0B 0345;;;;N;;;;1F83; +1F8C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0C 0345;;;;N;;;;1F84; +1F8D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0D 0345;;;;N;;;;1F85; +1F8E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0E 0345;;;;N;;;;1F86; +1F8F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0F 0345;;;;N;;;;1F87; +1F90;GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F20 0345;;;;N;;;1F98;;1F98 +1F91;GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F21 0345;;;;N;;;1F99;;1F99 +1F92;GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F22 0345;;;;N;;;1F9A;;1F9A +1F93;GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F23 0345;;;;N;;;1F9B;;1F9B +1F94;GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F24 0345;;;;N;;;1F9C;;1F9C +1F95;GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F25 0345;;;;N;;;1F9D;;1F9D +1F96;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F26 0345;;;;N;;;1F9E;;1F9E +1F97;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F27 0345;;;;N;;;1F9F;;1F9F +1F98;GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F28 0345;;;;N;;;;1F90; +1F99;GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F29 0345;;;;N;;;;1F91; +1F9A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2A 0345;;;;N;;;;1F92; +1F9B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2B 0345;;;;N;;;;1F93; +1F9C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2C 0345;;;;N;;;;1F94; +1F9D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2D 0345;;;;N;;;;1F95; +1F9E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2E 0345;;;;N;;;;1F96; +1F9F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2F 0345;;;;N;;;;1F97; +1FA0;GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F60 0345;;;;N;;;1FA8;;1FA8 +1FA1;GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F61 0345;;;;N;;;1FA9;;1FA9 +1FA2;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F62 0345;;;;N;;;1FAA;;1FAA +1FA3;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F63 0345;;;;N;;;1FAB;;1FAB +1FA4;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F64 0345;;;;N;;;1FAC;;1FAC +1FA5;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F65 0345;;;;N;;;1FAD;;1FAD +1FA6;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F66 0345;;;;N;;;1FAE;;1FAE +1FA7;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F67 0345;;;;N;;;1FAF;;1FAF +1FA8;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F68 0345;;;;N;;;;1FA0; +1FA9;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F69 0345;;;;N;;;;1FA1; +1FAA;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6A 0345;;;;N;;;;1FA2; +1FAB;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6B 0345;;;;N;;;;1FA3; +1FAC;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6C 0345;;;;N;;;;1FA4; +1FAD;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6D 0345;;;;N;;;;1FA5; +1FAE;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6E 0345;;;;N;;;;1FA6; +1FAF;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6F 0345;;;;N;;;;1FA7; +1FB0;GREEK SMALL LETTER ALPHA WITH VRACHY;Ll;0;L;03B1 0306;;;;N;;;1FB8;;1FB8 +1FB1;GREEK SMALL LETTER ALPHA WITH MACRON;Ll;0;L;03B1 0304;;;;N;;;1FB9;;1FB9 +1FB2;GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F70 0345;;;;N;;;;; +1FB3;GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI;Ll;0;L;03B1 0345;;;;N;;;1FBC;;1FBC +1FB4;GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AC 0345;;;;N;;;;; +1FB6;GREEK SMALL LETTER ALPHA WITH PERISPOMENI;Ll;0;L;03B1 0342;;;;N;;;;; +1FB7;GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FB6 0345;;;;N;;;;; +1FB8;GREEK CAPITAL LETTER ALPHA WITH VRACHY;Lu;0;L;0391 0306;;;;N;;;;1FB0; +1FB9;GREEK CAPITAL LETTER ALPHA WITH MACRON;Lu;0;L;0391 0304;;;;N;;;;1FB1; +1FBA;GREEK CAPITAL LETTER ALPHA WITH VARIA;Lu;0;L;0391 0300;;;;N;;;;1F70; +1FBB;GREEK CAPITAL LETTER ALPHA WITH OXIA;Lu;0;L;0386;;;;N;;;;1F71; +1FBC;GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI;Lt;0;L;0391 0345;;;;N;;;;1FB3; +1FBD;GREEK KORONIS;Sk;0;ON;<compat> 0020 0313;;;;N;;;;; +1FBE;GREEK PROSGEGRAMMENI;Ll;0;L;03B9;;;;N;;;0399;;0399 +1FBF;GREEK PSILI;Sk;0;ON;<compat> 0020 0313;;;;N;;;;; +1FC0;GREEK PERISPOMENI;Sk;0;ON;<compat> 0020 0342;;;;N;;;;; +1FC1;GREEK DIALYTIKA AND PERISPOMENI;Sk;0;ON;00A8 0342;;;;N;;;;; +1FC2;GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F74 0345;;;;N;;;;; +1FC3;GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI;Ll;0;L;03B7 0345;;;;N;;;1FCC;;1FCC +1FC4;GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AE 0345;;;;N;;;;; +1FC6;GREEK SMALL LETTER ETA WITH PERISPOMENI;Ll;0;L;03B7 0342;;;;N;;;;; +1FC7;GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FC6 0345;;;;N;;;;; +1FC8;GREEK CAPITAL LETTER EPSILON WITH VARIA;Lu;0;L;0395 0300;;;;N;;;;1F72; +1FC9;GREEK CAPITAL LETTER EPSILON WITH OXIA;Lu;0;L;0388;;;;N;;;;1F73; +1FCA;GREEK CAPITAL LETTER ETA WITH VARIA;Lu;0;L;0397 0300;;;;N;;;;1F74; +1FCB;GREEK CAPITAL LETTER ETA WITH OXIA;Lu;0;L;0389;;;;N;;;;1F75; +1FCC;GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI;Lt;0;L;0397 0345;;;;N;;;;1FC3; +1FCD;GREEK PSILI AND VARIA;Sk;0;ON;1FBF 0300;;;;N;;;;; +1FCE;GREEK PSILI AND OXIA;Sk;0;ON;1FBF 0301;;;;N;;;;; +1FCF;GREEK PSILI AND PERISPOMENI;Sk;0;ON;1FBF 0342;;;;N;;;;; +1FD0;GREEK SMALL LETTER IOTA WITH VRACHY;Ll;0;L;03B9 0306;;;;N;;;1FD8;;1FD8 +1FD1;GREEK SMALL LETTER IOTA WITH MACRON;Ll;0;L;03B9 0304;;;;N;;;1FD9;;1FD9 +1FD2;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA;Ll;0;L;03CA 0300;;;;N;;;;; +1FD3;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA;Ll;0;L;0390;;;;N;;;;; +1FD6;GREEK SMALL LETTER IOTA WITH PERISPOMENI;Ll;0;L;03B9 0342;;;;N;;;;; +1FD7;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CA 0342;;;;N;;;;; +1FD8;GREEK CAPITAL LETTER IOTA WITH VRACHY;Lu;0;L;0399 0306;;;;N;;;;1FD0; +1FD9;GREEK CAPITAL LETTER IOTA WITH MACRON;Lu;0;L;0399 0304;;;;N;;;;1FD1; +1FDA;GREEK CAPITAL LETTER IOTA WITH VARIA;Lu;0;L;0399 0300;;;;N;;;;1F76; +1FDB;GREEK CAPITAL LETTER IOTA WITH OXIA;Lu;0;L;038A;;;;N;;;;1F77; +1FDD;GREEK DASIA AND VARIA;Sk;0;ON;1FFE 0300;;;;N;;;;; +1FDE;GREEK DASIA AND OXIA;Sk;0;ON;1FFE 0301;;;;N;;;;; +1FDF;GREEK DASIA AND PERISPOMENI;Sk;0;ON;1FFE 0342;;;;N;;;;; +1FE0;GREEK SMALL LETTER UPSILON WITH VRACHY;Ll;0;L;03C5 0306;;;;N;;;1FE8;;1FE8 +1FE1;GREEK SMALL LETTER UPSILON WITH MACRON;Ll;0;L;03C5 0304;;;;N;;;1FE9;;1FE9 +1FE2;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA;Ll;0;L;03CB 0300;;;;N;;;;; +1FE3;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA;Ll;0;L;03B0;;;;N;;;;; +1FE4;GREEK SMALL LETTER RHO WITH PSILI;Ll;0;L;03C1 0313;;;;N;;;;; +1FE5;GREEK SMALL LETTER RHO WITH DASIA;Ll;0;L;03C1 0314;;;;N;;;1FEC;;1FEC +1FE6;GREEK SMALL LETTER UPSILON WITH PERISPOMENI;Ll;0;L;03C5 0342;;;;N;;;;; +1FE7;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CB 0342;;;;N;;;;; +1FE8;GREEK CAPITAL LETTER UPSILON WITH VRACHY;Lu;0;L;03A5 0306;;;;N;;;;1FE0; +1FE9;GREEK CAPITAL LETTER UPSILON WITH MACRON;Lu;0;L;03A5 0304;;;;N;;;;1FE1; +1FEA;GREEK CAPITAL LETTER UPSILON WITH VARIA;Lu;0;L;03A5 0300;;;;N;;;;1F7A; +1FEB;GREEK CAPITAL LETTER UPSILON WITH OXIA;Lu;0;L;038E;;;;N;;;;1F7B; +1FEC;GREEK CAPITAL LETTER RHO WITH DASIA;Lu;0;L;03A1 0314;;;;N;;;;1FE5; +1FED;GREEK DIALYTIKA AND VARIA;Sk;0;ON;00A8 0300;;;;N;;;;; +1FEE;GREEK DIALYTIKA AND OXIA;Sk;0;ON;0385;;;;N;;;;; +1FEF;GREEK VARIA;Sk;0;ON;0060;;;;N;;;;; +1FF2;GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F7C 0345;;;;N;;;;; +1FF3;GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI;Ll;0;L;03C9 0345;;;;N;;;1FFC;;1FFC +1FF4;GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03CE 0345;;;;N;;;;; +1FF6;GREEK SMALL LETTER OMEGA WITH PERISPOMENI;Ll;0;L;03C9 0342;;;;N;;;;; +1FF7;GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FF6 0345;;;;N;;;;; +1FF8;GREEK CAPITAL LETTER OMICRON WITH VARIA;Lu;0;L;039F 0300;;;;N;;;;1F78; +1FF9;GREEK CAPITAL LETTER OMICRON WITH OXIA;Lu;0;L;038C;;;;N;;;;1F79; +1FFA;GREEK CAPITAL LETTER OMEGA WITH VARIA;Lu;0;L;03A9 0300;;;;N;;;;1F7C; +1FFB;GREEK CAPITAL LETTER OMEGA WITH OXIA;Lu;0;L;038F;;;;N;;;;1F7D; +1FFC;GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI;Lt;0;L;03A9 0345;;;;N;;;;1FF3; +1FFD;GREEK OXIA;Sk;0;ON;00B4;;;;N;;;;; +1FFE;GREEK DASIA;Sk;0;ON;<compat> 0020 0314;;;;N;;;;; +2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;; +2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;; +2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; +2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; +2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; +2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; +2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; +2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;; +2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; +2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; +200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; +200B;ZERO WIDTH SPACE;Zs;0;BN;;;;;N;;;;; +200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;; +200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;; +200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;; +200F;RIGHT-TO-LEFT MARK;Cf;0;R;;;;;N;;;;; +2010;HYPHEN;Pd;0;ON;;;;;N;;;;; +2011;NON-BREAKING HYPHEN;Pd;0;ON;<noBreak> 2010;;;;N;;;;; +2012;FIGURE DASH;Pd;0;ON;;;;;N;;;;; +2013;EN DASH;Pd;0;ON;;;;;N;;;;; +2014;EM DASH;Pd;0;ON;;;;;N;;;;; +2015;HORIZONTAL BAR;Pd;0;ON;;;;;N;QUOTATION DASH;;;; +2016;DOUBLE VERTICAL LINE;Po;0;ON;;;;;N;DOUBLE VERTICAL BAR;;;; +2017;DOUBLE LOW LINE;Po;0;ON;<compat> 0020 0333;;;;N;SPACING DOUBLE UNDERSCORE;;;; +2018;LEFT SINGLE QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE TURNED COMMA QUOTATION MARK;;;; +2019;RIGHT SINGLE QUOTATION MARK;Pf;0;ON;;;;;N;SINGLE COMMA QUOTATION MARK;;;; +201A;SINGLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW SINGLE COMMA QUOTATION MARK;;;; +201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE REVERSED COMMA QUOTATION MARK;;;; +201C;LEFT DOUBLE QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE TURNED COMMA QUOTATION MARK;;;; +201D;RIGHT DOUBLE QUOTATION MARK;Pf;0;ON;;;;;N;DOUBLE COMMA QUOTATION MARK;;;; +201E;DOUBLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW DOUBLE COMMA QUOTATION MARK;;;; +201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE REVERSED COMMA QUOTATION MARK;;;; +2020;DAGGER;Po;0;ON;;;;;N;;;;; +2021;DOUBLE DAGGER;Po;0;ON;;;;;N;;;;; +2022;BULLET;Po;0;ON;;;;;N;;;;; +2023;TRIANGULAR BULLET;Po;0;ON;;;;;N;;;;; +2024;ONE DOT LEADER;Po;0;ON;<compat> 002E;;;;N;;;;; +2025;TWO DOT LEADER;Po;0;ON;<compat> 002E 002E;;;;N;;;;; +2026;HORIZONTAL ELLIPSIS;Po;0;ON;<compat> 002E 002E 002E;;;;N;;;;; +2027;HYPHENATION POINT;Po;0;ON;;;;;N;;;;; +2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; +2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; +202A;LEFT-TO-RIGHT EMBEDDING;Cf;0;LRE;;;;;N;;;;; +202B;RIGHT-TO-LEFT EMBEDDING;Cf;0;RLE;;;;;N;;;;; +202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;; +202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;; +202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;; +202F;NARROW NO-BREAK SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;; +2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;; +2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;; +2032;PRIME;Po;0;ET;;;;;N;;;;; +2033;DOUBLE PRIME;Po;0;ET;<compat> 2032 2032;;;;N;;;;; +2034;TRIPLE PRIME;Po;0;ET;<compat> 2032 2032 2032;;;;N;;;;; +2035;REVERSED PRIME;Po;0;ON;;;;;N;;;;; +2036;REVERSED DOUBLE PRIME;Po;0;ON;<compat> 2035 2035;;;;N;;;;; +2037;REVERSED TRIPLE PRIME;Po;0;ON;<compat> 2035 2035 2035;;;;N;;;;; +2038;CARET;Po;0;ON;;;;;N;;;;; +2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING SINGLE GUILLEMET;;;; +203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING SINGLE GUILLEMET;;;; +203B;REFERENCE MARK;Po;0;ON;;;;;N;;;;; +203C;DOUBLE EXCLAMATION MARK;Po;0;ON;<compat> 0021 0021;;;;N;;;;; +203D;INTERROBANG;Po;0;ON;;;;;N;;;;; +203E;OVERLINE;Po;0;ON;<compat> 0020 0305;;;;N;SPACING OVERSCORE;;;; +203F;UNDERTIE;Pc;0;ON;;;;;N;;Enotikon;;; +2040;CHARACTER TIE;Pc;0;ON;;;;;N;;;;; +2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;; +2042;ASTERISM;Po;0;ON;;;;;N;;;;; +2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;; +2044;FRACTION SLASH;Sm;0;ON;;;;;N;;;;; +2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;; +2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;; +2047;DOUBLE QUESTION MARK;Po;0;ON;<compat> 003F 003F;;;;N;;;;; +2048;QUESTION EXCLAMATION MARK;Po;0;ON;<compat> 003F 0021;;;;N;;;;; +2049;EXCLAMATION QUESTION MARK;Po;0;ON;<compat> 0021 003F;;;;N;;;;; +204A;TIRONIAN SIGN ET;Po;0;ON;;;;;N;;;;; +204B;REVERSED PILCROW SIGN;Po;0;ON;;;;;N;;;;; +204C;BLACK LEFTWARDS BULLET;Po;0;ON;;;;;N;;;;; +204D;BLACK RIGHTWARDS BULLET;Po;0;ON;;;;;N;;;;; +204E;LOW ASTERISK;Po;0;ON;;;;;N;;;;; +204F;REVERSED SEMICOLON;Po;0;ON;;;;;N;;;;; +2050;CLOSE UP;Po;0;ON;;;;;N;;;;; +2051;TWO ASTERISKS ALIGNED VERTICALLY;Po;0;ON;;;;;N;;;;; +2052;COMMERCIAL MINUS SIGN;Sm;0;ON;;;;;N;;;;; +2053;SWUNG DASH;Po;0;ON;;;;;N;;;;; +2054;INVERTED UNDERTIE;Pc;0;ON;;;;;N;;;;; +2057;QUADRUPLE PRIME;Po;0;ON;<compat> 2032 2032 2032 2032;;;;N;;;;; +205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; +2060;WORD JOINER;Cf;0;BN;;;;;N;;;;; +2061;FUNCTION APPLICATION;Cf;0;BN;;;;;N;;;;; +2062;INVISIBLE TIMES;Cf;0;BN;;;;;N;;;;; +2063;INVISIBLE SEPARATOR;Cf;0;BN;;;;;N;;;;; +206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; +206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; +206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; +206D;ACTIVATE ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; +206E;NATIONAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;; +206F;NOMINAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;; +2070;SUPERSCRIPT ZERO;No;0;EN;<super> 0030;;0;0;N;SUPERSCRIPT DIGIT ZERO;;;; +2071;SUPERSCRIPT LATIN SMALL LETTER I;Ll;0;L;<super> 0069;;;;N;;;;; +2074;SUPERSCRIPT FOUR;No;0;EN;<super> 0034;;4;4;N;SUPERSCRIPT DIGIT FOUR;;;; +2075;SUPERSCRIPT FIVE;No;0;EN;<super> 0035;;5;5;N;SUPERSCRIPT DIGIT FIVE;;;; +2076;SUPERSCRIPT SIX;No;0;EN;<super> 0036;;6;6;N;SUPERSCRIPT DIGIT SIX;;;; +2077;SUPERSCRIPT SEVEN;No;0;EN;<super> 0037;;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;; +2078;SUPERSCRIPT EIGHT;No;0;EN;<super> 0038;;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;; +2079;SUPERSCRIPT NINE;No;0;EN;<super> 0039;;9;9;N;SUPERSCRIPT DIGIT NINE;;;; +207A;SUPERSCRIPT PLUS SIGN;Sm;0;ET;<super> 002B;;;;N;;;;; +207B;SUPERSCRIPT MINUS;Sm;0;ET;<super> 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;; +207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON;<super> 003D;;;;N;;;;; +207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON;<super> 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;; +207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<super> 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;; +207F;SUPERSCRIPT LATIN SMALL LETTER N;Ll;0;L;<super> 006E;;;;N;;;;; +2080;SUBSCRIPT ZERO;No;0;EN;<sub> 0030;;0;0;N;SUBSCRIPT DIGIT ZERO;;;; +2081;SUBSCRIPT ONE;No;0;EN;<sub> 0031;;1;1;N;SUBSCRIPT DIGIT ONE;;;; +2082;SUBSCRIPT TWO;No;0;EN;<sub> 0032;;2;2;N;SUBSCRIPT DIGIT TWO;;;; +2083;SUBSCRIPT THREE;No;0;EN;<sub> 0033;;3;3;N;SUBSCRIPT DIGIT THREE;;;; +2084;SUBSCRIPT FOUR;No;0;EN;<sub> 0034;;4;4;N;SUBSCRIPT DIGIT FOUR;;;; +2085;SUBSCRIPT FIVE;No;0;EN;<sub> 0035;;5;5;N;SUBSCRIPT DIGIT FIVE;;;; +2086;SUBSCRIPT SIX;No;0;EN;<sub> 0036;;6;6;N;SUBSCRIPT DIGIT SIX;;;; +2087;SUBSCRIPT SEVEN;No;0;EN;<sub> 0037;;7;7;N;SUBSCRIPT DIGIT SEVEN;;;; +2088;SUBSCRIPT EIGHT;No;0;EN;<sub> 0038;;8;8;N;SUBSCRIPT DIGIT EIGHT;;;; +2089;SUBSCRIPT NINE;No;0;EN;<sub> 0039;;9;9;N;SUBSCRIPT DIGIT NINE;;;; +208A;SUBSCRIPT PLUS SIGN;Sm;0;ET;<sub> 002B;;;;N;;;;; +208B;SUBSCRIPT MINUS;Sm;0;ET;<sub> 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;; +208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON;<sub> 003D;;;;N;;;;; +208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON;<sub> 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;; +208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<sub> 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;; +20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; +20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;; +20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;; +20A3;FRENCH FRANC SIGN;Sc;0;ET;;;;;N;;;;; +20A4;LIRA SIGN;Sc;0;ET;;;;;N;;;;; +20A5;MILL SIGN;Sc;0;ET;;;;;N;;;;; +20A6;NAIRA SIGN;Sc;0;ET;;;;;N;;;;; +20A7;PESETA SIGN;Sc;0;ET;;;;;N;;;;; +20A8;RUPEE SIGN;Sc;0;ET;<compat> 0052 0073;;;;N;;;;; +20A9;WON SIGN;Sc;0;ET;;;;;N;;;;; +20AA;NEW SHEQEL SIGN;Sc;0;ET;;;;;N;;;;; +20AB;DONG SIGN;Sc;0;ET;;;;;N;;;;; +20AC;EURO SIGN;Sc;0;ET;;;;;N;;;;; +20AD;KIP SIGN;Sc;0;ET;;;;;N;;;;; +20AE;TUGRIK SIGN;Sc;0;ET;;;;;N;;;;; +20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;; +20B0;GERMAN PENNY SIGN;Sc;0;ET;;;;;N;;;;; +20B1;PESO SIGN;Sc;0;ET;;;;;N;;;;; +20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; +20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; +20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; +20D3;COMBINING SHORT VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT VERTICAL BAR OVERLAY;;;; +20D4;COMBINING ANTICLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING ANTICLOCKWISE ARROW ABOVE;;;; +20D5;COMBINING CLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING CLOCKWISE ARROW ABOVE;;;; +20D6;COMBINING LEFT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT ARROW ABOVE;;;; +20D7;COMBINING RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT ARROW ABOVE;;;; +20D8;COMBINING RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING RING OVERLAY;;;; +20D9;COMBINING CLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING CLOCKWISE RING OVERLAY;;;; +20DA;COMBINING ANTICLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING ANTICLOCKWISE RING OVERLAY;;;; +20DB;COMBINING THREE DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING THREE DOTS ABOVE;;;; +20DC;COMBINING FOUR DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING FOUR DOTS ABOVE;;;; +20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;; +20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;; +20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;; +20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;; +20E1;COMBINING LEFT RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT RIGHT ARROW ABOVE;;;; +20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;; +20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;; +20E4;COMBINING ENCLOSING UPWARD POINTING TRIANGLE;Me;0;NSM;;;;;N;;;;; +20E5;COMBINING REVERSE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;; +20E6;COMBINING DOUBLE VERTICAL STROKE OVERLAY;Mn;1;NSM;;;;;N;;;;; +20E7;COMBINING ANNUITY SYMBOL;Mn;230;NSM;;;;;N;;;;; +20E8;COMBINING TRIPLE UNDERDOT;Mn;220;NSM;;;;;N;;;;; +20E9;COMBINING WIDE BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; +20EA;COMBINING LEFTWARDS ARROW OVERLAY;Mn;1;NSM;;;;;N;;;;; +2100;ACCOUNT OF;So;0;ON;<compat> 0061 002F 0063;;;;N;;;;; +2101;ADDRESSED TO THE SUBJECT;So;0;ON;<compat> 0061 002F 0073;;;;N;;;;; +2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L;<font> 0043;;;;N;DOUBLE-STRUCK C;;;; +2103;DEGREE CELSIUS;So;0;ON;<compat> 00B0 0043;;;;N;DEGREES CENTIGRADE;;;; +2104;CENTRE LINE SYMBOL;So;0;ON;;;;;N;C L SYMBOL;;;; +2105;CARE OF;So;0;ON;<compat> 0063 002F 006F;;;;N;;;;; +2106;CADA UNA;So;0;ON;<compat> 0063 002F 0075;;;;N;;;;; +2107;EULER CONSTANT;Lu;0;L;<compat> 0190;;;;N;EULERS;;;; +2108;SCRUPLE;So;0;ON;;;;;N;;;;; +2109;DEGREE FAHRENHEIT;So;0;ON;<compat> 00B0 0046;;;;N;DEGREES FAHRENHEIT;;;; +210A;SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +210B;SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;SCRIPT H;;;; +210C;BLACK-LETTER CAPITAL H;Lu;0;L;<font> 0048;;;;N;BLACK-LETTER H;;;; +210D;DOUBLE-STRUCK CAPITAL H;Lu;0;L;<font> 0048;;;;N;DOUBLE-STRUCK H;;;; +210E;PLANCK CONSTANT;Ll;0;L;<font> 0068;;;;N;;;;; +210F;PLANCK CONSTANT OVER TWO PI;Ll;0;L;<font> 0127;;;;N;PLANCK CONSTANT OVER 2 PI;;;; +2110;SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;SCRIPT I;;;; +2111;BLACK-LETTER CAPITAL I;Lu;0;L;<font> 0049;;;;N;BLACK-LETTER I;;;; +2112;SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;SCRIPT L;;;; +2113;SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +2114;L B BAR SYMBOL;So;0;ON;;;;;N;;;;; +2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L;<font> 004E;;;;N;DOUBLE-STRUCK N;;;; +2116;NUMERO SIGN;So;0;ON;<compat> 004E 006F;;;;N;NUMERO;;;; +2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;; +2118;SCRIPT CAPITAL P;So;0;ON;;;;;N;SCRIPT P;;;; +2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L;<font> 0050;;;;N;DOUBLE-STRUCK P;;;; +211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L;<font> 0051;;;;N;DOUBLE-STRUCK Q;;;; +211B;SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;SCRIPT R;;;; +211C;BLACK-LETTER CAPITAL R;Lu;0;L;<font> 0052;;;;N;BLACK-LETTER R;;;; +211D;DOUBLE-STRUCK CAPITAL R;Lu;0;L;<font> 0052;;;;N;DOUBLE-STRUCK R;;;; +211E;PRESCRIPTION TAKE;So;0;ON;;;;;N;;;;; +211F;RESPONSE;So;0;ON;;;;;N;;;;; +2120;SERVICE MARK;So;0;ON;<super> 0053 004D;;;;N;;;;; +2121;TELEPHONE SIGN;So;0;ON;<compat> 0054 0045 004C;;;;N;T E L SYMBOL;;;; +2122;TRADE MARK SIGN;So;0;ON;<super> 0054 004D;;;;N;TRADEMARK;;;; +2123;VERSICLE;So;0;ON;;;;;N;;;;; +2124;DOUBLE-STRUCK CAPITAL Z;Lu;0;L;<font> 005A;;;;N;DOUBLE-STRUCK Z;;;; +2125;OUNCE SIGN;So;0;ON;;;;;N;OUNCE;;;; +2126;OHM SIGN;Lu;0;L;03A9;;;;N;OHM;;;03C9; +2127;INVERTED OHM SIGN;So;0;ON;;;;;N;MHO;;;; +2128;BLACK-LETTER CAPITAL Z;Lu;0;L;<font> 005A;;;;N;BLACK-LETTER Z;;;; +2129;TURNED GREEK SMALL LETTER IOTA;So;0;ON;;;;;N;;;;; +212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B; +212B;ANGSTROM SIGN;Lu;0;L;00C5;;;;N;ANGSTROM UNIT;;;00E5; +212C;SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;SCRIPT B;;;; +212D;BLACK-LETTER CAPITAL C;Lu;0;L;<font> 0043;;;;N;BLACK-LETTER C;;;; +212E;ESTIMATED SYMBOL;So;0;ET;;;;;N;;;;; +212F;SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +2130;SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;SCRIPT E;;;; +2131;SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;SCRIPT F;;;; +2132;TURNED CAPITAL F;So;0;ON;;;;;N;TURNED F;;;; +2133;SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;SCRIPT M;;;; +2134;SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +2135;ALEF SYMBOL;Lo;0;L;<compat> 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;; +2136;BET SYMBOL;Lo;0;L;<compat> 05D1;;;;N;SECOND TRANSFINITE CARDINAL;;;; +2137;GIMEL SYMBOL;Lo;0;L;<compat> 05D2;;;;N;THIRD TRANSFINITE CARDINAL;;;; +2138;DALET SYMBOL;Lo;0;L;<compat> 05D3;;;;N;FOURTH TRANSFINITE CARDINAL;;;; +2139;INFORMATION SOURCE;Ll;0;L;<font> 0069;;;;N;;;;; +213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;; +213B;FACSIMILE SIGN;So;0;ON;<compat> 0046 0041 0058;;;;N;;;;; +213D;DOUBLE-STRUCK SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; +213E;DOUBLE-STRUCK CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; +213F;DOUBLE-STRUCK CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; +2140;DOUBLE-STRUCK N-ARY SUMMATION;Sm;0;ON;<font> 2211;;;;Y;;;;; +2141;TURNED SANS-SERIF CAPITAL G;Sm;0;ON;;;;;N;;;;; +2142;TURNED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;; +2143;REVERSED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;; +2144;TURNED SANS-SERIF CAPITAL Y;Sm;0;ON;;;;;N;;;;; +2145;DOUBLE-STRUCK ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +2146;DOUBLE-STRUCK ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +2147;DOUBLE-STRUCK ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +2148;DOUBLE-STRUCK ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +2149;DOUBLE-STRUCK ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +214A;PROPERTY LINE;So;0;ON;;;;;N;;;;; +214B;TURNED AMPERSAND;Sm;0;ON;;;;;N;;;;; +2153;VULGAR FRACTION ONE THIRD;No;0;ON;<fraction> 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;; +2154;VULGAR FRACTION TWO THIRDS;No;0;ON;<fraction> 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;; +2155;VULGAR FRACTION ONE FIFTH;No;0;ON;<fraction> 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;; +2156;VULGAR FRACTION TWO FIFTHS;No;0;ON;<fraction> 0032 2044 0035;;;2/5;N;FRACTION TWO FIFTHS;;;; +2157;VULGAR FRACTION THREE FIFTHS;No;0;ON;<fraction> 0033 2044 0035;;;3/5;N;FRACTION THREE FIFTHS;;;; +2158;VULGAR FRACTION FOUR FIFTHS;No;0;ON;<fraction> 0034 2044 0035;;;4/5;N;FRACTION FOUR FIFTHS;;;; +2159;VULGAR FRACTION ONE SIXTH;No;0;ON;<fraction> 0031 2044 0036;;;1/6;N;FRACTION ONE SIXTH;;;; +215A;VULGAR FRACTION FIVE SIXTHS;No;0;ON;<fraction> 0035 2044 0036;;;5/6;N;FRACTION FIVE SIXTHS;;;; +215B;VULGAR FRACTION ONE EIGHTH;No;0;ON;<fraction> 0031 2044 0038;;;1/8;N;FRACTION ONE EIGHTH;;;; +215C;VULGAR FRACTION THREE EIGHTHS;No;0;ON;<fraction> 0033 2044 0038;;;3/8;N;FRACTION THREE EIGHTHS;;;; +215D;VULGAR FRACTION FIVE EIGHTHS;No;0;ON;<fraction> 0035 2044 0038;;;5/8;N;FRACTION FIVE EIGHTHS;;;; +215E;VULGAR FRACTION SEVEN EIGHTHS;No;0;ON;<fraction> 0037 2044 0038;;;7/8;N;FRACTION SEVEN EIGHTHS;;;; +215F;FRACTION NUMERATOR ONE;No;0;ON;<fraction> 0031 2044;;;1;N;;;;; +2160;ROMAN NUMERAL ONE;Nl;0;L;<compat> 0049;;;1;N;;;;2170; +2161;ROMAN NUMERAL TWO;Nl;0;L;<compat> 0049 0049;;;2;N;;;;2171; +2162;ROMAN NUMERAL THREE;Nl;0;L;<compat> 0049 0049 0049;;;3;N;;;;2172; +2163;ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0049 0056;;;4;N;;;;2173; +2164;ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0056;;;5;N;;;;2174; +2165;ROMAN NUMERAL SIX;Nl;0;L;<compat> 0056 0049;;;6;N;;;;2175; +2166;ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0056 0049 0049;;;7;N;;;;2176; +2167;ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0056 0049 0049 0049;;;8;N;;;;2177; +2168;ROMAN NUMERAL NINE;Nl;0;L;<compat> 0049 0058;;;9;N;;;;2178; +2169;ROMAN NUMERAL TEN;Nl;0;L;<compat> 0058;;;10;N;;;;2179; +216A;ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0058 0049;;;11;N;;;;217A; +216B;ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0058 0049 0049;;;12;N;;;;217B; +216C;ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 004C;;;50;N;;;;217C; +216D;ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0043;;;100;N;;;;217D; +216E;ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0044;;;500;N;;;;217E; +216F;ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 004D;;;1000;N;;;;217F; +2170;SMALL ROMAN NUMERAL ONE;Nl;0;L;<compat> 0069;;;1;N;;;2160;;2160 +2171;SMALL ROMAN NUMERAL TWO;Nl;0;L;<compat> 0069 0069;;;2;N;;;2161;;2161 +2172;SMALL ROMAN NUMERAL THREE;Nl;0;L;<compat> 0069 0069 0069;;;3;N;;;2162;;2162 +2173;SMALL ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0069 0076;;;4;N;;;2163;;2163 +2174;SMALL ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0076;;;5;N;;;2164;;2164 +2175;SMALL ROMAN NUMERAL SIX;Nl;0;L;<compat> 0076 0069;;;6;N;;;2165;;2165 +2176;SMALL ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0076 0069 0069;;;7;N;;;2166;;2166 +2177;SMALL ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0076 0069 0069 0069;;;8;N;;;2167;;2167 +2178;SMALL ROMAN NUMERAL NINE;Nl;0;L;<compat> 0069 0078;;;9;N;;;2168;;2168 +2179;SMALL ROMAN NUMERAL TEN;Nl;0;L;<compat> 0078;;;10;N;;;2169;;2169 +217A;SMALL ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0078 0069;;;11;N;;;216A;;216A +217B;SMALL ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0078 0069 0069;;;12;N;;;216B;;216B +217C;SMALL ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 006C;;;50;N;;;216C;;216C +217D;SMALL ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0063;;;100;N;;;216D;;216D +217E;SMALL ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0064;;;500;N;;;216E;;216E +217F;SMALL ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 006D;;;1000;N;;;216F;;216F +2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;; +2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;; +2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;; +2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Nl;0;L;;;;;N;;;;; +2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;; +2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;; +2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;; +2193;DOWNWARDS ARROW;Sm;0;ON;;;;;N;DOWN ARROW;;;; +2194;LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;; +2195;UP DOWN ARROW;So;0;ON;;;;;N;;;;; +2196;NORTH WEST ARROW;So;0;ON;;;;;N;UPPER LEFT ARROW;;;; +2197;NORTH EAST ARROW;So;0;ON;;;;;N;UPPER RIGHT ARROW;;;; +2198;SOUTH EAST ARROW;So;0;ON;;;;;N;LOWER RIGHT ARROW;;;; +2199;SOUTH WEST ARROW;So;0;ON;;;;;N;LOWER LEFT ARROW;;;; +219A;LEFTWARDS ARROW WITH STROKE;Sm;0;ON;2190 0338;;;;N;LEFT ARROW WITH STROKE;;;; +219B;RIGHTWARDS ARROW WITH STROKE;Sm;0;ON;2192 0338;;;;N;RIGHT ARROW WITH STROKE;;;; +219C;LEFTWARDS WAVE ARROW;So;0;ON;;;;;N;LEFT WAVE ARROW;;;; +219D;RIGHTWARDS WAVE ARROW;So;0;ON;;;;;N;RIGHT WAVE ARROW;;;; +219E;LEFTWARDS TWO HEADED ARROW;So;0;ON;;;;;N;LEFT TWO HEADED ARROW;;;; +219F;UPWARDS TWO HEADED ARROW;So;0;ON;;;;;N;UP TWO HEADED ARROW;;;; +21A0;RIGHTWARDS TWO HEADED ARROW;Sm;0;ON;;;;;N;RIGHT TWO HEADED ARROW;;;; +21A1;DOWNWARDS TWO HEADED ARROW;So;0;ON;;;;;N;DOWN TWO HEADED ARROW;;;; +21A2;LEFTWARDS ARROW WITH TAIL;So;0;ON;;;;;N;LEFT ARROW WITH TAIL;;;; +21A3;RIGHTWARDS ARROW WITH TAIL;Sm;0;ON;;;;;N;RIGHT ARROW WITH TAIL;;;; +21A4;LEFTWARDS ARROW FROM BAR;So;0;ON;;;;;N;LEFT ARROW FROM BAR;;;; +21A5;UPWARDS ARROW FROM BAR;So;0;ON;;;;;N;UP ARROW FROM BAR;;;; +21A6;RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;RIGHT ARROW FROM BAR;;;; +21A7;DOWNWARDS ARROW FROM BAR;So;0;ON;;;;;N;DOWN ARROW FROM BAR;;;; +21A8;UP DOWN ARROW WITH BASE;So;0;ON;;;;;N;;;;; +21A9;LEFTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;LEFT ARROW WITH HOOK;;;; +21AA;RIGHTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;RIGHT ARROW WITH HOOK;;;; +21AB;LEFTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;LEFT ARROW WITH LOOP;;;; +21AC;RIGHTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;RIGHT ARROW WITH LOOP;;;; +21AD;LEFT RIGHT WAVE ARROW;So;0;ON;;;;;N;;;;; +21AE;LEFT RIGHT ARROW WITH STROKE;Sm;0;ON;2194 0338;;;;N;;;;; +21AF;DOWNWARDS ZIGZAG ARROW;So;0;ON;;;;;N;DOWN ZIGZAG ARROW;;;; +21B0;UPWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP LEFT;;;; +21B1;UPWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP RIGHT;;;; +21B2;DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP LEFT;;;; +21B3;DOWNWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP RIGHT;;;; +21B4;RIGHTWARDS ARROW WITH CORNER DOWNWARDS;So;0;ON;;;;;N;RIGHT ARROW WITH CORNER DOWN;;;; +21B5;DOWNWARDS ARROW WITH CORNER LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH CORNER LEFT;;;; +21B6;ANTICLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;; +21B7;CLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;; +21B8;NORTH WEST ARROW TO LONG BAR;So;0;ON;;;;;N;UPPER LEFT ARROW TO LONG BAR;;;; +21B9;LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR OVER RIGHT ARROW TO BAR;;;; +21BA;ANTICLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; +21BB;CLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; +21BC;LEFTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB UP;;;; +21BD;LEFTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB DOWN;;;; +21BE;UPWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB RIGHT;;;; +21BF;UPWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB LEFT;;;; +21C0;RIGHTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB UP;;;; +21C1;RIGHTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB DOWN;;;; +21C2;DOWNWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB RIGHT;;;; +21C3;DOWNWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB LEFT;;;; +21C4;RIGHTWARDS ARROW OVER LEFTWARDS ARROW;So;0;ON;;;;;N;RIGHT ARROW OVER LEFT ARROW;;;; +21C5;UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW;So;0;ON;;;;;N;UP ARROW LEFT OF DOWN ARROW;;;; +21C6;LEFTWARDS ARROW OVER RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT ARROW OVER RIGHT ARROW;;;; +21C7;LEFTWARDS PAIRED ARROWS;So;0;ON;;;;;N;LEFT PAIRED ARROWS;;;; +21C8;UPWARDS PAIRED ARROWS;So;0;ON;;;;;N;UP PAIRED ARROWS;;;; +21C9;RIGHTWARDS PAIRED ARROWS;So;0;ON;;;;;N;RIGHT PAIRED ARROWS;;;; +21CA;DOWNWARDS PAIRED ARROWS;So;0;ON;;;;;N;DOWN PAIRED ARROWS;;;; +21CB;LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON;So;0;ON;;;;;N;LEFT HARPOON OVER RIGHT HARPOON;;;; +21CC;RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON;So;0;ON;;;;;N;RIGHT HARPOON OVER LEFT HARPOON;;;; +21CD;LEFTWARDS DOUBLE ARROW WITH STROKE;So;0;ON;21D0 0338;;;;N;LEFT DOUBLE ARROW WITH STROKE;;;; +21CE;LEFT RIGHT DOUBLE ARROW WITH STROKE;Sm;0;ON;21D4 0338;;;;N;;;;; +21CF;RIGHTWARDS DOUBLE ARROW WITH STROKE;Sm;0;ON;21D2 0338;;;;N;RIGHT DOUBLE ARROW WITH STROKE;;;; +21D0;LEFTWARDS DOUBLE ARROW;So;0;ON;;;;;N;LEFT DOUBLE ARROW;;;; +21D1;UPWARDS DOUBLE ARROW;So;0;ON;;;;;N;UP DOUBLE ARROW;;;; +21D2;RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;RIGHT DOUBLE ARROW;;;; +21D3;DOWNWARDS DOUBLE ARROW;So;0;ON;;;;;N;DOWN DOUBLE ARROW;;;; +21D4;LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; +21D5;UP DOWN DOUBLE ARROW;So;0;ON;;;;;N;;;;; +21D6;NORTH WEST DOUBLE ARROW;So;0;ON;;;;;N;UPPER LEFT DOUBLE ARROW;;;; +21D7;NORTH EAST DOUBLE ARROW;So;0;ON;;;;;N;UPPER RIGHT DOUBLE ARROW;;;; +21D8;SOUTH EAST DOUBLE ARROW;So;0;ON;;;;;N;LOWER RIGHT DOUBLE ARROW;;;; +21D9;SOUTH WEST DOUBLE ARROW;So;0;ON;;;;;N;LOWER LEFT DOUBLE ARROW;;;; +21DA;LEFTWARDS TRIPLE ARROW;So;0;ON;;;;;N;LEFT TRIPLE ARROW;;;; +21DB;RIGHTWARDS TRIPLE ARROW;So;0;ON;;;;;N;RIGHT TRIPLE ARROW;;;; +21DC;LEFTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;LEFT SQUIGGLE ARROW;;;; +21DD;RIGHTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;RIGHT SQUIGGLE ARROW;;;; +21DE;UPWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;UP ARROW WITH DOUBLE STROKE;;;; +21DF;DOWNWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;DOWN ARROW WITH DOUBLE STROKE;;;; +21E0;LEFTWARDS DASHED ARROW;So;0;ON;;;;;N;LEFT DASHED ARROW;;;; +21E1;UPWARDS DASHED ARROW;So;0;ON;;;;;N;UP DASHED ARROW;;;; +21E2;RIGHTWARDS DASHED ARROW;So;0;ON;;;;;N;RIGHT DASHED ARROW;;;; +21E3;DOWNWARDS DASHED ARROW;So;0;ON;;;;;N;DOWN DASHED ARROW;;;; +21E4;LEFTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR;;;; +21E5;RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;RIGHT ARROW TO BAR;;;; +21E6;LEFTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE LEFT ARROW;;;; +21E7;UPWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE UP ARROW;;;; +21E8;RIGHTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE RIGHT ARROW;;;; +21E9;DOWNWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE DOWN ARROW;;;; +21EA;UPWARDS WHITE ARROW FROM BAR;So;0;ON;;;;;N;WHITE UP ARROW FROM BAR;;;; +21EB;UPWARDS WHITE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;; +21EC;UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;; +21ED;UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; +21EE;UPWARDS WHITE DOUBLE ARROW;So;0;ON;;;;;N;;;;; +21EF;UPWARDS WHITE DOUBLE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;; +21F0;RIGHTWARDS WHITE ARROW FROM WALL;So;0;ON;;;;;N;;;;; +21F1;NORTH WEST ARROW TO CORNER;So;0;ON;;;;;N;;;;; +21F2;SOUTH EAST ARROW TO CORNER;So;0;ON;;;;;N;;;;; +21F3;UP DOWN WHITE ARROW;So;0;ON;;;;;N;;;;; +21F4;RIGHT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; +21F5;DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW;Sm;0;ON;;;;;N;;;;; +21F6;THREE RIGHTWARDS ARROWS;Sm;0;ON;;;;;N;;;;; +21F7;LEFTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21F8;RIGHTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21F9;LEFT RIGHT ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21FA;LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21FB;RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21FC;LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +21FD;LEFTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; +21FE;RIGHTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; +21FF;LEFT RIGHT OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;; +2200;FOR ALL;Sm;0;ON;;;;;N;;;;; +2201;COMPLEMENT;Sm;0;ON;;;;;Y;;;;; +2202;PARTIAL DIFFERENTIAL;Sm;0;ON;;;;;Y;;;;; +2203;THERE EXISTS;Sm;0;ON;;;;;Y;;;;; +2204;THERE DOES NOT EXIST;Sm;0;ON;2203 0338;;;;Y;;;;; +2205;EMPTY SET;Sm;0;ON;;;;;N;;;;; +2206;INCREMENT;Sm;0;ON;;;;;N;;;;; +2207;NABLA;Sm;0;ON;;;;;N;;;;; +2208;ELEMENT OF;Sm;0;ON;;;;;Y;;;;; +2209;NOT AN ELEMENT OF;Sm;0;ON;2208 0338;;;;Y;;;;; +220A;SMALL ELEMENT OF;Sm;0;ON;;;;;Y;;;;; +220B;CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;; +220C;DOES NOT CONTAIN AS MEMBER;Sm;0;ON;220B 0338;;;;Y;;;;; +220D;SMALL CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;; +220E;END OF PROOF;Sm;0;ON;;;;;N;;;;; +220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;; +2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;; +2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;; +2212;MINUS SIGN;Sm;0;ET;;;;;N;;;;; +2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;; +2214;DOT PLUS;Sm;0;ON;;;;;N;;;;; +2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; +2216;SET MINUS;Sm;0;ON;;;;;Y;;;;; +2217;ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;; +2218;RING OPERATOR;Sm;0;ON;;;;;N;;;;; +2219;BULLET OPERATOR;Sm;0;ON;;;;;N;;;;; +221A;SQUARE ROOT;Sm;0;ON;;;;;Y;;;;; +221B;CUBE ROOT;Sm;0;ON;;;;;Y;;;;; +221C;FOURTH ROOT;Sm;0;ON;;;;;Y;;;;; +221D;PROPORTIONAL TO;Sm;0;ON;;;;;Y;;;;; +221E;INFINITY;Sm;0;ON;;;;;N;;;;; +221F;RIGHT ANGLE;Sm;0;ON;;;;;Y;;;;; +2220;ANGLE;Sm;0;ON;;;;;Y;;;;; +2221;MEASURED ANGLE;Sm;0;ON;;;;;Y;;;;; +2222;SPHERICAL ANGLE;Sm;0;ON;;;;;Y;;;;; +2223;DIVIDES;Sm;0;ON;;;;;N;;;;; +2224;DOES NOT DIVIDE;Sm;0;ON;2223 0338;;;;Y;;;;; +2225;PARALLEL TO;Sm;0;ON;;;;;N;;;;; +2226;NOT PARALLEL TO;Sm;0;ON;2225 0338;;;;Y;;;;; +2227;LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2228;LOGICAL OR;Sm;0;ON;;;;;N;;;;; +2229;INTERSECTION;Sm;0;ON;;;;;N;;;;; +222A;UNION;Sm;0;ON;;;;;N;;;;; +222B;INTEGRAL;Sm;0;ON;;;;;Y;;;;; +222C;DOUBLE INTEGRAL;Sm;0;ON;<compat> 222B 222B;;;;Y;;;;; +222D;TRIPLE INTEGRAL;Sm;0;ON;<compat> 222B 222B 222B;;;;Y;;;;; +222E;CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; +222F;SURFACE INTEGRAL;Sm;0;ON;<compat> 222E 222E;;;;Y;;;;; +2230;VOLUME INTEGRAL;Sm;0;ON;<compat> 222E 222E 222E;;;;Y;;;;; +2231;CLOCKWISE INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2232;CLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2233;ANTICLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2234;THEREFORE;Sm;0;ON;;;;;N;;;;; +2235;BECAUSE;Sm;0;ON;;;;;N;;;;; +2236;RATIO;Sm;0;ON;;;;;N;;;;; +2237;PROPORTION;Sm;0;ON;;;;;N;;;;; +2238;DOT MINUS;Sm;0;ON;;;;;N;;;;; +2239;EXCESS;Sm;0;ON;;;;;Y;;;;; +223A;GEOMETRIC PROPORTION;Sm;0;ON;;;;;N;;;;; +223B;HOMOTHETIC;Sm;0;ON;;;;;Y;;;;; +223C;TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +223D;REVERSED TILDE;Sm;0;ON;;;;;Y;;lazy S;;; +223E;INVERTED LAZY S;Sm;0;ON;;;;;Y;;;;; +223F;SINE WAVE;Sm;0;ON;;;;;Y;;;;; +2240;WREATH PRODUCT;Sm;0;ON;;;;;Y;;;;; +2241;NOT TILDE;Sm;0;ON;223C 0338;;;;Y;;;;; +2242;MINUS TILDE;Sm;0;ON;;;;;Y;;;;; +2243;ASYMPTOTICALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2244;NOT ASYMPTOTICALLY EQUAL TO;Sm;0;ON;2243 0338;;;;Y;;;;; +2245;APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2246;APPROXIMATELY BUT NOT ACTUALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2247;NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO;Sm;0;ON;2245 0338;;;;Y;;;;; +2248;ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2249;NOT ALMOST EQUAL TO;Sm;0;ON;2248 0338;;;;Y;;;;; +224A;ALMOST EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +224B;TRIPLE TILDE;Sm;0;ON;;;;;Y;;;;; +224C;ALL EQUAL TO;Sm;0;ON;;;;;Y;;;;; +224D;EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; +224E;GEOMETRICALLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; +224F;DIFFERENCE BETWEEN;Sm;0;ON;;;;;N;;;;; +2250;APPROACHES THE LIMIT;Sm;0;ON;;;;;N;;;;; +2251;GEOMETRICALLY EQUAL TO;Sm;0;ON;;;;;N;;;;; +2252;APPROXIMATELY EQUAL TO OR THE IMAGE OF;Sm;0;ON;;;;;Y;;;;; +2253;IMAGE OF OR APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2254;COLON EQUALS;Sm;0;ON;;;;;Y;COLON EQUAL;;;; +2255;EQUALS COLON;Sm;0;ON;;;;;Y;EQUAL COLON;;;; +2256;RING IN EQUAL TO;Sm;0;ON;;;;;N;;;;; +2257;RING EQUAL TO;Sm;0;ON;;;;;N;;;;; +2258;CORRESPONDS TO;Sm;0;ON;;;;;N;;;;; +2259;ESTIMATES;Sm;0;ON;;;;;N;;;;; +225A;EQUIANGULAR TO;Sm;0;ON;;;;;N;;;;; +225B;STAR EQUALS;Sm;0;ON;;;;;N;;;;; +225C;DELTA EQUAL TO;Sm;0;ON;;;;;N;;;;; +225D;EQUAL TO BY DEFINITION;Sm;0;ON;;;;;N;;;;; +225E;MEASURED BY;Sm;0;ON;;;;;N;;;;; +225F;QUESTIONED EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2260;NOT EQUAL TO;Sm;0;ON;003D 0338;;;;Y;;;;; +2261;IDENTICAL TO;Sm;0;ON;;;;;N;;;;; +2262;NOT IDENTICAL TO;Sm;0;ON;2261 0338;;;;Y;;;;; +2263;STRICTLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; +2264;LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUAL TO;;;; +2265;GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUAL TO;;;; +2266;LESS-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OVER EQUAL TO;;;; +2267;GREATER-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OVER EQUAL TO;;;; +2268;LESS-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUAL TO;;;; +2269;GREATER-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUAL TO;;;; +226A;MUCH LESS-THAN;Sm;0;ON;;;;;Y;MUCH LESS THAN;;;; +226B;MUCH GREATER-THAN;Sm;0;ON;;;;;Y;MUCH GREATER THAN;;;; +226C;BETWEEN;Sm;0;ON;;;;;N;;;;; +226D;NOT EQUIVALENT TO;Sm;0;ON;224D 0338;;;;N;;;;; +226E;NOT LESS-THAN;Sm;0;ON;003C 0338;;;;Y;NOT LESS THAN;;;; +226F;NOT GREATER-THAN;Sm;0;ON;003E 0338;;;;Y;NOT GREATER THAN;;;; +2270;NEITHER LESS-THAN NOR EQUAL TO;Sm;0;ON;2264 0338;;;;Y;NEITHER LESS THAN NOR EQUAL TO;;;; +2271;NEITHER GREATER-THAN NOR EQUAL TO;Sm;0;ON;2265 0338;;;;Y;NEITHER GREATER THAN NOR EQUAL TO;;;; +2272;LESS-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUIVALENT TO;;;; +2273;GREATER-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUIVALENT TO;;;; +2274;NEITHER LESS-THAN NOR EQUIVALENT TO;Sm;0;ON;2272 0338;;;;Y;NEITHER LESS THAN NOR EQUIVALENT TO;;;; +2275;NEITHER GREATER-THAN NOR EQUIVALENT TO;Sm;0;ON;2273 0338;;;;Y;NEITHER GREATER THAN NOR EQUIVALENT TO;;;; +2276;LESS-THAN OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN OR GREATER THAN;;;; +2277;GREATER-THAN OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN OR LESS THAN;;;; +2278;NEITHER LESS-THAN NOR GREATER-THAN;Sm;0;ON;2276 0338;;;;Y;NEITHER LESS THAN NOR GREATER THAN;;;; +2279;NEITHER GREATER-THAN NOR LESS-THAN;Sm;0;ON;2277 0338;;;;Y;NEITHER GREATER THAN NOR LESS THAN;;;; +227A;PRECEDES;Sm;0;ON;;;;;Y;;;;; +227B;SUCCEEDS;Sm;0;ON;;;;;Y;;;;; +227C;PRECEDES OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +227D;SUCCEEDS OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +227E;PRECEDES OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +227F;SUCCEEDS OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +2280;DOES NOT PRECEDE;Sm;0;ON;227A 0338;;;;Y;;;;; +2281;DOES NOT SUCCEED;Sm;0;ON;227B 0338;;;;Y;;;;; +2282;SUBSET OF;Sm;0;ON;;;;;Y;;;;; +2283;SUPERSET OF;Sm;0;ON;;;;;Y;;;;; +2284;NOT A SUBSET OF;Sm;0;ON;2282 0338;;;;Y;;;;; +2285;NOT A SUPERSET OF;Sm;0;ON;2283 0338;;;;Y;;;;; +2286;SUBSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2287;SUPERSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2288;NEITHER A SUBSET OF NOR EQUAL TO;Sm;0;ON;2286 0338;;;;Y;;;;; +2289;NEITHER A SUPERSET OF NOR EQUAL TO;Sm;0;ON;2287 0338;;;;Y;;;;; +228A;SUBSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUBSET OF OR NOT EQUAL TO;;;; +228B;SUPERSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUPERSET OF OR NOT EQUAL TO;;;; +228C;MULTISET;Sm;0;ON;;;;;Y;;;;; +228D;MULTISET MULTIPLICATION;Sm;0;ON;;;;;N;;;;; +228E;MULTISET UNION;Sm;0;ON;;;;;N;;;;; +228F;SQUARE IMAGE OF;Sm;0;ON;;;;;Y;;;;; +2290;SQUARE ORIGINAL OF;Sm;0;ON;;;;;Y;;;;; +2291;SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2292;SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2293;SQUARE CAP;Sm;0;ON;;;;;N;;;;; +2294;SQUARE CUP;Sm;0;ON;;;;;N;;;;; +2295;CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; +2296;CIRCLED MINUS;Sm;0;ON;;;;;N;;;;; +2297;CIRCLED TIMES;Sm;0;ON;;;;;N;;;;; +2298;CIRCLED DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; +2299;CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +229A;CIRCLED RING OPERATOR;Sm;0;ON;;;;;N;;;;; +229B;CIRCLED ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;; +229C;CIRCLED EQUALS;Sm;0;ON;;;;;N;;;;; +229D;CIRCLED DASH;Sm;0;ON;;;;;N;;;;; +229E;SQUARED PLUS;Sm;0;ON;;;;;N;;;;; +229F;SQUARED MINUS;Sm;0;ON;;;;;N;;;;; +22A0;SQUARED TIMES;Sm;0;ON;;;;;N;;;;; +22A1;SQUARED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +22A2;RIGHT TACK;Sm;0;ON;;;;;Y;;;;; +22A3;LEFT TACK;Sm;0;ON;;;;;Y;;;;; +22A4;DOWN TACK;Sm;0;ON;;;;;N;;;;; +22A5;UP TACK;Sm;0;ON;;;;;N;;;;; +22A6;ASSERTION;Sm;0;ON;;;;;Y;;;;; +22A7;MODELS;Sm;0;ON;;;;;Y;;;;; +22A8;TRUE;Sm;0;ON;;;;;Y;;;;; +22A9;FORCES;Sm;0;ON;;;;;Y;;;;; +22AA;TRIPLE VERTICAL BAR RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +22AB;DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +22AC;DOES NOT PROVE;Sm;0;ON;22A2 0338;;;;Y;;;;; +22AD;NOT TRUE;Sm;0;ON;22A8 0338;;;;Y;;;;; +22AE;DOES NOT FORCE;Sm;0;ON;22A9 0338;;;;Y;;;;; +22AF;NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;22AB 0338;;;;Y;;;;; +22B0;PRECEDES UNDER RELATION;Sm;0;ON;;;;;Y;;;;; +22B1;SUCCEEDS UNDER RELATION;Sm;0;ON;;;;;Y;;;;; +22B2;NORMAL SUBGROUP OF;Sm;0;ON;;;;;Y;;;;; +22B3;CONTAINS AS NORMAL SUBGROUP;Sm;0;ON;;;;;Y;;;;; +22B4;NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22B5;CONTAINS AS NORMAL SUBGROUP OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22B6;ORIGINAL OF;Sm;0;ON;;;;;Y;;;;; +22B7;IMAGE OF;Sm;0;ON;;;;;Y;;;;; +22B8;MULTIMAP;Sm;0;ON;;;;;Y;;;;; +22B9;HERMITIAN CONJUGATE MATRIX;Sm;0;ON;;;;;N;;;;; +22BA;INTERCALATE;Sm;0;ON;;;;;N;;;;; +22BB;XOR;Sm;0;ON;;;;;N;;;;; +22BC;NAND;Sm;0;ON;;;;;N;;;;; +22BD;NOR;Sm;0;ON;;;;;N;;;;; +22BE;RIGHT ANGLE WITH ARC;Sm;0;ON;;;;;Y;;;;; +22BF;RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;; +22C0;N-ARY LOGICAL AND;Sm;0;ON;;;;;N;;;;; +22C1;N-ARY LOGICAL OR;Sm;0;ON;;;;;N;;;;; +22C2;N-ARY INTERSECTION;Sm;0;ON;;;;;N;;;;; +22C3;N-ARY UNION;Sm;0;ON;;;;;N;;;;; +22C4;DIAMOND OPERATOR;Sm;0;ON;;;;;N;;;;; +22C5;DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +22C6;STAR OPERATOR;Sm;0;ON;;;;;N;;;;; +22C7;DIVISION TIMES;Sm;0;ON;;;;;N;;;;; +22C8;BOWTIE;Sm;0;ON;;;;;N;;;;; +22C9;LEFT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CA;RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CB;LEFT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CC;RIGHT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CD;REVERSED TILDE EQUALS;Sm;0;ON;;;;;Y;;;;; +22CE;CURLY LOGICAL OR;Sm;0;ON;;;;;N;;;;; +22CF;CURLY LOGICAL AND;Sm;0;ON;;;;;N;;;;; +22D0;DOUBLE SUBSET;Sm;0;ON;;;;;Y;;;;; +22D1;DOUBLE SUPERSET;Sm;0;ON;;;;;Y;;;;; +22D2;DOUBLE INTERSECTION;Sm;0;ON;;;;;N;;;;; +22D3;DOUBLE UNION;Sm;0;ON;;;;;N;;;;; +22D4;PITCHFORK;Sm;0;ON;;;;;N;;;;; +22D5;EQUAL AND PARALLEL TO;Sm;0;ON;;;;;N;;;;; +22D6;LESS-THAN WITH DOT;Sm;0;ON;;;;;Y;LESS THAN WITH DOT;;;; +22D7;GREATER-THAN WITH DOT;Sm;0;ON;;;;;Y;GREATER THAN WITH DOT;;;; +22D8;VERY MUCH LESS-THAN;Sm;0;ON;;;;;Y;VERY MUCH LESS THAN;;;; +22D9;VERY MUCH GREATER-THAN;Sm;0;ON;;;;;Y;VERY MUCH GREATER THAN;;;; +22DA;LESS-THAN EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN EQUAL TO OR GREATER THAN;;;; +22DB;GREATER-THAN EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN EQUAL TO OR LESS THAN;;;; +22DC;EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR LESS THAN;;;; +22DD;EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR GREATER THAN;;;; +22DE;EQUAL TO OR PRECEDES;Sm;0;ON;;;;;Y;;;;; +22DF;EQUAL TO OR SUCCEEDS;Sm;0;ON;;;;;Y;;;;; +22E0;DOES NOT PRECEDE OR EQUAL;Sm;0;ON;227C 0338;;;;Y;;;;; +22E1;DOES NOT SUCCEED OR EQUAL;Sm;0;ON;227D 0338;;;;Y;;;;; +22E2;NOT SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;2291 0338;;;;Y;;;;; +22E3;NOT SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;2292 0338;;;;Y;;;;; +22E4;SQUARE IMAGE OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22E5;SQUARE ORIGINAL OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22E6;LESS-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUIVALENT TO;;;; +22E7;GREATER-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUIVALENT TO;;;; +22E8;PRECEDES BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +22E9;SUCCEEDS BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +22EA;NOT NORMAL SUBGROUP OF;Sm;0;ON;22B2 0338;;;;Y;;;;; +22EB;DOES NOT CONTAIN AS NORMAL SUBGROUP;Sm;0;ON;22B3 0338;;;;Y;;;;; +22EC;NOT NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;22B4 0338;;;;Y;;;;; +22ED;DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL;Sm;0;ON;22B5 0338;;;;Y;;;;; +22EE;VERTICAL ELLIPSIS;Sm;0;ON;;;;;N;;;;; +22EF;MIDLINE HORIZONTAL ELLIPSIS;Sm;0;ON;;;;;N;;;;; +22F0;UP RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;; +22F1;DOWN RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;; +22F2;ELEMENT OF WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22F3;ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22F4;SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22F5;ELEMENT OF WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +22F6;ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +22F7;SMALL ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +22F8;ELEMENT OF WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; +22F9;ELEMENT OF WITH TWO HORIZONTAL STROKES;Sm;0;ON;;;;;Y;;;;; +22FA;CONTAINS WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22FB;CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22FC;SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +22FD;CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +22FE;SMALL CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +22FF;Z NOTATION BAG MEMBERSHIP;Sm;0;ON;;;;;Y;;;;; +2300;DIAMETER SIGN;So;0;ON;;;;;N;;;;; +2301;ELECTRIC ARROW;So;0;ON;;;;;N;;;;; +2302;HOUSE;So;0;ON;;;;;N;;;;; +2303;UP ARROWHEAD;So;0;ON;;;;;N;;;;; +2304;DOWN ARROWHEAD;So;0;ON;;;;;N;;;;; +2305;PROJECTIVE;So;0;ON;;;;;N;;;;; +2306;PERSPECTIVE;So;0;ON;;;;;N;;;;; +2307;WAVY LINE;So;0;ON;;;;;N;;;;; +2308;LEFT CEILING;Sm;0;ON;;;;;Y;;;;; +2309;RIGHT CEILING;Sm;0;ON;;;;;Y;;;;; +230A;LEFT FLOOR;Sm;0;ON;;;;;Y;;;;; +230B;RIGHT FLOOR;Sm;0;ON;;;;;Y;;;;; +230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;; +230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;; +230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;; +230F;TOP LEFT CROP;So;0;ON;;;;;N;;;;; +2310;REVERSED NOT SIGN;So;0;ON;;;;;N;;;;; +2311;SQUARE LOZENGE;So;0;ON;;;;;N;;;;; +2312;ARC;So;0;ON;;;;;N;;;;; +2313;SEGMENT;So;0;ON;;;;;N;;;;; +2314;SECTOR;So;0;ON;;;;;N;;;;; +2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;; +2316;POSITION INDICATOR;So;0;ON;;;;;N;;;;; +2317;VIEWDATA SQUARE;So;0;ON;;;;;N;;;;; +2318;PLACE OF INTEREST SIGN;So;0;ON;;;;;N;COMMAND KEY;;;; +2319;TURNED NOT SIGN;So;0;ON;;;;;N;;;;; +231A;WATCH;So;0;ON;;;;;N;;;;; +231B;HOURGLASS;So;0;ON;;;;;N;;;;; +231C;TOP LEFT CORNER;So;0;ON;;;;;N;;;;; +231D;TOP RIGHT CORNER;So;0;ON;;;;;N;;;;; +231E;BOTTOM LEFT CORNER;So;0;ON;;;;;N;;;;; +231F;BOTTOM RIGHT CORNER;So;0;ON;;;;;N;;;;; +2320;TOP HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2321;BOTTOM HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2322;FROWN;So;0;ON;;;;;N;;;;; +2323;SMILE;So;0;ON;;;;;N;;;;; +2324;UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS;So;0;ON;;;;;N;ENTER KEY;;;; +2325;OPTION KEY;So;0;ON;;;;;N;;;;; +2326;ERASE TO THE RIGHT;So;0;ON;;;;;N;DELETE TO THE RIGHT KEY;;;; +2327;X IN A RECTANGLE BOX;So;0;ON;;;;;N;CLEAR KEY;;;; +2328;KEYBOARD;So;0;ON;;;;;N;;;;; +2329;LEFT-POINTING ANGLE BRACKET;Ps;0;ON;3008;;;;Y;BRA;;;; +232A;RIGHT-POINTING ANGLE BRACKET;Pe;0;ON;3009;;;;Y;KET;;;; +232B;ERASE TO THE LEFT;So;0;ON;;;;;N;DELETE TO THE LEFT KEY;;;; +232C;BENZENE RING;So;0;ON;;;;;N;;;;; +232D;CYLINDRICITY;So;0;ON;;;;;N;;;;; +232E;ALL AROUND-PROFILE;So;0;ON;;;;;N;;;;; +232F;SYMMETRY;So;0;ON;;;;;N;;;;; +2330;TOTAL RUNOUT;So;0;ON;;;;;N;;;;; +2331;DIMENSION ORIGIN;So;0;ON;;;;;N;;;;; +2332;CONICAL TAPER;So;0;ON;;;;;N;;;;; +2333;SLOPE;So;0;ON;;;;;N;;;;; +2334;COUNTERBORE;So;0;ON;;;;;N;;;;; +2335;COUNTERSINK;So;0;ON;;;;;N;;;;; +2336;APL FUNCTIONAL SYMBOL I-BEAM;So;0;L;;;;;N;;;;; +2337;APL FUNCTIONAL SYMBOL SQUISH QUAD;So;0;L;;;;;N;;;;; +2338;APL FUNCTIONAL SYMBOL QUAD EQUAL;So;0;L;;;;;N;;;;; +2339;APL FUNCTIONAL SYMBOL QUAD DIVIDE;So;0;L;;;;;N;;;;; +233A;APL FUNCTIONAL SYMBOL QUAD DIAMOND;So;0;L;;;;;N;;;;; +233B;APL FUNCTIONAL SYMBOL QUAD JOT;So;0;L;;;;;N;;;;; +233C;APL FUNCTIONAL SYMBOL QUAD CIRCLE;So;0;L;;;;;N;;;;; +233D;APL FUNCTIONAL SYMBOL CIRCLE STILE;So;0;L;;;;;N;;;;; +233E;APL FUNCTIONAL SYMBOL CIRCLE JOT;So;0;L;;;;;N;;;;; +233F;APL FUNCTIONAL SYMBOL SLASH BAR;So;0;L;;;;;N;;;;; +2340;APL FUNCTIONAL SYMBOL BACKSLASH BAR;So;0;L;;;;;N;;;;; +2341;APL FUNCTIONAL SYMBOL QUAD SLASH;So;0;L;;;;;N;;;;; +2342;APL FUNCTIONAL SYMBOL QUAD BACKSLASH;So;0;L;;;;;N;;;;; +2343;APL FUNCTIONAL SYMBOL QUAD LESS-THAN;So;0;L;;;;;N;;;;; +2344;APL FUNCTIONAL SYMBOL QUAD GREATER-THAN;So;0;L;;;;;N;;;;; +2345;APL FUNCTIONAL SYMBOL LEFTWARDS VANE;So;0;L;;;;;N;;;;; +2346;APL FUNCTIONAL SYMBOL RIGHTWARDS VANE;So;0;L;;;;;N;;;;; +2347;APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW;So;0;L;;;;;N;;;;; +2348;APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW;So;0;L;;;;;N;;;;; +2349;APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH;So;0;L;;;;;N;;;;; +234A;APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR;So;0;L;;;;;N;;*;;; +234B;APL FUNCTIONAL SYMBOL DELTA STILE;So;0;L;;;;;N;;;;; +234C;APL FUNCTIONAL SYMBOL QUAD DOWN CARET;So;0;L;;;;;N;;;;; +234D;APL FUNCTIONAL SYMBOL QUAD DELTA;So;0;L;;;;;N;;;;; +234E;APL FUNCTIONAL SYMBOL DOWN TACK JOT;So;0;L;;;;;N;;*;;; +234F;APL FUNCTIONAL SYMBOL UPWARDS VANE;So;0;L;;;;;N;;;;; +2350;APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW;So;0;L;;;;;N;;;;; +2351;APL FUNCTIONAL SYMBOL UP TACK OVERBAR;So;0;L;;;;;N;;*;;; +2352;APL FUNCTIONAL SYMBOL DEL STILE;So;0;L;;;;;N;;;;; +2353;APL FUNCTIONAL SYMBOL QUAD UP CARET;So;0;L;;;;;N;;;;; +2354;APL FUNCTIONAL SYMBOL QUAD DEL;So;0;L;;;;;N;;;;; +2355;APL FUNCTIONAL SYMBOL UP TACK JOT;So;0;L;;;;;N;;*;;; +2356;APL FUNCTIONAL SYMBOL DOWNWARDS VANE;So;0;L;;;;;N;;;;; +2357;APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW;So;0;L;;;;;N;;;;; +2358;APL FUNCTIONAL SYMBOL QUOTE UNDERBAR;So;0;L;;;;;N;;;;; +2359;APL FUNCTIONAL SYMBOL DELTA UNDERBAR;So;0;L;;;;;N;;;;; +235A;APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR;So;0;L;;;;;N;;;;; +235B;APL FUNCTIONAL SYMBOL JOT UNDERBAR;So;0;L;;;;;N;;;;; +235C;APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR;So;0;L;;;;;N;;;;; +235D;APL FUNCTIONAL SYMBOL UP SHOE JOT;So;0;L;;;;;N;;;;; +235E;APL FUNCTIONAL SYMBOL QUOTE QUAD;So;0;L;;;;;N;;;;; +235F;APL FUNCTIONAL SYMBOL CIRCLE STAR;So;0;L;;;;;N;;;;; +2360;APL FUNCTIONAL SYMBOL QUAD COLON;So;0;L;;;;;N;;;;; +2361;APL FUNCTIONAL SYMBOL UP TACK DIAERESIS;So;0;L;;;;;N;;*;;; +2362;APL FUNCTIONAL SYMBOL DEL DIAERESIS;So;0;L;;;;;N;;;;; +2363;APL FUNCTIONAL SYMBOL STAR DIAERESIS;So;0;L;;;;;N;;;;; +2364;APL FUNCTIONAL SYMBOL JOT DIAERESIS;So;0;L;;;;;N;;;;; +2365;APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS;So;0;L;;;;;N;;;;; +2366;APL FUNCTIONAL SYMBOL DOWN SHOE STILE;So;0;L;;;;;N;;;;; +2367;APL FUNCTIONAL SYMBOL LEFT SHOE STILE;So;0;L;;;;;N;;;;; +2368;APL FUNCTIONAL SYMBOL TILDE DIAERESIS;So;0;L;;;;;N;;;;; +2369;APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS;So;0;L;;;;;N;;;;; +236A;APL FUNCTIONAL SYMBOL COMMA BAR;So;0;L;;;;;N;;;;; +236B;APL FUNCTIONAL SYMBOL DEL TILDE;So;0;L;;;;;N;;;;; +236C;APL FUNCTIONAL SYMBOL ZILDE;So;0;L;;;;;N;;;;; +236D;APL FUNCTIONAL SYMBOL STILE TILDE;So;0;L;;;;;N;;;;; +236E;APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR;So;0;L;;;;;N;;;;; +236F;APL FUNCTIONAL SYMBOL QUAD NOT EQUAL;So;0;L;;;;;N;;;;; +2370;APL FUNCTIONAL SYMBOL QUAD QUESTION;So;0;L;;;;;N;;;;; +2371;APL FUNCTIONAL SYMBOL DOWN CARET TILDE;So;0;L;;;;;N;;;;; +2372;APL FUNCTIONAL SYMBOL UP CARET TILDE;So;0;L;;;;;N;;;;; +2373;APL FUNCTIONAL SYMBOL IOTA;So;0;L;;;;;N;;;;; +2374;APL FUNCTIONAL SYMBOL RHO;So;0;L;;;;;N;;;;; +2375;APL FUNCTIONAL SYMBOL OMEGA;So;0;L;;;;;N;;;;; +2376;APL FUNCTIONAL SYMBOL ALPHA UNDERBAR;So;0;L;;;;;N;;;;; +2377;APL FUNCTIONAL SYMBOL EPSILON UNDERBAR;So;0;L;;;;;N;;;;; +2378;APL FUNCTIONAL SYMBOL IOTA UNDERBAR;So;0;L;;;;;N;;;;; +2379;APL FUNCTIONAL SYMBOL OMEGA UNDERBAR;So;0;L;;;;;N;;;;; +237A;APL FUNCTIONAL SYMBOL ALPHA;So;0;L;;;;;N;;;;; +237B;NOT CHECK MARK;So;0;ON;;;;;N;;;;; +237C;RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW;Sm;0;ON;;;;;N;;;;; +237D;SHOULDERED OPEN BOX;So;0;ON;;;;;N;;;;; +237E;BELL SYMBOL;So;0;ON;;;;;N;;;;; +237F;VERTICAL LINE WITH MIDDLE DOT;So;0;ON;;;;;N;;;;; +2380;INSERTION SYMBOL;So;0;ON;;;;;N;;;;; +2381;CONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;; +2382;DISCONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;; +2383;EMPHASIS SYMBOL;So;0;ON;;;;;N;;;;; +2384;COMPOSITION SYMBOL;So;0;ON;;;;;N;;;;; +2385;WHITE SQUARE WITH CENTRE VERTICAL LINE;So;0;ON;;;;;N;;;;; +2386;ENTER SYMBOL;So;0;ON;;;;;N;;;;; +2387;ALTERNATIVE KEY SYMBOL;So;0;ON;;;;;N;;;;; +2388;HELM SYMBOL;So;0;ON;;;;;N;;;;; +2389;CIRCLED HORIZONTAL BAR WITH NOTCH;So;0;ON;;;;;N;;pause;;; +238A;CIRCLED TRIANGLE DOWN;So;0;ON;;;;;N;;break;;; +238B;BROKEN CIRCLE WITH NORTHWEST ARROW;So;0;ON;;;;;N;;escape;;; +238C;UNDO SYMBOL;So;0;ON;;;;;N;;;;; +238D;MONOSTABLE SYMBOL;So;0;ON;;;;;N;;;;; +238E;HYSTERESIS SYMBOL;So;0;ON;;;;;N;;;;; +238F;OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL;So;0;ON;;;;;N;;;;; +2390;OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL;So;0;ON;;;;;N;;;;; +2391;PASSIVE-PULL-DOWN-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;; +2392;PASSIVE-PULL-UP-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;; +2393;DIRECT CURRENT SYMBOL FORM TWO;So;0;ON;;;;;N;;;;; +2394;SOFTWARE-FUNCTION SYMBOL;So;0;ON;;;;;N;;;;; +2395;APL FUNCTIONAL SYMBOL QUAD;So;0;L;;;;;N;;;;; +2396;DECIMAL SEPARATOR KEY SYMBOL;So;0;ON;;;;;N;;;;; +2397;PREVIOUS PAGE;So;0;ON;;;;;N;;;;; +2398;NEXT PAGE;So;0;ON;;;;;N;;;;; +2399;PRINT SCREEN SYMBOL;So;0;ON;;;;;N;;;;; +239A;CLEAR SCREEN SYMBOL;So;0;ON;;;;;N;;;;; +239B;LEFT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;; +239C;LEFT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;; +239D;LEFT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;; +239E;RIGHT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;; +239F;RIGHT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;; +23A0;RIGHT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;; +23A1;LEFT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;; +23A2;LEFT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; +23A3;LEFT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;; +23A4;RIGHT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;; +23A5;RIGHT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; +23A6;RIGHT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;; +23A7;LEFT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;; +23A8;LEFT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;; +23A9;LEFT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;; +23AA;CURLY BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;; +23AB;RIGHT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;; +23AC;RIGHT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;; +23AD;RIGHT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;; +23AE;INTEGRAL EXTENSION;Sm;0;ON;;;;;N;;;;; +23AF;HORIZONTAL LINE EXTENSION;Sm;0;ON;;;;;N;;;;; +23B0;UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;; +23B1;UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;; +23B2;SUMMATION TOP;Sm;0;ON;;;;;N;;;;; +23B3;SUMMATION BOTTOM;Sm;0;ON;;;;;N;;;;; +23B4;TOP SQUARE BRACKET;Ps;0;ON;;;;;N;;;;; +23B5;BOTTOM SQUARE BRACKET;Pe;0;ON;;;;;N;;;;; +23B6;BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET;Po;0;ON;;;;;N;;;;; +23B7;RADICAL SYMBOL BOTTOM;So;0;ON;;;;;N;;;;; +23B8;LEFT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;; +23B9;RIGHT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;; +23BA;HORIZONTAL SCAN LINE-1;So;0;ON;;;;;N;;;;; +23BB;HORIZONTAL SCAN LINE-3;So;0;ON;;;;;N;;;;; +23BC;HORIZONTAL SCAN LINE-7;So;0;ON;;;;;N;;;;; +23BD;HORIZONTAL SCAN LINE-9;So;0;ON;;;;;N;;;;; +23BE;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT;So;0;ON;;;;;N;;;;; +23BF;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT;So;0;ON;;;;;N;;;;; +23C0;DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE;So;0;ON;;;;;N;;;;; +23C1;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;; +23C2;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;; +23C3;DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; +23C4;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; +23C5;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;; +23C6;DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE;So;0;ON;;;;;N;;;;; +23C7;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;; +23C8;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;; +23C9;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;;;;; +23CA;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;;;;; +23CB;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT;So;0;ON;;;;;N;;;;; +23CC;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT;So;0;ON;;;;;N;;;;; +23CD;SQUARE FOOT;So;0;ON;;;;;N;;;;; +23CE;RETURN SYMBOL;So;0;ON;;;;;N;;;;; +23CF;EJECT SYMBOL;So;0;ON;;;;;N;;;;; +23D0;VERTICAL LINE EXTENSION;So;0;ON;;;;;N;;;;; +2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;; +2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;; +2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;; +2403;SYMBOL FOR END OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR END OF TEXT;;;; +2404;SYMBOL FOR END OF TRANSMISSION;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION;;;; +2405;SYMBOL FOR ENQUIRY;So;0;ON;;;;;N;GRAPHIC FOR ENQUIRY;;;; +2406;SYMBOL FOR ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR ACKNOWLEDGE;;;; +2407;SYMBOL FOR BELL;So;0;ON;;;;;N;GRAPHIC FOR BELL;;;; +2408;SYMBOL FOR BACKSPACE;So;0;ON;;;;;N;GRAPHIC FOR BACKSPACE;;;; +2409;SYMBOL FOR HORIZONTAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR HORIZONTAL TABULATION;;;; +240A;SYMBOL FOR LINE FEED;So;0;ON;;;;;N;GRAPHIC FOR LINE FEED;;;; +240B;SYMBOL FOR VERTICAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR VERTICAL TABULATION;;;; +240C;SYMBOL FOR FORM FEED;So;0;ON;;;;;N;GRAPHIC FOR FORM FEED;;;; +240D;SYMBOL FOR CARRIAGE RETURN;So;0;ON;;;;;N;GRAPHIC FOR CARRIAGE RETURN;;;; +240E;SYMBOL FOR SHIFT OUT;So;0;ON;;;;;N;GRAPHIC FOR SHIFT OUT;;;; +240F;SYMBOL FOR SHIFT IN;So;0;ON;;;;;N;GRAPHIC FOR SHIFT IN;;;; +2410;SYMBOL FOR DATA LINK ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR DATA LINK ESCAPE;;;; +2411;SYMBOL FOR DEVICE CONTROL ONE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL ONE;;;; +2412;SYMBOL FOR DEVICE CONTROL TWO;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL TWO;;;; +2413;SYMBOL FOR DEVICE CONTROL THREE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL THREE;;;; +2414;SYMBOL FOR DEVICE CONTROL FOUR;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL FOUR;;;; +2415;SYMBOL FOR NEGATIVE ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR NEGATIVE ACKNOWLEDGE;;;; +2416;SYMBOL FOR SYNCHRONOUS IDLE;So;0;ON;;;;;N;GRAPHIC FOR SYNCHRONOUS IDLE;;;; +2417;SYMBOL FOR END OF TRANSMISSION BLOCK;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION BLOCK;;;; +2418;SYMBOL FOR CANCEL;So;0;ON;;;;;N;GRAPHIC FOR CANCEL;;;; +2419;SYMBOL FOR END OF MEDIUM;So;0;ON;;;;;N;GRAPHIC FOR END OF MEDIUM;;;; +241A;SYMBOL FOR SUBSTITUTE;So;0;ON;;;;;N;GRAPHIC FOR SUBSTITUTE;;;; +241B;SYMBOL FOR ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR ESCAPE;;;; +241C;SYMBOL FOR FILE SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR FILE SEPARATOR;;;; +241D;SYMBOL FOR GROUP SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR GROUP SEPARATOR;;;; +241E;SYMBOL FOR RECORD SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR RECORD SEPARATOR;;;; +241F;SYMBOL FOR UNIT SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR UNIT SEPARATOR;;;; +2420;SYMBOL FOR SPACE;So;0;ON;;;;;N;GRAPHIC FOR SPACE;;;; +2421;SYMBOL FOR DELETE;So;0;ON;;;;;N;GRAPHIC FOR DELETE;;;; +2422;BLANK SYMBOL;So;0;ON;;;;;N;BLANK;;;; +2423;OPEN BOX;So;0;ON;;;;;N;;;;; +2424;SYMBOL FOR NEWLINE;So;0;ON;;;;;N;GRAPHIC FOR NEWLINE;;;; +2425;SYMBOL FOR DELETE FORM TWO;So;0;ON;;;;;N;;;;; +2426;SYMBOL FOR SUBSTITUTE FORM TWO;So;0;ON;;;;;N;;;;; +2440;OCR HOOK;So;0;ON;;;;;N;;;;; +2441;OCR CHAIR;So;0;ON;;;;;N;;;;; +2442;OCR FORK;So;0;ON;;;;;N;;;;; +2443;OCR INVERTED FORK;So;0;ON;;;;;N;;;;; +2444;OCR BELT BUCKLE;So;0;ON;;;;;N;;;;; +2445;OCR BOW TIE;So;0;ON;;;;;N;;;;; +2446;OCR BRANCH BANK IDENTIFICATION;So;0;ON;;;;;N;;;;; +2447;OCR AMOUNT OF CHECK;So;0;ON;;;;;N;;;;; +2448;OCR DASH;So;0;ON;;;;;N;;;;; +2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;; +244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;; +2460;CIRCLED DIGIT ONE;No;0;EN;<circle> 0031;;1;1;N;;;;; +2461;CIRCLED DIGIT TWO;No;0;EN;<circle> 0032;;2;2;N;;;;; +2462;CIRCLED DIGIT THREE;No;0;EN;<circle> 0033;;3;3;N;;;;; +2463;CIRCLED DIGIT FOUR;No;0;EN;<circle> 0034;;4;4;N;;;;; +2464;CIRCLED DIGIT FIVE;No;0;EN;<circle> 0035;;5;5;N;;;;; +2465;CIRCLED DIGIT SIX;No;0;EN;<circle> 0036;;6;6;N;;;;; +2466;CIRCLED DIGIT SEVEN;No;0;EN;<circle> 0037;;7;7;N;;;;; +2467;CIRCLED DIGIT EIGHT;No;0;EN;<circle> 0038;;8;8;N;;;;; +2468;CIRCLED DIGIT NINE;No;0;EN;<circle> 0039;;9;9;N;;;;; +2469;CIRCLED NUMBER TEN;No;0;EN;<circle> 0031 0030;;;10;N;;;;; +246A;CIRCLED NUMBER ELEVEN;No;0;EN;<circle> 0031 0031;;;11;N;;;;; +246B;CIRCLED NUMBER TWELVE;No;0;EN;<circle> 0031 0032;;;12;N;;;;; +246C;CIRCLED NUMBER THIRTEEN;No;0;EN;<circle> 0031 0033;;;13;N;;;;; +246D;CIRCLED NUMBER FOURTEEN;No;0;EN;<circle> 0031 0034;;;14;N;;;;; +246E;CIRCLED NUMBER FIFTEEN;No;0;EN;<circle> 0031 0035;;;15;N;;;;; +246F;CIRCLED NUMBER SIXTEEN;No;0;EN;<circle> 0031 0036;;;16;N;;;;; +2470;CIRCLED NUMBER SEVENTEEN;No;0;EN;<circle> 0031 0037;;;17;N;;;;; +2471;CIRCLED NUMBER EIGHTEEN;No;0;EN;<circle> 0031 0038;;;18;N;;;;; +2472;CIRCLED NUMBER NINETEEN;No;0;EN;<circle> 0031 0039;;;19;N;;;;; +2473;CIRCLED NUMBER TWENTY;No;0;EN;<circle> 0032 0030;;;20;N;;;;; +2474;PARENTHESIZED DIGIT ONE;No;0;EN;<compat> 0028 0031 0029;;1;1;N;;;;; +2475;PARENTHESIZED DIGIT TWO;No;0;EN;<compat> 0028 0032 0029;;2;2;N;;;;; +2476;PARENTHESIZED DIGIT THREE;No;0;EN;<compat> 0028 0033 0029;;3;3;N;;;;; +2477;PARENTHESIZED DIGIT FOUR;No;0;EN;<compat> 0028 0034 0029;;4;4;N;;;;; +2478;PARENTHESIZED DIGIT FIVE;No;0;EN;<compat> 0028 0035 0029;;5;5;N;;;;; +2479;PARENTHESIZED DIGIT SIX;No;0;EN;<compat> 0028 0036 0029;;6;6;N;;;;; +247A;PARENTHESIZED DIGIT SEVEN;No;0;EN;<compat> 0028 0037 0029;;7;7;N;;;;; +247B;PARENTHESIZED DIGIT EIGHT;No;0;EN;<compat> 0028 0038 0029;;8;8;N;;;;; +247C;PARENTHESIZED DIGIT NINE;No;0;EN;<compat> 0028 0039 0029;;9;9;N;;;;; +247D;PARENTHESIZED NUMBER TEN;No;0;EN;<compat> 0028 0031 0030 0029;;;10;N;;;;; +247E;PARENTHESIZED NUMBER ELEVEN;No;0;EN;<compat> 0028 0031 0031 0029;;;11;N;;;;; +247F;PARENTHESIZED NUMBER TWELVE;No;0;EN;<compat> 0028 0031 0032 0029;;;12;N;;;;; +2480;PARENTHESIZED NUMBER THIRTEEN;No;0;EN;<compat> 0028 0031 0033 0029;;;13;N;;;;; +2481;PARENTHESIZED NUMBER FOURTEEN;No;0;EN;<compat> 0028 0031 0034 0029;;;14;N;;;;; +2482;PARENTHESIZED NUMBER FIFTEEN;No;0;EN;<compat> 0028 0031 0035 0029;;;15;N;;;;; +2483;PARENTHESIZED NUMBER SIXTEEN;No;0;EN;<compat> 0028 0031 0036 0029;;;16;N;;;;; +2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;EN;<compat> 0028 0031 0037 0029;;;17;N;;;;; +2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;EN;<compat> 0028 0031 0038 0029;;;18;N;;;;; +2486;PARENTHESIZED NUMBER NINETEEN;No;0;EN;<compat> 0028 0031 0039 0029;;;19;N;;;;; +2487;PARENTHESIZED NUMBER TWENTY;No;0;EN;<compat> 0028 0032 0030 0029;;;20;N;;;;; +2488;DIGIT ONE FULL STOP;No;0;EN;<compat> 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;; +2489;DIGIT TWO FULL STOP;No;0;EN;<compat> 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;; +248A;DIGIT THREE FULL STOP;No;0;EN;<compat> 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;; +248B;DIGIT FOUR FULL STOP;No;0;EN;<compat> 0034 002E;;4;4;N;DIGIT FOUR PERIOD;;;; +248C;DIGIT FIVE FULL STOP;No;0;EN;<compat> 0035 002E;;5;5;N;DIGIT FIVE PERIOD;;;; +248D;DIGIT SIX FULL STOP;No;0;EN;<compat> 0036 002E;;6;6;N;DIGIT SIX PERIOD;;;; +248E;DIGIT SEVEN FULL STOP;No;0;EN;<compat> 0037 002E;;7;7;N;DIGIT SEVEN PERIOD;;;; +248F;DIGIT EIGHT FULL STOP;No;0;EN;<compat> 0038 002E;;8;8;N;DIGIT EIGHT PERIOD;;;; +2490;DIGIT NINE FULL STOP;No;0;EN;<compat> 0039 002E;;9;9;N;DIGIT NINE PERIOD;;;; +2491;NUMBER TEN FULL STOP;No;0;EN;<compat> 0031 0030 002E;;;10;N;NUMBER TEN PERIOD;;;; +2492;NUMBER ELEVEN FULL STOP;No;0;EN;<compat> 0031 0031 002E;;;11;N;NUMBER ELEVEN PERIOD;;;; +2493;NUMBER TWELVE FULL STOP;No;0;EN;<compat> 0031 0032 002E;;;12;N;NUMBER TWELVE PERIOD;;;; +2494;NUMBER THIRTEEN FULL STOP;No;0;EN;<compat> 0031 0033 002E;;;13;N;NUMBER THIRTEEN PERIOD;;;; +2495;NUMBER FOURTEEN FULL STOP;No;0;EN;<compat> 0031 0034 002E;;;14;N;NUMBER FOURTEEN PERIOD;;;; +2496;NUMBER FIFTEEN FULL STOP;No;0;EN;<compat> 0031 0035 002E;;;15;N;NUMBER FIFTEEN PERIOD;;;; +2497;NUMBER SIXTEEN FULL STOP;No;0;EN;<compat> 0031 0036 002E;;;16;N;NUMBER SIXTEEN PERIOD;;;; +2498;NUMBER SEVENTEEN FULL STOP;No;0;EN;<compat> 0031 0037 002E;;;17;N;NUMBER SEVENTEEN PERIOD;;;; +2499;NUMBER EIGHTEEN FULL STOP;No;0;EN;<compat> 0031 0038 002E;;;18;N;NUMBER EIGHTEEN PERIOD;;;; +249A;NUMBER NINETEEN FULL STOP;No;0;EN;<compat> 0031 0039 002E;;;19;N;NUMBER NINETEEN PERIOD;;;; +249B;NUMBER TWENTY FULL STOP;No;0;EN;<compat> 0032 0030 002E;;;20;N;NUMBER TWENTY PERIOD;;;; +249C;PARENTHESIZED LATIN SMALL LETTER A;So;0;L;<compat> 0028 0061 0029;;;;N;;;;; +249D;PARENTHESIZED LATIN SMALL LETTER B;So;0;L;<compat> 0028 0062 0029;;;;N;;;;; +249E;PARENTHESIZED LATIN SMALL LETTER C;So;0;L;<compat> 0028 0063 0029;;;;N;;;;; +249F;PARENTHESIZED LATIN SMALL LETTER D;So;0;L;<compat> 0028 0064 0029;;;;N;;;;; +24A0;PARENTHESIZED LATIN SMALL LETTER E;So;0;L;<compat> 0028 0065 0029;;;;N;;;;; +24A1;PARENTHESIZED LATIN SMALL LETTER F;So;0;L;<compat> 0028 0066 0029;;;;N;;;;; +24A2;PARENTHESIZED LATIN SMALL LETTER G;So;0;L;<compat> 0028 0067 0029;;;;N;;;;; +24A3;PARENTHESIZED LATIN SMALL LETTER H;So;0;L;<compat> 0028 0068 0029;;;;N;;;;; +24A4;PARENTHESIZED LATIN SMALL LETTER I;So;0;L;<compat> 0028 0069 0029;;;;N;;;;; +24A5;PARENTHESIZED LATIN SMALL LETTER J;So;0;L;<compat> 0028 006A 0029;;;;N;;;;; +24A6;PARENTHESIZED LATIN SMALL LETTER K;So;0;L;<compat> 0028 006B 0029;;;;N;;;;; +24A7;PARENTHESIZED LATIN SMALL LETTER L;So;0;L;<compat> 0028 006C 0029;;;;N;;;;; +24A8;PARENTHESIZED LATIN SMALL LETTER M;So;0;L;<compat> 0028 006D 0029;;;;N;;;;; +24A9;PARENTHESIZED LATIN SMALL LETTER N;So;0;L;<compat> 0028 006E 0029;;;;N;;;;; +24AA;PARENTHESIZED LATIN SMALL LETTER O;So;0;L;<compat> 0028 006F 0029;;;;N;;;;; +24AB;PARENTHESIZED LATIN SMALL LETTER P;So;0;L;<compat> 0028 0070 0029;;;;N;;;;; +24AC;PARENTHESIZED LATIN SMALL LETTER Q;So;0;L;<compat> 0028 0071 0029;;;;N;;;;; +24AD;PARENTHESIZED LATIN SMALL LETTER R;So;0;L;<compat> 0028 0072 0029;;;;N;;;;; +24AE;PARENTHESIZED LATIN SMALL LETTER S;So;0;L;<compat> 0028 0073 0029;;;;N;;;;; +24AF;PARENTHESIZED LATIN SMALL LETTER T;So;0;L;<compat> 0028 0074 0029;;;;N;;;;; +24B0;PARENTHESIZED LATIN SMALL LETTER U;So;0;L;<compat> 0028 0075 0029;;;;N;;;;; +24B1;PARENTHESIZED LATIN SMALL LETTER V;So;0;L;<compat> 0028 0076 0029;;;;N;;;;; +24B2;PARENTHESIZED LATIN SMALL LETTER W;So;0;L;<compat> 0028 0077 0029;;;;N;;;;; +24B3;PARENTHESIZED LATIN SMALL LETTER X;So;0;L;<compat> 0028 0078 0029;;;;N;;;;; +24B4;PARENTHESIZED LATIN SMALL LETTER Y;So;0;L;<compat> 0028 0079 0029;;;;N;;;;; +24B5;PARENTHESIZED LATIN SMALL LETTER Z;So;0;L;<compat> 0028 007A 0029;;;;N;;;;; +24B6;CIRCLED LATIN CAPITAL LETTER A;So;0;L;<circle> 0041;;;;N;;;;24D0; +24B7;CIRCLED LATIN CAPITAL LETTER B;So;0;L;<circle> 0042;;;;N;;;;24D1; +24B8;CIRCLED LATIN CAPITAL LETTER C;So;0;L;<circle> 0043;;;;N;;;;24D2; +24B9;CIRCLED LATIN CAPITAL LETTER D;So;0;L;<circle> 0044;;;;N;;;;24D3; +24BA;CIRCLED LATIN CAPITAL LETTER E;So;0;L;<circle> 0045;;;;N;;;;24D4; +24BB;CIRCLED LATIN CAPITAL LETTER F;So;0;L;<circle> 0046;;;;N;;;;24D5; +24BC;CIRCLED LATIN CAPITAL LETTER G;So;0;L;<circle> 0047;;;;N;;;;24D6; +24BD;CIRCLED LATIN CAPITAL LETTER H;So;0;L;<circle> 0048;;;;N;;;;24D7; +24BE;CIRCLED LATIN CAPITAL LETTER I;So;0;L;<circle> 0049;;;;N;;;;24D8; +24BF;CIRCLED LATIN CAPITAL LETTER J;So;0;L;<circle> 004A;;;;N;;;;24D9; +24C0;CIRCLED LATIN CAPITAL LETTER K;So;0;L;<circle> 004B;;;;N;;;;24DA; +24C1;CIRCLED LATIN CAPITAL LETTER L;So;0;L;<circle> 004C;;;;N;;;;24DB; +24C2;CIRCLED LATIN CAPITAL LETTER M;So;0;L;<circle> 004D;;;;N;;;;24DC; +24C3;CIRCLED LATIN CAPITAL LETTER N;So;0;L;<circle> 004E;;;;N;;;;24DD; +24C4;CIRCLED LATIN CAPITAL LETTER O;So;0;L;<circle> 004F;;;;N;;;;24DE; +24C5;CIRCLED LATIN CAPITAL LETTER P;So;0;L;<circle> 0050;;;;N;;;;24DF; +24C6;CIRCLED LATIN CAPITAL LETTER Q;So;0;L;<circle> 0051;;;;N;;;;24E0; +24C7;CIRCLED LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;24E1; +24C8;CIRCLED LATIN CAPITAL LETTER S;So;0;L;<circle> 0053;;;;N;;;;24E2; +24C9;CIRCLED LATIN CAPITAL LETTER T;So;0;L;<circle> 0054;;;;N;;;;24E3; +24CA;CIRCLED LATIN CAPITAL LETTER U;So;0;L;<circle> 0055;;;;N;;;;24E4; +24CB;CIRCLED LATIN CAPITAL LETTER V;So;0;L;<circle> 0056;;;;N;;;;24E5; +24CC;CIRCLED LATIN CAPITAL LETTER W;So;0;L;<circle> 0057;;;;N;;;;24E6; +24CD;CIRCLED LATIN CAPITAL LETTER X;So;0;L;<circle> 0058;;;;N;;;;24E7; +24CE;CIRCLED LATIN CAPITAL LETTER Y;So;0;L;<circle> 0059;;;;N;;;;24E8; +24CF;CIRCLED LATIN CAPITAL LETTER Z;So;0;L;<circle> 005A;;;;N;;;;24E9; +24D0;CIRCLED LATIN SMALL LETTER A;So;0;L;<circle> 0061;;;;N;;;24B6;;24B6 +24D1;CIRCLED LATIN SMALL LETTER B;So;0;L;<circle> 0062;;;;N;;;24B7;;24B7 +24D2;CIRCLED LATIN SMALL LETTER C;So;0;L;<circle> 0063;;;;N;;;24B8;;24B8 +24D3;CIRCLED LATIN SMALL LETTER D;So;0;L;<circle> 0064;;;;N;;;24B9;;24B9 +24D4;CIRCLED LATIN SMALL LETTER E;So;0;L;<circle> 0065;;;;N;;;24BA;;24BA +24D5;CIRCLED LATIN SMALL LETTER F;So;0;L;<circle> 0066;;;;N;;;24BB;;24BB +24D6;CIRCLED LATIN SMALL LETTER G;So;0;L;<circle> 0067;;;;N;;;24BC;;24BC +24D7;CIRCLED LATIN SMALL LETTER H;So;0;L;<circle> 0068;;;;N;;;24BD;;24BD +24D8;CIRCLED LATIN SMALL LETTER I;So;0;L;<circle> 0069;;;;N;;;24BE;;24BE +24D9;CIRCLED LATIN SMALL LETTER J;So;0;L;<circle> 006A;;;;N;;;24BF;;24BF +24DA;CIRCLED LATIN SMALL LETTER K;So;0;L;<circle> 006B;;;;N;;;24C0;;24C0 +24DB;CIRCLED LATIN SMALL LETTER L;So;0;L;<circle> 006C;;;;N;;;24C1;;24C1 +24DC;CIRCLED LATIN SMALL LETTER M;So;0;L;<circle> 006D;;;;N;;;24C2;;24C2 +24DD;CIRCLED LATIN SMALL LETTER N;So;0;L;<circle> 006E;;;;N;;;24C3;;24C3 +24DE;CIRCLED LATIN SMALL LETTER O;So;0;L;<circle> 006F;;;;N;;;24C4;;24C4 +24DF;CIRCLED LATIN SMALL LETTER P;So;0;L;<circle> 0070;;;;N;;;24C5;;24C5 +24E0;CIRCLED LATIN SMALL LETTER Q;So;0;L;<circle> 0071;;;;N;;;24C6;;24C6 +24E1;CIRCLED LATIN SMALL LETTER R;So;0;L;<circle> 0072;;;;N;;;24C7;;24C7 +24E2;CIRCLED LATIN SMALL LETTER S;So;0;L;<circle> 0073;;;;N;;;24C8;;24C8 +24E3;CIRCLED LATIN SMALL LETTER T;So;0;L;<circle> 0074;;;;N;;;24C9;;24C9 +24E4;CIRCLED LATIN SMALL LETTER U;So;0;L;<circle> 0075;;;;N;;;24CA;;24CA +24E5;CIRCLED LATIN SMALL LETTER V;So;0;L;<circle> 0076;;;;N;;;24CB;;24CB +24E6;CIRCLED LATIN SMALL LETTER W;So;0;L;<circle> 0077;;;;N;;;24CC;;24CC +24E7;CIRCLED LATIN SMALL LETTER X;So;0;L;<circle> 0078;;;;N;;;24CD;;24CD +24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L;<circle> 0079;;;;N;;;24CE;;24CE +24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L;<circle> 007A;;;;N;;;24CF;;24CF +24EA;CIRCLED DIGIT ZERO;No;0;EN;<circle> 0030;;0;0;N;;;;; +24EB;NEGATIVE CIRCLED NUMBER ELEVEN;No;0;ON;;;;11;N;;;;; +24EC;NEGATIVE CIRCLED NUMBER TWELVE;No;0;ON;;;;12;N;;;;; +24ED;NEGATIVE CIRCLED NUMBER THIRTEEN;No;0;ON;;;;13;N;;;;; +24EE;NEGATIVE CIRCLED NUMBER FOURTEEN;No;0;ON;;;;14;N;;;;; +24EF;NEGATIVE CIRCLED NUMBER FIFTEEN;No;0;ON;;;;15;N;;;;; +24F0;NEGATIVE CIRCLED NUMBER SIXTEEN;No;0;ON;;;;16;N;;;;; +24F1;NEGATIVE CIRCLED NUMBER SEVENTEEN;No;0;ON;;;;17;N;;;;; +24F2;NEGATIVE CIRCLED NUMBER EIGHTEEN;No;0;ON;;;;18;N;;;;; +24F3;NEGATIVE CIRCLED NUMBER NINETEEN;No;0;ON;;;;19;N;;;;; +24F4;NEGATIVE CIRCLED NUMBER TWENTY;No;0;ON;;;;20;N;;;;; +24F5;DOUBLE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;;;;; +24F6;DOUBLE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;;;;; +24F7;DOUBLE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;;;;; +24F8;DOUBLE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;;;;; +24F9;DOUBLE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;;;;; +24FA;DOUBLE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;;;;; +24FB;DOUBLE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;;;;; +24FC;DOUBLE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;;;;; +24FD;DOUBLE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;;;;; +24FE;DOUBLE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;;;;; +24FF;NEGATIVE CIRCLED DIGIT ZERO;No;0;ON;;;0;0;N;;;;; +2500;BOX DRAWINGS LIGHT HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT HORIZONTAL;;;; +2501;BOX DRAWINGS HEAVY HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY HORIZONTAL;;;; +2502;BOX DRAWINGS LIGHT VERTICAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL;;;; +2503;BOX DRAWINGS HEAVY VERTICAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL;;;; +2504;BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH HORIZONTAL;;;; +2505;BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH HORIZONTAL;;;; +2506;BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH VERTICAL;;;; +2507;BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH VERTICAL;;;; +2508;BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH HORIZONTAL;;;; +2509;BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH HORIZONTAL;;;; +250A;BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH VERTICAL;;;; +250B;BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH VERTICAL;;;; +250C;BOX DRAWINGS LIGHT DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND RIGHT;;;; +250D;BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT HEAVY;;;; +250E;BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT LIGHT;;;; +250F;BOX DRAWINGS HEAVY DOWN AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND RIGHT;;;; +2510;BOX DRAWINGS LIGHT DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND LEFT;;;; +2511;BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT HEAVY;;;; +2512;BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT LIGHT;;;; +2513;BOX DRAWINGS HEAVY DOWN AND LEFT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND LEFT;;;; +2514;BOX DRAWINGS LIGHT UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT UP AND RIGHT;;;; +2515;BOX DRAWINGS UP LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT HEAVY;;;; +2516;BOX DRAWINGS UP HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT LIGHT;;;; +2517;BOX DRAWINGS HEAVY UP AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY UP AND RIGHT;;;; +2518;BOX DRAWINGS LIGHT UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT UP AND LEFT;;;; +2519;BOX DRAWINGS UP LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT HEAVY;;;; +251A;BOX DRAWINGS UP HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT LIGHT;;;; +251B;BOX DRAWINGS HEAVY UP AND LEFT;So;0;ON;;;;;N;FORMS HEAVY UP AND LEFT;;;; +251C;BOX DRAWINGS LIGHT VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND RIGHT;;;; +251D;BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND RIGHT HEAVY;;;; +251E;BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT DOWN LIGHT;;;; +251F;BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT UP LIGHT;;;; +2520;BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND RIGHT LIGHT;;;; +2521;BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT UP HEAVY;;;; +2522;BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT DOWN HEAVY;;;; +2523;BOX DRAWINGS HEAVY VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND RIGHT;;;; +2524;BOX DRAWINGS LIGHT VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND LEFT;;;; +2525;BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND LEFT HEAVY;;;; +2526;BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT DOWN LIGHT;;;; +2527;BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT UP LIGHT;;;; +2528;BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND LEFT LIGHT;;;; +2529;BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT UP HEAVY;;;; +252A;BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT DOWN HEAVY;;;; +252B;BOX DRAWINGS HEAVY VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND LEFT;;;; +252C;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOWN AND HORIZONTAL;;;; +252D;BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT DOWN LIGHT;;;; +252E;BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT DOWN LIGHT;;;; +252F;BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND HORIZONTAL HEAVY;;;; +2530;BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND HORIZONTAL LIGHT;;;; +2531;BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT DOWN HEAVY;;;; +2532;BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT DOWN HEAVY;;;; +2533;BOX DRAWINGS HEAVY DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOWN AND HORIZONTAL;;;; +2534;BOX DRAWINGS LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT UP AND HORIZONTAL;;;; +2535;BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT UP LIGHT;;;; +2536;BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT UP LIGHT;;;; +2537;BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND HORIZONTAL HEAVY;;;; +2538;BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND HORIZONTAL LIGHT;;;; +2539;BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT UP HEAVY;;;; +253A;BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT UP HEAVY;;;; +253B;BOX DRAWINGS HEAVY UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY UP AND HORIZONTAL;;;; +253C;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND HORIZONTAL;;;; +253D;BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT VERTICAL LIGHT;;;; +253E;BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT VERTICAL LIGHT;;;; +253F;BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND HORIZONTAL HEAVY;;;; +2540;BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND DOWN HORIZONTAL LIGHT;;;; +2541;BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND UP HORIZONTAL LIGHT;;;; +2542;BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND HORIZONTAL LIGHT;;;; +2543;BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT UP HEAVY AND RIGHT DOWN LIGHT;;;; +2544;BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT UP HEAVY AND LEFT DOWN LIGHT;;;; +2545;BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT DOWN HEAVY AND RIGHT UP LIGHT;;;; +2546;BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT DOWN HEAVY AND LEFT UP LIGHT;;;; +2547;BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND UP HORIZONTAL HEAVY;;;; +2548;BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND DOWN HORIZONTAL HEAVY;;;; +2549;BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT VERTICAL HEAVY;;;; +254A;BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT VERTICAL HEAVY;;;; +254B;BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND HORIZONTAL;;;; +254C;BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH HORIZONTAL;;;; +254D;BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH HORIZONTAL;;;; +254E;BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH VERTICAL;;;; +254F;BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH VERTICAL;;;; +2550;BOX DRAWINGS DOUBLE HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE HORIZONTAL;;;; +2551;BOX DRAWINGS DOUBLE VERTICAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL;;;; +2552;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND RIGHT DOUBLE;;;; +2553;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND RIGHT SINGLE;;;; +2554;BOX DRAWINGS DOUBLE DOWN AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND RIGHT;;;; +2555;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND LEFT DOUBLE;;;; +2556;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND LEFT SINGLE;;;; +2557;BOX DRAWINGS DOUBLE DOWN AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND LEFT;;;; +2558;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND RIGHT DOUBLE;;;; +2559;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND RIGHT SINGLE;;;; +255A;BOX DRAWINGS DOUBLE UP AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE UP AND RIGHT;;;; +255B;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND LEFT DOUBLE;;;; +255C;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND LEFT SINGLE;;;; +255D;BOX DRAWINGS DOUBLE UP AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE UP AND LEFT;;;; +255E;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND RIGHT DOUBLE;;;; +255F;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND RIGHT SINGLE;;;; +2560;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND RIGHT;;;; +2561;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND LEFT DOUBLE;;;; +2562;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND LEFT SINGLE;;;; +2563;BOX DRAWINGS DOUBLE VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND LEFT;;;; +2564;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND HORIZONTAL DOUBLE;;;; +2565;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND HORIZONTAL SINGLE;;;; +2566;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND HORIZONTAL;;;; +2567;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND HORIZONTAL DOUBLE;;;; +2568;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND HORIZONTAL SINGLE;;;; +2569;BOX DRAWINGS DOUBLE UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE UP AND HORIZONTAL;;;; +256A;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND HORIZONTAL DOUBLE;;;; +256B;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND HORIZONTAL SINGLE;;;; +256C;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND HORIZONTAL;;;; +256D;BOX DRAWINGS LIGHT ARC DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND RIGHT;;;; +256E;BOX DRAWINGS LIGHT ARC DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND LEFT;;;; +256F;BOX DRAWINGS LIGHT ARC UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND LEFT;;;; +2570;BOX DRAWINGS LIGHT ARC UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND RIGHT;;;; +2571;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;;;; +2572;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;;;; +2573;BOX DRAWINGS LIGHT DIAGONAL CROSS;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL CROSS;;;; +2574;BOX DRAWINGS LIGHT LEFT;So;0;ON;;;;;N;FORMS LIGHT LEFT;;;; +2575;BOX DRAWINGS LIGHT UP;So;0;ON;;;;;N;FORMS LIGHT UP;;;; +2576;BOX DRAWINGS LIGHT RIGHT;So;0;ON;;;;;N;FORMS LIGHT RIGHT;;;; +2577;BOX DRAWINGS LIGHT DOWN;So;0;ON;;;;;N;FORMS LIGHT DOWN;;;; +2578;BOX DRAWINGS HEAVY LEFT;So;0;ON;;;;;N;FORMS HEAVY LEFT;;;; +2579;BOX DRAWINGS HEAVY UP;So;0;ON;;;;;N;FORMS HEAVY UP;;;; +257A;BOX DRAWINGS HEAVY RIGHT;So;0;ON;;;;;N;FORMS HEAVY RIGHT;;;; +257B;BOX DRAWINGS HEAVY DOWN;So;0;ON;;;;;N;FORMS HEAVY DOWN;;;; +257C;BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT;So;0;ON;;;;;N;FORMS LIGHT LEFT AND HEAVY RIGHT;;;; +257D;BOX DRAWINGS LIGHT UP AND HEAVY DOWN;So;0;ON;;;;;N;FORMS LIGHT UP AND HEAVY DOWN;;;; +257E;BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT;So;0;ON;;;;;N;FORMS HEAVY LEFT AND LIGHT RIGHT;;;; +257F;BOX DRAWINGS HEAVY UP AND LIGHT DOWN;So;0;ON;;;;;N;FORMS HEAVY UP AND LIGHT DOWN;;;; +2580;UPPER HALF BLOCK;So;0;ON;;;;;N;;;;; +2581;LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2582;LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +2583;LOWER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +2584;LOWER HALF BLOCK;So;0;ON;;;;;N;;;;; +2585;LOWER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +2586;LOWER THREE QUARTERS BLOCK;So;0;ON;;;;;N;LOWER THREE QUARTER BLOCK;;;; +2587;LOWER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +2588;FULL BLOCK;So;0;ON;;;;;N;;;;; +2589;LEFT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +258A;LEFT THREE QUARTERS BLOCK;So;0;ON;;;;;N;LEFT THREE QUARTER BLOCK;;;; +258B;LEFT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +258C;LEFT HALF BLOCK;So;0;ON;;;;;N;;;;; +258D;LEFT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +258E;LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +258F;LEFT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2590;RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;; +2591;LIGHT SHADE;So;0;ON;;;;;N;;;;; +2592;MEDIUM SHADE;So;0;ON;;;;;N;;;;; +2593;DARK SHADE;So;0;ON;;;;;N;;;;; +2594;UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2595;RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2596;QUADRANT LOWER LEFT;So;0;ON;;;;;N;;;;; +2597;QUADRANT LOWER RIGHT;So;0;ON;;;;;N;;;;; +2598;QUADRANT UPPER LEFT;So;0;ON;;;;;N;;;;; +2599;QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; +259A;QUADRANT UPPER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; +259B;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;; +259C;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; +259D;QUADRANT UPPER RIGHT;So;0;ON;;;;;N;;;;; +259E;QUADRANT UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;; +259F;QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;; +25A0;BLACK SQUARE;So;0;ON;;;;;N;;;;; +25A1;WHITE SQUARE;So;0;ON;;;;;N;;;;; +25A2;WHITE SQUARE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;; +25A3;WHITE SQUARE CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; +25A4;SQUARE WITH HORIZONTAL FILL;So;0;ON;;;;;N;;;;; +25A5;SQUARE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;; +25A6;SQUARE WITH ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; +25A7;SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;; +25A8;SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;; +25A9;SQUARE WITH DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; +25AA;BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; +25AB;WHITE SMALL SQUARE;So;0;ON;;;;;N;;;;; +25AC;BLACK RECTANGLE;So;0;ON;;;;;N;;;;; +25AD;WHITE RECTANGLE;So;0;ON;;;;;N;;;;; +25AE;BLACK VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;; +25AF;WHITE VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;; +25B0;BLACK PARALLELOGRAM;So;0;ON;;;;;N;;;;; +25B1;WHITE PARALLELOGRAM;So;0;ON;;;;;N;;;;; +25B2;BLACK UP-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING TRIANGLE;;;; +25B3;WHITE UP-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE;;;; +25B4;BLACK UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING SMALL TRIANGLE;;;; +25B5;WHITE UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING SMALL TRIANGLE;;;; +25B6;BLACK RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING TRIANGLE;;;; +25B7;WHITE RIGHT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE RIGHT POINTING TRIANGLE;;;; +25B8;BLACK RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING SMALL TRIANGLE;;;; +25B9;WHITE RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE RIGHT POINTING SMALL TRIANGLE;;;; +25BA;BLACK RIGHT-POINTING POINTER;So;0;ON;;;;;N;BLACK RIGHT POINTING POINTER;;;; +25BB;WHITE RIGHT-POINTING POINTER;So;0;ON;;;;;N;WHITE RIGHT POINTING POINTER;;;; +25BC;BLACK DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING TRIANGLE;;;; +25BD;WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING TRIANGLE;;;; +25BE;BLACK DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING SMALL TRIANGLE;;;; +25BF;WHITE DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING SMALL TRIANGLE;;;; +25C0;BLACK LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING TRIANGLE;;;; +25C1;WHITE LEFT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE LEFT POINTING TRIANGLE;;;; +25C2;BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING SMALL TRIANGLE;;;; +25C3;WHITE LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE LEFT POINTING SMALL TRIANGLE;;;; +25C4;BLACK LEFT-POINTING POINTER;So;0;ON;;;;;N;BLACK LEFT POINTING POINTER;;;; +25C5;WHITE LEFT-POINTING POINTER;So;0;ON;;;;;N;WHITE LEFT POINTING POINTER;;;; +25C6;BLACK DIAMOND;So;0;ON;;;;;N;;;;; +25C7;WHITE DIAMOND;So;0;ON;;;;;N;;;;; +25C8;WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;; +25C9;FISHEYE;So;0;ON;;;;;N;;;;; +25CA;LOZENGE;So;0;ON;;;;;N;;;;; +25CB;WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25CC;DOTTED CIRCLE;So;0;ON;;;;;N;;;;; +25CD;CIRCLE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;; +25CE;BULLSEYE;So;0;ON;;;;;N;;;;; +25CF;BLACK CIRCLE;So;0;ON;;;;;N;;;;; +25D0;CIRCLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; +25D1;CIRCLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; +25D2;CIRCLE WITH LOWER HALF BLACK;So;0;ON;;;;;N;;;;; +25D3;CIRCLE WITH UPPER HALF BLACK;So;0;ON;;;;;N;;;;; +25D4;CIRCLE WITH UPPER RIGHT QUADRANT BLACK;So;0;ON;;;;;N;;;;; +25D5;CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK;So;0;ON;;;;;N;;;;; +25D6;LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +25D7;RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +25D8;INVERSE BULLET;So;0;ON;;;;;N;;;;; +25D9;INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25DA;UPPER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25DB;LOWER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25DC;UPPER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25DD;UPPER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25DE;LOWER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25DF;LOWER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25E0;UPPER HALF CIRCLE;So;0;ON;;;;;N;;;;; +25E1;LOWER HALF CIRCLE;So;0;ON;;;;;N;;;;; +25E2;BLACK LOWER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +25E3;BLACK LOWER LEFT TRIANGLE;So;0;ON;;;;;N;;;;; +25E4;BLACK UPPER LEFT TRIANGLE;So;0;ON;;;;;N;;;;; +25E5;BLACK UPPER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +25E6;WHITE BULLET;So;0;ON;;;;;N;;;;; +25E7;SQUARE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; +25E8;SQUARE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; +25E9;SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; +25EA;SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; +25EB;WHITE SQUARE WITH VERTICAL BISECTING LINE;So;0;ON;;;;;N;;;;; +25EC;WHITE UP-POINTING TRIANGLE WITH DOT;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE WITH DOT;;;; +25ED;UP-POINTING TRIANGLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH LEFT HALF BLACK;;;; +25EE;UP-POINTING TRIANGLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH RIGHT HALF BLACK;;;; +25EF;LARGE CIRCLE;So;0;ON;;;;;N;;;;; +25F0;WHITE SQUARE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F1;WHITE SQUARE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F2;WHITE SQUARE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F3;WHITE SQUARE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F4;WHITE CIRCLE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F5;WHITE CIRCLE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F6;WHITE CIRCLE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F7;WHITE CIRCLE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F8;UPPER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;; +25F9;UPPER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;; +25FA;LOWER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;; +25FB;WHITE MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;; +25FC;BLACK MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;; +25FD;WHITE MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;; +25FE;BLACK MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;; +25FF;LOWER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;; +2600;BLACK SUN WITH RAYS;So;0;ON;;;;;N;;;;; +2601;CLOUD;So;0;ON;;;;;N;;;;; +2602;UMBRELLA;So;0;ON;;;;;N;;;;; +2603;SNOWMAN;So;0;ON;;;;;N;;;;; +2604;COMET;So;0;ON;;;;;N;;;;; +2605;BLACK STAR;So;0;ON;;;;;N;;;;; +2606;WHITE STAR;So;0;ON;;;;;N;;;;; +2607;LIGHTNING;So;0;ON;;;;;N;;;;; +2608;THUNDERSTORM;So;0;ON;;;;;N;;;;; +2609;SUN;So;0;ON;;;;;N;;;;; +260A;ASCENDING NODE;So;0;ON;;;;;N;;;;; +260B;DESCENDING NODE;So;0;ON;;;;;N;;;;; +260C;CONJUNCTION;So;0;ON;;;;;N;;;;; +260D;OPPOSITION;So;0;ON;;;;;N;;;;; +260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;; +260F;WHITE TELEPHONE;So;0;ON;;;;;N;;;;; +2610;BALLOT BOX;So;0;ON;;;;;N;;;;; +2611;BALLOT BOX WITH CHECK;So;0;ON;;;;;N;;;;; +2612;BALLOT BOX WITH X;So;0;ON;;;;;N;;;;; +2613;SALTIRE;So;0;ON;;;;;N;;;;; +2614;UMBRELLA WITH RAIN DROPS;So;0;ON;;;;;N;;;;; +2615;HOT BEVERAGE;So;0;ON;;;;;N;;;;; +2616;WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;; +2617;BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;; +2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; +261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; +261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +261C;WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; +261D;WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;; +261E;WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +261F;WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; +2620;SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;; +2621;CAUTION SIGN;So;0;ON;;;;;N;;;;; +2622;RADIOACTIVE SIGN;So;0;ON;;;;;N;;;;; +2623;BIOHAZARD SIGN;So;0;ON;;;;;N;;;;; +2624;CADUCEUS;So;0;ON;;;;;N;;;;; +2625;ANKH;So;0;ON;;;;;N;;;;; +2626;ORTHODOX CROSS;So;0;ON;;;;;N;;;;; +2627;CHI RHO;So;0;ON;;;;;N;;;;; +2628;CROSS OF LORRAINE;So;0;ON;;;;;N;;;;; +2629;CROSS OF JERUSALEM;So;0;ON;;;;;N;;;;; +262A;STAR AND CRESCENT;So;0;ON;;;;;N;;;;; +262B;FARSI SYMBOL;So;0;ON;;;;;N;SYMBOL OF IRAN;;;; +262C;ADI SHAKTI;So;0;ON;;;;;N;;;;; +262D;HAMMER AND SICKLE;So;0;ON;;;;;N;;;;; +262E;PEACE SYMBOL;So;0;ON;;;;;N;;;;; +262F;YIN YANG;So;0;ON;;;;;N;;;;; +2630;TRIGRAM FOR HEAVEN;So;0;ON;;;;;N;;;;; +2631;TRIGRAM FOR LAKE;So;0;ON;;;;;N;;;;; +2632;TRIGRAM FOR FIRE;So;0;ON;;;;;N;;;;; +2633;TRIGRAM FOR THUNDER;So;0;ON;;;;;N;;;;; +2634;TRIGRAM FOR WIND;So;0;ON;;;;;N;;;;; +2635;TRIGRAM FOR WATER;So;0;ON;;;;;N;;;;; +2636;TRIGRAM FOR MOUNTAIN;So;0;ON;;;;;N;;;;; +2637;TRIGRAM FOR EARTH;So;0;ON;;;;;N;;;;; +2638;WHEEL OF DHARMA;So;0;ON;;;;;N;;;;; +2639;WHITE FROWNING FACE;So;0;ON;;;;;N;;;;; +263A;WHITE SMILING FACE;So;0;ON;;;;;N;;;;; +263B;BLACK SMILING FACE;So;0;ON;;;;;N;;;;; +263C;WHITE SUN WITH RAYS;So;0;ON;;;;;N;;;;; +263D;FIRST QUARTER MOON;So;0;ON;;;;;N;;;;; +263E;LAST QUARTER MOON;So;0;ON;;;;;N;;;;; +263F;MERCURY;So;0;ON;;;;;N;;;;; +2640;FEMALE SIGN;So;0;ON;;;;;N;;;;; +2641;EARTH;So;0;ON;;;;;N;;;;; +2642;MALE SIGN;So;0;ON;;;;;N;;;;; +2643;JUPITER;So;0;ON;;;;;N;;;;; +2644;SATURN;So;0;ON;;;;;N;;;;; +2645;URANUS;So;0;ON;;;;;N;;;;; +2646;NEPTUNE;So;0;ON;;;;;N;;;;; +2647;PLUTO;So;0;ON;;;;;N;;;;; +2648;ARIES;So;0;ON;;;;;N;;;;; +2649;TAURUS;So;0;ON;;;;;N;;;;; +264A;GEMINI;So;0;ON;;;;;N;;;;; +264B;CANCER;So;0;ON;;;;;N;;;;; +264C;LEO;So;0;ON;;;;;N;;;;; +264D;VIRGO;So;0;ON;;;;;N;;;;; +264E;LIBRA;So;0;ON;;;;;N;;;;; +264F;SCORPIUS;So;0;ON;;;;;N;;;;; +2650;SAGITTARIUS;So;0;ON;;;;;N;;;;; +2651;CAPRICORN;So;0;ON;;;;;N;;;;; +2652;AQUARIUS;So;0;ON;;;;;N;;;;; +2653;PISCES;So;0;ON;;;;;N;;;;; +2654;WHITE CHESS KING;So;0;ON;;;;;N;;;;; +2655;WHITE CHESS QUEEN;So;0;ON;;;;;N;;;;; +2656;WHITE CHESS ROOK;So;0;ON;;;;;N;;;;; +2657;WHITE CHESS BISHOP;So;0;ON;;;;;N;;;;; +2658;WHITE CHESS KNIGHT;So;0;ON;;;;;N;;;;; +2659;WHITE CHESS PAWN;So;0;ON;;;;;N;;;;; +265A;BLACK CHESS KING;So;0;ON;;;;;N;;;;; +265B;BLACK CHESS QUEEN;So;0;ON;;;;;N;;;;; +265C;BLACK CHESS ROOK;So;0;ON;;;;;N;;;;; +265D;BLACK CHESS BISHOP;So;0;ON;;;;;N;;;;; +265E;BLACK CHESS KNIGHT;So;0;ON;;;;;N;;;;; +265F;BLACK CHESS PAWN;So;0;ON;;;;;N;;;;; +2660;BLACK SPADE SUIT;So;0;ON;;;;;N;;;;; +2661;WHITE HEART SUIT;So;0;ON;;;;;N;;;;; +2662;WHITE DIAMOND SUIT;So;0;ON;;;;;N;;;;; +2663;BLACK CLUB SUIT;So;0;ON;;;;;N;;;;; +2664;WHITE SPADE SUIT;So;0;ON;;;;;N;;;;; +2665;BLACK HEART SUIT;So;0;ON;;;;;N;;;;; +2666;BLACK DIAMOND SUIT;So;0;ON;;;;;N;;;;; +2667;WHITE CLUB SUIT;So;0;ON;;;;;N;;;;; +2668;HOT SPRINGS;So;0;ON;;;;;N;;;;; +2669;QUARTER NOTE;So;0;ON;;;;;N;;;;; +266A;EIGHTH NOTE;So;0;ON;;;;;N;;;;; +266B;BEAMED EIGHTH NOTES;So;0;ON;;;;;N;BARRED EIGHTH NOTES;;;; +266C;BEAMED SIXTEENTH NOTES;So;0;ON;;;;;N;BARRED SIXTEENTH NOTES;;;; +266D;MUSIC FLAT SIGN;So;0;ON;;;;;N;FLAT;;;; +266E;MUSIC NATURAL SIGN;So;0;ON;;;;;N;NATURAL;;;; +266F;MUSIC SHARP SIGN;Sm;0;ON;;;;;N;SHARP;;;; +2670;WEST SYRIAC CROSS;So;0;ON;;;;;N;;;;; +2671;EAST SYRIAC CROSS;So;0;ON;;;;;N;;;;; +2672;UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;; +2673;RECYCLING SYMBOL FOR TYPE-1 PLASTICS;So;0;ON;;;;;N;;pete;;; +2674;RECYCLING SYMBOL FOR TYPE-2 PLASTICS;So;0;ON;;;;;N;;hdpe;;; +2675;RECYCLING SYMBOL FOR TYPE-3 PLASTICS;So;0;ON;;;;;N;;pvc;;; +2676;RECYCLING SYMBOL FOR TYPE-4 PLASTICS;So;0;ON;;;;;N;;ldpe;;; +2677;RECYCLING SYMBOL FOR TYPE-5 PLASTICS;So;0;ON;;;;;N;;pp;;; +2678;RECYCLING SYMBOL FOR TYPE-6 PLASTICS;So;0;ON;;;;;N;;ps;;; +2679;RECYCLING SYMBOL FOR TYPE-7 PLASTICS;So;0;ON;;;;;N;;other;;; +267A;RECYCLING SYMBOL FOR GENERIC MATERIALS;So;0;ON;;;;;N;;;;; +267B;BLACK UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;; +267C;RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;; +267D;PARTIALLY-RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;; +2680;DIE FACE-1;So;0;ON;;;;;N;;;;; +2681;DIE FACE-2;So;0;ON;;;;;N;;;;; +2682;DIE FACE-3;So;0;ON;;;;;N;;;;; +2683;DIE FACE-4;So;0;ON;;;;;N;;;;; +2684;DIE FACE-5;So;0;ON;;;;;N;;;;; +2685;DIE FACE-6;So;0;ON;;;;;N;;;;; +2686;WHITE CIRCLE WITH DOT RIGHT;So;0;ON;;;;;N;;;;; +2687;WHITE CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;; +2688;BLACK CIRCLE WITH WHITE DOT RIGHT;So;0;ON;;;;;N;;;;; +2689;BLACK CIRCLE WITH TWO WHITE DOTS;So;0;ON;;;;;N;;;;; +268A;MONOGRAM FOR YANG;So;0;ON;;;;;N;;;;; +268B;MONOGRAM FOR YIN;So;0;ON;;;;;N;;;;; +268C;DIGRAM FOR GREATER YANG;So;0;ON;;;;;N;;;;; +268D;DIGRAM FOR LESSER YIN;So;0;ON;;;;;N;;;;; +268E;DIGRAM FOR LESSER YANG;So;0;ON;;;;;N;;;;; +268F;DIGRAM FOR GREATER YIN;So;0;ON;;;;;N;;;;; +2690;WHITE FLAG;So;0;ON;;;;;N;;;;; +2691;BLACK FLAG;So;0;ON;;;;;N;;;;; +26A0;WARNING SIGN;So;0;ON;;;;;N;;;;; +26A1;HIGH VOLTAGE SIGN;So;0;ON;;;;;N;;;;; +2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;; +2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;; +2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;; +2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;; +2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;; +2707;TAPE DRIVE;So;0;ON;;;;;N;;;;; +2708;AIRPLANE;So;0;ON;;;;;N;;;;; +2709;ENVELOPE;So;0;ON;;;;;N;;;;; +270C;VICTORY HAND;So;0;ON;;;;;N;;;;; +270D;WRITING HAND;So;0;ON;;;;;N;;;;; +270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;; +270F;PENCIL;So;0;ON;;;;;N;;;;; +2710;UPPER RIGHT PENCIL;So;0;ON;;;;;N;;;;; +2711;WHITE NIB;So;0;ON;;;;;N;;;;; +2712;BLACK NIB;So;0;ON;;;;;N;;;;; +2713;CHECK MARK;So;0;ON;;;;;N;;;;; +2714;HEAVY CHECK MARK;So;0;ON;;;;;N;;;;; +2715;MULTIPLICATION X;So;0;ON;;;;;N;;;;; +2716;HEAVY MULTIPLICATION X;So;0;ON;;;;;N;;;;; +2717;BALLOT X;So;0;ON;;;;;N;;;;; +2718;HEAVY BALLOT X;So;0;ON;;;;;N;;;;; +2719;OUTLINED GREEK CROSS;So;0;ON;;;;;N;;;;; +271A;HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; +271B;OPEN CENTRE CROSS;So;0;ON;;;;;N;OPEN CENTER CROSS;;;; +271C;HEAVY OPEN CENTRE CROSS;So;0;ON;;;;;N;HEAVY OPEN CENTER CROSS;;;; +271D;LATIN CROSS;So;0;ON;;;;;N;;;;; +271E;SHADOWED WHITE LATIN CROSS;So;0;ON;;;;;N;;;;; +271F;OUTLINED LATIN CROSS;So;0;ON;;;;;N;;;;; +2720;MALTESE CROSS;So;0;ON;;;;;N;;;;; +2721;STAR OF DAVID;So;0;ON;;;;;N;;;;; +2722;FOUR TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2723;FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2724;HEAVY FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;; +2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;; +2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;; +272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;; +272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;; +272C;BLACK CENTRE WHITE STAR;So;0;ON;;;;;N;BLACK CENTER WHITE STAR;;;; +272D;OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;; +272E;HEAVY OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;; +272F;PINWHEEL STAR;So;0;ON;;;;;N;;;;; +2730;SHADOWED WHITE STAR;So;0;ON;;;;;N;;;;; +2731;HEAVY ASTERISK;So;0;ON;;;;;N;;;;; +2732;OPEN CENTRE ASTERISK;So;0;ON;;;;;N;OPEN CENTER ASTERISK;;;; +2733;EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2734;EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +2735;EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +2736;SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +2737;EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;; +2738;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;; +2739;TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +273A;SIXTEEN POINTED ASTERISK;So;0;ON;;;;;N;;;;; +273B;TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +273C;OPEN CENTRE TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;OPEN CENTER TEARDROP-SPOKED ASTERISK;;;; +273D;HEAVY TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +273E;SIX PETALLED BLACK AND WHITE FLORETTE;So;0;ON;;;;;N;;;;; +273F;BLACK FLORETTE;So;0;ON;;;;;N;;;;; +2740;WHITE FLORETTE;So;0;ON;;;;;N;;;;; +2741;EIGHT PETALLED OUTLINED BLACK FLORETTE;So;0;ON;;;;;N;;;;; +2742;CIRCLED OPEN CENTRE EIGHT POINTED STAR;So;0;ON;;;;;N;CIRCLED OPEN CENTER EIGHT POINTED STAR;;;; +2743;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK;So;0;ON;;;;;N;;;;; +2744;SNOWFLAKE;So;0;ON;;;;;N;;;;; +2745;TIGHT TRIFOLIATE SNOWFLAKE;So;0;ON;;;;;N;;;;; +2746;HEAVY CHEVRON SNOWFLAKE;So;0;ON;;;;;N;;;;; +2747;SPARKLE;So;0;ON;;;;;N;;;;; +2748;HEAVY SPARKLE;So;0;ON;;;;;N;;;;; +2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; +274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; +274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; +274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;; +2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;; +2759;MEDIUM VERTICAL BAR;So;0;ON;;;;;N;;;;; +275A;HEAVY VERTICAL BAR;So;0;ON;;;;;N;;;;; +275B;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;; +2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2764;HEAVY BLACK HEART;So;0;ON;;;;;N;;;;; +2765;ROTATED HEAVY BLACK HEART BULLET;So;0;ON;;;;;N;;;;; +2766;FLORAL HEART;So;0;ON;;;;;N;;;;; +2767;ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; +2768;MEDIUM LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;; +2769;MEDIUM RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;; +276A;MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;; +276B;MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;; +276C;MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; +276D;MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; +276E;HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT;Ps;0;ON;;;;;Y;;;;; +276F;HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT;Pe;0;ON;;;;;Y;;;;; +2770;HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; +2771;HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; +2772;LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; +2773;LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; +2774;MEDIUM LEFT CURLY BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;; +2775;MEDIUM RIGHT CURLY BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;; +2776;DINGBAT NEGATIVE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED DIGIT ONE;;;; +2777;DINGBAT NEGATIVE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED DIGIT TWO;;;; +2778;DINGBAT NEGATIVE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED DIGIT THREE;;;; +2779;DINGBAT NEGATIVE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED DIGIT FOUR;;;; +277A;DINGBAT NEGATIVE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED DIGIT FIVE;;;; +277B;DINGBAT NEGATIVE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED DIGIT SIX;;;; +277C;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED DIGIT SEVEN;;;; +277D;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED DIGIT EIGHT;;;; +277E;DINGBAT NEGATIVE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED DIGIT NINE;;;; +277F;DINGBAT NEGATIVE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED NUMBER TEN;;;; +2780;DINGBAT CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;CIRCLED SANS-SERIF DIGIT ONE;;;; +2781;DINGBAT CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;CIRCLED SANS-SERIF DIGIT TWO;;;; +2782;DINGBAT CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;CIRCLED SANS-SERIF DIGIT THREE;;;; +2783;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;CIRCLED SANS-SERIF DIGIT FOUR;;;; +2784;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;CIRCLED SANS-SERIF DIGIT FIVE;;;; +2785;DINGBAT CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;CIRCLED SANS-SERIF DIGIT SIX;;;; +2786;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;CIRCLED SANS-SERIF DIGIT SEVEN;;;; +2787;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;CIRCLED SANS-SERIF DIGIT EIGHT;;;; +2788;DINGBAT CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;CIRCLED SANS-SERIF DIGIT NINE;;;; +2789;DINGBAT CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;CIRCLED SANS-SERIF NUMBER TEN;;;; +278A;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED SANS-SERIF DIGIT ONE;;;; +278B;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED SANS-SERIF DIGIT TWO;;;; +278C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED SANS-SERIF DIGIT THREE;;;; +278D;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED SANS-SERIF DIGIT FOUR;;;; +278E;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED SANS-SERIF DIGIT FIVE;;;; +278F;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED SANS-SERIF DIGIT SIX;;;; +2790;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED SANS-SERIF DIGIT SEVEN;;;; +2791;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED SANS-SERIF DIGIT EIGHT;;;; +2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;; +2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;; +2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;; +2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;; +2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;; +279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;; +279B;DRAFTING POINT RIGHTWARDS ARROW;So;0;ON;;;;;N;DRAFTING POINT RIGHT ARROW;;;; +279C;HEAVY ROUND-TIPPED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY ROUND-TIPPED RIGHT ARROW;;;; +279D;TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;TRIANGLE-HEADED RIGHT ARROW;;;; +279E;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TRIANGLE-HEADED RIGHT ARROW;;;; +279F;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;DASHED TRIANGLE-HEADED RIGHT ARROW;;;; +27A0;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY DASHED TRIANGLE-HEADED RIGHT ARROW;;;; +27A1;BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK RIGHT ARROW;;;; +27A2;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D TOP-LIGHTED RIGHT ARROWHEAD;;;; +27A3;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D BOTTOM-LIGHTED RIGHT ARROWHEAD;;;; +27A4;BLACK RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;BLACK RIGHT ARROWHEAD;;;; +27A5;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED DOWN AND RIGHT ARROW;;;; +27A6;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED UP AND RIGHT ARROW;;;; +27A7;SQUAT BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;SQUAT BLACK RIGHT ARROW;;;; +27A8;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY CONCAVE-POINTED BLACK RIGHT ARROW;;;; +27A9;RIGHT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;RIGHT-SHADED WHITE RIGHT ARROW;;;; +27AA;LEFT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT-SHADED WHITE RIGHT ARROW;;;; +27AB;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;BACK-TILTED SHADOWED WHITE RIGHT ARROW;;;; +27AC;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;FRONT-TILTED SHADOWED WHITE RIGHT ARROW;;;; +27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;; +27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;; +27B4;BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED LOWER RIGHT ARROW;;;; +27B5;BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK-FEATHERED RIGHT ARROW;;;; +27B6;BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED UPPER RIGHT ARROW;;;; +27B7;HEAVY BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED LOWER RIGHT ARROW;;;; +27B8;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED RIGHT ARROW;;;; +27B9;HEAVY BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED UPPER RIGHT ARROW;;;; +27BA;TEARDROP-BARBED RIGHTWARDS ARROW;So;0;ON;;;;;N;TEARDROP-BARBED RIGHT ARROW;;;; +27BB;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TEARDROP-SHANKED RIGHT ARROW;;;; +27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;; +27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;; +27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;; +27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;; +27D1;AND WITH DOT;Sm;0;ON;;;;;N;;;;; +27D2;ELEMENT OF OPENING UPWARDS;Sm;0;ON;;;;;N;;;;; +27D3;LOWER RIGHT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;; +27D4;UPPER LEFT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;; +27D5;LEFT OUTER JOIN;Sm;0;ON;;;;;Y;;;;; +27D6;RIGHT OUTER JOIN;Sm;0;ON;;;;;Y;;;;; +27D7;FULL OUTER JOIN;Sm;0;ON;;;;;N;;;;; +27D8;LARGE UP TACK;Sm;0;ON;;;;;N;;;;; +27D9;LARGE DOWN TACK;Sm;0;ON;;;;;N;;;;; +27DA;LEFT AND RIGHT DOUBLE TURNSTILE;Sm;0;ON;;;;;N;;;;; +27DB;LEFT AND RIGHT TACK;Sm;0;ON;;;;;N;;;;; +27DC;LEFT MULTIMAP;Sm;0;ON;;;;;Y;;;;; +27DD;LONG RIGHT TACK;Sm;0;ON;;;;;Y;;;;; +27DE;LONG LEFT TACK;Sm;0;ON;;;;;Y;;;;; +27DF;UP TACK WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; +27E0;LOZENGE DIVIDED BY HORIZONTAL RULE;Sm;0;ON;;;;;N;;;;; +27E1;WHITE CONCAVE-SIDED DIAMOND;Sm;0;ON;;;;;N;;;;; +27E2;WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;; +27E3;WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;; +27E4;WHITE SQUARE WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;; +27E5;WHITE SQUARE WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;; +27E6;MATHEMATICAL LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;;;;; +27E7;MATHEMATICAL RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;;;;; +27E8;MATHEMATICAL LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; +27E9;MATHEMATICAL RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; +27EA;MATHEMATICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; +27EB;MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; +27F0;UPWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;; +27F1;DOWNWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;; +27F2;ANTICLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; +27F3;CLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; +27F4;RIGHT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; +27F5;LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +27F6;LONG RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +27F7;LONG LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;; +27F8;LONG LEFTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; +27F9;LONG RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; +27FA;LONG LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; +27FB;LONG LEFTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +27FC;LONG RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +27FD;LONG LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +27FE;LONG RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +27FF;LONG RIGHTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;; +2800;BRAILLE PATTERN BLANK;So;0;ON;;;;;N;;;;; +2801;BRAILLE PATTERN DOTS-1;So;0;ON;;;;;N;;;;; +2802;BRAILLE PATTERN DOTS-2;So;0;ON;;;;;N;;;;; +2803;BRAILLE PATTERN DOTS-12;So;0;ON;;;;;N;;;;; +2804;BRAILLE PATTERN DOTS-3;So;0;ON;;;;;N;;;;; +2805;BRAILLE PATTERN DOTS-13;So;0;ON;;;;;N;;;;; +2806;BRAILLE PATTERN DOTS-23;So;0;ON;;;;;N;;;;; +2807;BRAILLE PATTERN DOTS-123;So;0;ON;;;;;N;;;;; +2808;BRAILLE PATTERN DOTS-4;So;0;ON;;;;;N;;;;; +2809;BRAILLE PATTERN DOTS-14;So;0;ON;;;;;N;;;;; +280A;BRAILLE PATTERN DOTS-24;So;0;ON;;;;;N;;;;; +280B;BRAILLE PATTERN DOTS-124;So;0;ON;;;;;N;;;;; +280C;BRAILLE PATTERN DOTS-34;So;0;ON;;;;;N;;;;; +280D;BRAILLE PATTERN DOTS-134;So;0;ON;;;;;N;;;;; +280E;BRAILLE PATTERN DOTS-234;So;0;ON;;;;;N;;;;; +280F;BRAILLE PATTERN DOTS-1234;So;0;ON;;;;;N;;;;; +2810;BRAILLE PATTERN DOTS-5;So;0;ON;;;;;N;;;;; +2811;BRAILLE PATTERN DOTS-15;So;0;ON;;;;;N;;;;; +2812;BRAILLE PATTERN DOTS-25;So;0;ON;;;;;N;;;;; +2813;BRAILLE PATTERN DOTS-125;So;0;ON;;;;;N;;;;; +2814;BRAILLE PATTERN DOTS-35;So;0;ON;;;;;N;;;;; +2815;BRAILLE PATTERN DOTS-135;So;0;ON;;;;;N;;;;; +2816;BRAILLE PATTERN DOTS-235;So;0;ON;;;;;N;;;;; +2817;BRAILLE PATTERN DOTS-1235;So;0;ON;;;;;N;;;;; +2818;BRAILLE PATTERN DOTS-45;So;0;ON;;;;;N;;;;; +2819;BRAILLE PATTERN DOTS-145;So;0;ON;;;;;N;;;;; +281A;BRAILLE PATTERN DOTS-245;So;0;ON;;;;;N;;;;; +281B;BRAILLE PATTERN DOTS-1245;So;0;ON;;;;;N;;;;; +281C;BRAILLE PATTERN DOTS-345;So;0;ON;;;;;N;;;;; +281D;BRAILLE PATTERN DOTS-1345;So;0;ON;;;;;N;;;;; +281E;BRAILLE PATTERN DOTS-2345;So;0;ON;;;;;N;;;;; +281F;BRAILLE PATTERN DOTS-12345;So;0;ON;;;;;N;;;;; +2820;BRAILLE PATTERN DOTS-6;So;0;ON;;;;;N;;;;; +2821;BRAILLE PATTERN DOTS-16;So;0;ON;;;;;N;;;;; +2822;BRAILLE PATTERN DOTS-26;So;0;ON;;;;;N;;;;; +2823;BRAILLE PATTERN DOTS-126;So;0;ON;;;;;N;;;;; +2824;BRAILLE PATTERN DOTS-36;So;0;ON;;;;;N;;;;; +2825;BRAILLE PATTERN DOTS-136;So;0;ON;;;;;N;;;;; +2826;BRAILLE PATTERN DOTS-236;So;0;ON;;;;;N;;;;; +2827;BRAILLE PATTERN DOTS-1236;So;0;ON;;;;;N;;;;; +2828;BRAILLE PATTERN DOTS-46;So;0;ON;;;;;N;;;;; +2829;BRAILLE PATTERN DOTS-146;So;0;ON;;;;;N;;;;; +282A;BRAILLE PATTERN DOTS-246;So;0;ON;;;;;N;;;;; +282B;BRAILLE PATTERN DOTS-1246;So;0;ON;;;;;N;;;;; +282C;BRAILLE PATTERN DOTS-346;So;0;ON;;;;;N;;;;; +282D;BRAILLE PATTERN DOTS-1346;So;0;ON;;;;;N;;;;; +282E;BRAILLE PATTERN DOTS-2346;So;0;ON;;;;;N;;;;; +282F;BRAILLE PATTERN DOTS-12346;So;0;ON;;;;;N;;;;; +2830;BRAILLE PATTERN DOTS-56;So;0;ON;;;;;N;;;;; +2831;BRAILLE PATTERN DOTS-156;So;0;ON;;;;;N;;;;; +2832;BRAILLE PATTERN DOTS-256;So;0;ON;;;;;N;;;;; +2833;BRAILLE PATTERN DOTS-1256;So;0;ON;;;;;N;;;;; +2834;BRAILLE PATTERN DOTS-356;So;0;ON;;;;;N;;;;; +2835;BRAILLE PATTERN DOTS-1356;So;0;ON;;;;;N;;;;; +2836;BRAILLE PATTERN DOTS-2356;So;0;ON;;;;;N;;;;; +2837;BRAILLE PATTERN DOTS-12356;So;0;ON;;;;;N;;;;; +2838;BRAILLE PATTERN DOTS-456;So;0;ON;;;;;N;;;;; +2839;BRAILLE PATTERN DOTS-1456;So;0;ON;;;;;N;;;;; +283A;BRAILLE PATTERN DOTS-2456;So;0;ON;;;;;N;;;;; +283B;BRAILLE PATTERN DOTS-12456;So;0;ON;;;;;N;;;;; +283C;BRAILLE PATTERN DOTS-3456;So;0;ON;;;;;N;;;;; +283D;BRAILLE PATTERN DOTS-13456;So;0;ON;;;;;N;;;;; +283E;BRAILLE PATTERN DOTS-23456;So;0;ON;;;;;N;;;;; +283F;BRAILLE PATTERN DOTS-123456;So;0;ON;;;;;N;;;;; +2840;BRAILLE PATTERN DOTS-7;So;0;ON;;;;;N;;;;; +2841;BRAILLE PATTERN DOTS-17;So;0;ON;;;;;N;;;;; +2842;BRAILLE PATTERN DOTS-27;So;0;ON;;;;;N;;;;; +2843;BRAILLE PATTERN DOTS-127;So;0;ON;;;;;N;;;;; +2844;BRAILLE PATTERN DOTS-37;So;0;ON;;;;;N;;;;; +2845;BRAILLE PATTERN DOTS-137;So;0;ON;;;;;N;;;;; +2846;BRAILLE PATTERN DOTS-237;So;0;ON;;;;;N;;;;; +2847;BRAILLE PATTERN DOTS-1237;So;0;ON;;;;;N;;;;; +2848;BRAILLE PATTERN DOTS-47;So;0;ON;;;;;N;;;;; +2849;BRAILLE PATTERN DOTS-147;So;0;ON;;;;;N;;;;; +284A;BRAILLE PATTERN DOTS-247;So;0;ON;;;;;N;;;;; +284B;BRAILLE PATTERN DOTS-1247;So;0;ON;;;;;N;;;;; +284C;BRAILLE PATTERN DOTS-347;So;0;ON;;;;;N;;;;; +284D;BRAILLE PATTERN DOTS-1347;So;0;ON;;;;;N;;;;; +284E;BRAILLE PATTERN DOTS-2347;So;0;ON;;;;;N;;;;; +284F;BRAILLE PATTERN DOTS-12347;So;0;ON;;;;;N;;;;; +2850;BRAILLE PATTERN DOTS-57;So;0;ON;;;;;N;;;;; +2851;BRAILLE PATTERN DOTS-157;So;0;ON;;;;;N;;;;; +2852;BRAILLE PATTERN DOTS-257;So;0;ON;;;;;N;;;;; +2853;BRAILLE PATTERN DOTS-1257;So;0;ON;;;;;N;;;;; +2854;BRAILLE PATTERN DOTS-357;So;0;ON;;;;;N;;;;; +2855;BRAILLE PATTERN DOTS-1357;So;0;ON;;;;;N;;;;; +2856;BRAILLE PATTERN DOTS-2357;So;0;ON;;;;;N;;;;; +2857;BRAILLE PATTERN DOTS-12357;So;0;ON;;;;;N;;;;; +2858;BRAILLE PATTERN DOTS-457;So;0;ON;;;;;N;;;;; +2859;BRAILLE PATTERN DOTS-1457;So;0;ON;;;;;N;;;;; +285A;BRAILLE PATTERN DOTS-2457;So;0;ON;;;;;N;;;;; +285B;BRAILLE PATTERN DOTS-12457;So;0;ON;;;;;N;;;;; +285C;BRAILLE PATTERN DOTS-3457;So;0;ON;;;;;N;;;;; +285D;BRAILLE PATTERN DOTS-13457;So;0;ON;;;;;N;;;;; +285E;BRAILLE PATTERN DOTS-23457;So;0;ON;;;;;N;;;;; +285F;BRAILLE PATTERN DOTS-123457;So;0;ON;;;;;N;;;;; +2860;BRAILLE PATTERN DOTS-67;So;0;ON;;;;;N;;;;; +2861;BRAILLE PATTERN DOTS-167;So;0;ON;;;;;N;;;;; +2862;BRAILLE PATTERN DOTS-267;So;0;ON;;;;;N;;;;; +2863;BRAILLE PATTERN DOTS-1267;So;0;ON;;;;;N;;;;; +2864;BRAILLE PATTERN DOTS-367;So;0;ON;;;;;N;;;;; +2865;BRAILLE PATTERN DOTS-1367;So;0;ON;;;;;N;;;;; +2866;BRAILLE PATTERN DOTS-2367;So;0;ON;;;;;N;;;;; +2867;BRAILLE PATTERN DOTS-12367;So;0;ON;;;;;N;;;;; +2868;BRAILLE PATTERN DOTS-467;So;0;ON;;;;;N;;;;; +2869;BRAILLE PATTERN DOTS-1467;So;0;ON;;;;;N;;;;; +286A;BRAILLE PATTERN DOTS-2467;So;0;ON;;;;;N;;;;; +286B;BRAILLE PATTERN DOTS-12467;So;0;ON;;;;;N;;;;; +286C;BRAILLE PATTERN DOTS-3467;So;0;ON;;;;;N;;;;; +286D;BRAILLE PATTERN DOTS-13467;So;0;ON;;;;;N;;;;; +286E;BRAILLE PATTERN DOTS-23467;So;0;ON;;;;;N;;;;; +286F;BRAILLE PATTERN DOTS-123467;So;0;ON;;;;;N;;;;; +2870;BRAILLE PATTERN DOTS-567;So;0;ON;;;;;N;;;;; +2871;BRAILLE PATTERN DOTS-1567;So;0;ON;;;;;N;;;;; +2872;BRAILLE PATTERN DOTS-2567;So;0;ON;;;;;N;;;;; +2873;BRAILLE PATTERN DOTS-12567;So;0;ON;;;;;N;;;;; +2874;BRAILLE PATTERN DOTS-3567;So;0;ON;;;;;N;;;;; +2875;BRAILLE PATTERN DOTS-13567;So;0;ON;;;;;N;;;;; +2876;BRAILLE PATTERN DOTS-23567;So;0;ON;;;;;N;;;;; +2877;BRAILLE PATTERN DOTS-123567;So;0;ON;;;;;N;;;;; +2878;BRAILLE PATTERN DOTS-4567;So;0;ON;;;;;N;;;;; +2879;BRAILLE PATTERN DOTS-14567;So;0;ON;;;;;N;;;;; +287A;BRAILLE PATTERN DOTS-24567;So;0;ON;;;;;N;;;;; +287B;BRAILLE PATTERN DOTS-124567;So;0;ON;;;;;N;;;;; +287C;BRAILLE PATTERN DOTS-34567;So;0;ON;;;;;N;;;;; +287D;BRAILLE PATTERN DOTS-134567;So;0;ON;;;;;N;;;;; +287E;BRAILLE PATTERN DOTS-234567;So;0;ON;;;;;N;;;;; +287F;BRAILLE PATTERN DOTS-1234567;So;0;ON;;;;;N;;;;; +2880;BRAILLE PATTERN DOTS-8;So;0;ON;;;;;N;;;;; +2881;BRAILLE PATTERN DOTS-18;So;0;ON;;;;;N;;;;; +2882;BRAILLE PATTERN DOTS-28;So;0;ON;;;;;N;;;;; +2883;BRAILLE PATTERN DOTS-128;So;0;ON;;;;;N;;;;; +2884;BRAILLE PATTERN DOTS-38;So;0;ON;;;;;N;;;;; +2885;BRAILLE PATTERN DOTS-138;So;0;ON;;;;;N;;;;; +2886;BRAILLE PATTERN DOTS-238;So;0;ON;;;;;N;;;;; +2887;BRAILLE PATTERN DOTS-1238;So;0;ON;;;;;N;;;;; +2888;BRAILLE PATTERN DOTS-48;So;0;ON;;;;;N;;;;; +2889;BRAILLE PATTERN DOTS-148;So;0;ON;;;;;N;;;;; +288A;BRAILLE PATTERN DOTS-248;So;0;ON;;;;;N;;;;; +288B;BRAILLE PATTERN DOTS-1248;So;0;ON;;;;;N;;;;; +288C;BRAILLE PATTERN DOTS-348;So;0;ON;;;;;N;;;;; +288D;BRAILLE PATTERN DOTS-1348;So;0;ON;;;;;N;;;;; +288E;BRAILLE PATTERN DOTS-2348;So;0;ON;;;;;N;;;;; +288F;BRAILLE PATTERN DOTS-12348;So;0;ON;;;;;N;;;;; +2890;BRAILLE PATTERN DOTS-58;So;0;ON;;;;;N;;;;; +2891;BRAILLE PATTERN DOTS-158;So;0;ON;;;;;N;;;;; +2892;BRAILLE PATTERN DOTS-258;So;0;ON;;;;;N;;;;; +2893;BRAILLE PATTERN DOTS-1258;So;0;ON;;;;;N;;;;; +2894;BRAILLE PATTERN DOTS-358;So;0;ON;;;;;N;;;;; +2895;BRAILLE PATTERN DOTS-1358;So;0;ON;;;;;N;;;;; +2896;BRAILLE PATTERN DOTS-2358;So;0;ON;;;;;N;;;;; +2897;BRAILLE PATTERN DOTS-12358;So;0;ON;;;;;N;;;;; +2898;BRAILLE PATTERN DOTS-458;So;0;ON;;;;;N;;;;; +2899;BRAILLE PATTERN DOTS-1458;So;0;ON;;;;;N;;;;; +289A;BRAILLE PATTERN DOTS-2458;So;0;ON;;;;;N;;;;; +289B;BRAILLE PATTERN DOTS-12458;So;0;ON;;;;;N;;;;; +289C;BRAILLE PATTERN DOTS-3458;So;0;ON;;;;;N;;;;; +289D;BRAILLE PATTERN DOTS-13458;So;0;ON;;;;;N;;;;; +289E;BRAILLE PATTERN DOTS-23458;So;0;ON;;;;;N;;;;; +289F;BRAILLE PATTERN DOTS-123458;So;0;ON;;;;;N;;;;; +28A0;BRAILLE PATTERN DOTS-68;So;0;ON;;;;;N;;;;; +28A1;BRAILLE PATTERN DOTS-168;So;0;ON;;;;;N;;;;; +28A2;BRAILLE PATTERN DOTS-268;So;0;ON;;;;;N;;;;; +28A3;BRAILLE PATTERN DOTS-1268;So;0;ON;;;;;N;;;;; +28A4;BRAILLE PATTERN DOTS-368;So;0;ON;;;;;N;;;;; +28A5;BRAILLE PATTERN DOTS-1368;So;0;ON;;;;;N;;;;; +28A6;BRAILLE PATTERN DOTS-2368;So;0;ON;;;;;N;;;;; +28A7;BRAILLE PATTERN DOTS-12368;So;0;ON;;;;;N;;;;; +28A8;BRAILLE PATTERN DOTS-468;So;0;ON;;;;;N;;;;; +28A9;BRAILLE PATTERN DOTS-1468;So;0;ON;;;;;N;;;;; +28AA;BRAILLE PATTERN DOTS-2468;So;0;ON;;;;;N;;;;; +28AB;BRAILLE PATTERN DOTS-12468;So;0;ON;;;;;N;;;;; +28AC;BRAILLE PATTERN DOTS-3468;So;0;ON;;;;;N;;;;; +28AD;BRAILLE PATTERN DOTS-13468;So;0;ON;;;;;N;;;;; +28AE;BRAILLE PATTERN DOTS-23468;So;0;ON;;;;;N;;;;; +28AF;BRAILLE PATTERN DOTS-123468;So;0;ON;;;;;N;;;;; +28B0;BRAILLE PATTERN DOTS-568;So;0;ON;;;;;N;;;;; +28B1;BRAILLE PATTERN DOTS-1568;So;0;ON;;;;;N;;;;; +28B2;BRAILLE PATTERN DOTS-2568;So;0;ON;;;;;N;;;;; +28B3;BRAILLE PATTERN DOTS-12568;So;0;ON;;;;;N;;;;; +28B4;BRAILLE PATTERN DOTS-3568;So;0;ON;;;;;N;;;;; +28B5;BRAILLE PATTERN DOTS-13568;So;0;ON;;;;;N;;;;; +28B6;BRAILLE PATTERN DOTS-23568;So;0;ON;;;;;N;;;;; +28B7;BRAILLE PATTERN DOTS-123568;So;0;ON;;;;;N;;;;; +28B8;BRAILLE PATTERN DOTS-4568;So;0;ON;;;;;N;;;;; +28B9;BRAILLE PATTERN DOTS-14568;So;0;ON;;;;;N;;;;; +28BA;BRAILLE PATTERN DOTS-24568;So;0;ON;;;;;N;;;;; +28BB;BRAILLE PATTERN DOTS-124568;So;0;ON;;;;;N;;;;; +28BC;BRAILLE PATTERN DOTS-34568;So;0;ON;;;;;N;;;;; +28BD;BRAILLE PATTERN DOTS-134568;So;0;ON;;;;;N;;;;; +28BE;BRAILLE PATTERN DOTS-234568;So;0;ON;;;;;N;;;;; +28BF;BRAILLE PATTERN DOTS-1234568;So;0;ON;;;;;N;;;;; +28C0;BRAILLE PATTERN DOTS-78;So;0;ON;;;;;N;;;;; +28C1;BRAILLE PATTERN DOTS-178;So;0;ON;;;;;N;;;;; +28C2;BRAILLE PATTERN DOTS-278;So;0;ON;;;;;N;;;;; +28C3;BRAILLE PATTERN DOTS-1278;So;0;ON;;;;;N;;;;; +28C4;BRAILLE PATTERN DOTS-378;So;0;ON;;;;;N;;;;; +28C5;BRAILLE PATTERN DOTS-1378;So;0;ON;;;;;N;;;;; +28C6;BRAILLE PATTERN DOTS-2378;So;0;ON;;;;;N;;;;; +28C7;BRAILLE PATTERN DOTS-12378;So;0;ON;;;;;N;;;;; +28C8;BRAILLE PATTERN DOTS-478;So;0;ON;;;;;N;;;;; +28C9;BRAILLE PATTERN DOTS-1478;So;0;ON;;;;;N;;;;; +28CA;BRAILLE PATTERN DOTS-2478;So;0;ON;;;;;N;;;;; +28CB;BRAILLE PATTERN DOTS-12478;So;0;ON;;;;;N;;;;; +28CC;BRAILLE PATTERN DOTS-3478;So;0;ON;;;;;N;;;;; +28CD;BRAILLE PATTERN DOTS-13478;So;0;ON;;;;;N;;;;; +28CE;BRAILLE PATTERN DOTS-23478;So;0;ON;;;;;N;;;;; +28CF;BRAILLE PATTERN DOTS-123478;So;0;ON;;;;;N;;;;; +28D0;BRAILLE PATTERN DOTS-578;So;0;ON;;;;;N;;;;; +28D1;BRAILLE PATTERN DOTS-1578;So;0;ON;;;;;N;;;;; +28D2;BRAILLE PATTERN DOTS-2578;So;0;ON;;;;;N;;;;; +28D3;BRAILLE PATTERN DOTS-12578;So;0;ON;;;;;N;;;;; +28D4;BRAILLE PATTERN DOTS-3578;So;0;ON;;;;;N;;;;; +28D5;BRAILLE PATTERN DOTS-13578;So;0;ON;;;;;N;;;;; +28D6;BRAILLE PATTERN DOTS-23578;So;0;ON;;;;;N;;;;; +28D7;BRAILLE PATTERN DOTS-123578;So;0;ON;;;;;N;;;;; +28D8;BRAILLE PATTERN DOTS-4578;So;0;ON;;;;;N;;;;; +28D9;BRAILLE PATTERN DOTS-14578;So;0;ON;;;;;N;;;;; +28DA;BRAILLE PATTERN DOTS-24578;So;0;ON;;;;;N;;;;; +28DB;BRAILLE PATTERN DOTS-124578;So;0;ON;;;;;N;;;;; +28DC;BRAILLE PATTERN DOTS-34578;So;0;ON;;;;;N;;;;; +28DD;BRAILLE PATTERN DOTS-134578;So;0;ON;;;;;N;;;;; +28DE;BRAILLE PATTERN DOTS-234578;So;0;ON;;;;;N;;;;; +28DF;BRAILLE PATTERN DOTS-1234578;So;0;ON;;;;;N;;;;; +28E0;BRAILLE PATTERN DOTS-678;So;0;ON;;;;;N;;;;; +28E1;BRAILLE PATTERN DOTS-1678;So;0;ON;;;;;N;;;;; +28E2;BRAILLE PATTERN DOTS-2678;So;0;ON;;;;;N;;;;; +28E3;BRAILLE PATTERN DOTS-12678;So;0;ON;;;;;N;;;;; +28E4;BRAILLE PATTERN DOTS-3678;So;0;ON;;;;;N;;;;; +28E5;BRAILLE PATTERN DOTS-13678;So;0;ON;;;;;N;;;;; +28E6;BRAILLE PATTERN DOTS-23678;So;0;ON;;;;;N;;;;; +28E7;BRAILLE PATTERN DOTS-123678;So;0;ON;;;;;N;;;;; +28E8;BRAILLE PATTERN DOTS-4678;So;0;ON;;;;;N;;;;; +28E9;BRAILLE PATTERN DOTS-14678;So;0;ON;;;;;N;;;;; +28EA;BRAILLE PATTERN DOTS-24678;So;0;ON;;;;;N;;;;; +28EB;BRAILLE PATTERN DOTS-124678;So;0;ON;;;;;N;;;;; +28EC;BRAILLE PATTERN DOTS-34678;So;0;ON;;;;;N;;;;; +28ED;BRAILLE PATTERN DOTS-134678;So;0;ON;;;;;N;;;;; +28EE;BRAILLE PATTERN DOTS-234678;So;0;ON;;;;;N;;;;; +28EF;BRAILLE PATTERN DOTS-1234678;So;0;ON;;;;;N;;;;; +28F0;BRAILLE PATTERN DOTS-5678;So;0;ON;;;;;N;;;;; +28F1;BRAILLE PATTERN DOTS-15678;So;0;ON;;;;;N;;;;; +28F2;BRAILLE PATTERN DOTS-25678;So;0;ON;;;;;N;;;;; +28F3;BRAILLE PATTERN DOTS-125678;So;0;ON;;;;;N;;;;; +28F4;BRAILLE PATTERN DOTS-35678;So;0;ON;;;;;N;;;;; +28F5;BRAILLE PATTERN DOTS-135678;So;0;ON;;;;;N;;;;; +28F6;BRAILLE PATTERN DOTS-235678;So;0;ON;;;;;N;;;;; +28F7;BRAILLE PATTERN DOTS-1235678;So;0;ON;;;;;N;;;;; +28F8;BRAILLE PATTERN DOTS-45678;So;0;ON;;;;;N;;;;; +28F9;BRAILLE PATTERN DOTS-145678;So;0;ON;;;;;N;;;;; +28FA;BRAILLE PATTERN DOTS-245678;So;0;ON;;;;;N;;;;; +28FB;BRAILLE PATTERN DOTS-1245678;So;0;ON;;;;;N;;;;; +28FC;BRAILLE PATTERN DOTS-345678;So;0;ON;;;;;N;;;;; +28FD;BRAILLE PATTERN DOTS-1345678;So;0;ON;;;;;N;;;;; +28FE;BRAILLE PATTERN DOTS-2345678;So;0;ON;;;;;N;;;;; +28FF;BRAILLE PATTERN DOTS-12345678;So;0;ON;;;;;N;;;;; +2900;RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2901;RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2902;LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2903;RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2904;LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2905;RIGHTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +2906;LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +2907;RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;; +2908;DOWNWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +2909;UPWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +290A;UPWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;; +290B;DOWNWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;; +290C;LEFTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +290D;RIGHTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +290E;LEFTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +290F;RIGHTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +2910;RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;; +2911;RIGHTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;; +2912;UPWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;; +2913;DOWNWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;; +2914;RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2915;RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2916;RIGHTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;; +2917;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2918;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2919;LEFTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;; +291A;RIGHTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;; +291B;LEFTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;; +291C;RIGHTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;; +291D;LEFTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; +291E;RIGHTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; +291F;LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; +2920;RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; +2921;NORTH WEST AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2922;NORTH EAST AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;; +2923;NORTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; +2924;NORTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; +2925;SOUTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; +2926;SOUTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;; +2927;NORTH WEST ARROW AND NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2928;NORTH EAST ARROW AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2929;SOUTH EAST ARROW AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;; +292A;SOUTH WEST ARROW AND NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;; +292B;RISING DIAGONAL CROSSING FALLING DIAGONAL;Sm;0;ON;;;;;N;;;;; +292C;FALLING DIAGONAL CROSSING RISING DIAGONAL;Sm;0;ON;;;;;N;;;;; +292D;SOUTH EAST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +292E;NORTH EAST ARROW CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +292F;FALLING DIAGONAL CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2930;RISING DIAGONAL CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2931;NORTH EAST ARROW CROSSING NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;; +2932;NORTH WEST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;; +2933;WAVE ARROW POINTING DIRECTLY RIGHT;Sm;0;ON;;;;;N;;;;; +2934;ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS;Sm;0;ON;;;;;N;;;;; +2935;ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS;Sm;0;ON;;;;;N;;;;; +2936;ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS;Sm;0;ON;;;;;N;;;;; +2937;ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS;Sm;0;ON;;;;;N;;;;; +2938;RIGHT-SIDE ARC CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +2939;LEFT-SIDE ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +293A;TOP ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +293B;BOTTOM ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +293C;TOP ARC CLOCKWISE ARROW WITH MINUS;Sm;0;ON;;;;;N;;;;; +293D;TOP ARC ANTICLOCKWISE ARROW WITH PLUS;Sm;0;ON;;;;;N;;;;; +293E;LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +293F;LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;; +2940;ANTICLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; +2941;CLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;; +2942;RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2943;LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2944;SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2945;RIGHTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;; +2946;LEFTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;; +2947;RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;; +2948;LEFT RIGHT ARROW THROUGH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; +2949;UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; +294A;LEFT BARB UP RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;; +294B;LEFT BARB DOWN RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;; +294C;UP BARB RIGHT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;; +294D;UP BARB LEFT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;; +294E;LEFT BARB UP RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;; +294F;UP BARB RIGHT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;; +2950;LEFT BARB DOWN RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;; +2951;UP BARB LEFT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;; +2952;LEFTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;; +2953;RIGHTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;; +2954;UPWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;; +2955;DOWNWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;; +2956;LEFTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;; +2957;RIGHTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;; +2958;UPWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;; +2959;DOWNWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;; +295A;LEFTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;; +295B;RIGHTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;; +295C;UPWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;; +295D;DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;; +295E;LEFTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;; +295F;RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;; +2960;UPWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;; +2961;DOWNWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;; +2962;LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; +2963;UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; +2964;RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; +2965;DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; +2966;LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;; +2967;LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; +2968;RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;; +2969;RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;; +296A;LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;; +296B;LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;; +296C;RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;; +296D;RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;; +296E;UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; +296F;DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;; +2970;RIGHT DOUBLE ARROW WITH ROUNDED HEAD;Sm;0;ON;;;;;N;;;;; +2971;EQUALS SIGN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2972;TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2973;LEFTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; +2974;RIGHTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;; +2975;RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;; +2976;LESS-THAN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2977;LEFTWARDS ARROW THROUGH LESS-THAN;Sm;0;ON;;;;;N;;;;; +2978;GREATER-THAN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +2979;SUBSET ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +297A;LEFTWARDS ARROW THROUGH SUBSET;Sm;0;ON;;;;;N;;;;; +297B;SUPERSET ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;; +297C;LEFT FISH TAIL;Sm;0;ON;;;;;N;;;;; +297D;RIGHT FISH TAIL;Sm;0;ON;;;;;N;;;;; +297E;UP FISH TAIL;Sm;0;ON;;;;;N;;;;; +297F;DOWN FISH TAIL;Sm;0;ON;;;;;N;;;;; +2980;TRIPLE VERTICAL BAR DELIMITER;Sm;0;ON;;;;;N;;;;; +2981;Z NOTATION SPOT;Sm;0;ON;;;;;N;;;;; +2982;Z NOTATION TYPE COLON;Sm;0;ON;;;;;N;;;;; +2983;LEFT WHITE CURLY BRACKET;Ps;0;ON;;;;;Y;;;;; +2984;RIGHT WHITE CURLY BRACKET;Pe;0;ON;;;;;Y;;;;; +2985;LEFT WHITE PARENTHESIS;Ps;0;ON;;;;;Y;;;;; +2986;RIGHT WHITE PARENTHESIS;Pe;0;ON;;;;;Y;;;;; +2987;Z NOTATION LEFT IMAGE BRACKET;Ps;0;ON;;;;;Y;;;;; +2988;Z NOTATION RIGHT IMAGE BRACKET;Pe;0;ON;;;;;Y;;;;; +2989;Z NOTATION LEFT BINDING BRACKET;Ps;0;ON;;;;;Y;;;;; +298A;Z NOTATION RIGHT BINDING BRACKET;Pe;0;ON;;;;;Y;;;;; +298B;LEFT SQUARE BRACKET WITH UNDERBAR;Ps;0;ON;;;;;Y;;;;; +298C;RIGHT SQUARE BRACKET WITH UNDERBAR;Pe;0;ON;;;;;Y;;;;; +298D;LEFT SQUARE BRACKET WITH TICK IN TOP CORNER;Ps;0;ON;;;;;Y;;;;; +298E;RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Pe;0;ON;;;;;Y;;;;; +298F;LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Ps;0;ON;;;;;Y;;;;; +2990;RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER;Pe;0;ON;;;;;Y;;;;; +2991;LEFT ANGLE BRACKET WITH DOT;Ps;0;ON;;;;;Y;;;;; +2992;RIGHT ANGLE BRACKET WITH DOT;Pe;0;ON;;;;;Y;;;;; +2993;LEFT ARC LESS-THAN BRACKET;Ps;0;ON;;;;;Y;;;;; +2994;RIGHT ARC GREATER-THAN BRACKET;Pe;0;ON;;;;;Y;;;;; +2995;DOUBLE LEFT ARC GREATER-THAN BRACKET;Ps;0;ON;;;;;Y;;;;; +2996;DOUBLE RIGHT ARC LESS-THAN BRACKET;Pe;0;ON;;;;;Y;;;;; +2997;LEFT BLACK TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;; +2998;RIGHT BLACK TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;; +2999;DOTTED FENCE;Sm;0;ON;;;;;N;;;;; +299A;VERTICAL ZIGZAG LINE;Sm;0;ON;;;;;N;;;;; +299B;MEASURED ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;; +299C;RIGHT ANGLE VARIANT WITH SQUARE;Sm;0;ON;;;;;Y;;;;; +299D;MEASURED RIGHT ANGLE WITH DOT;Sm;0;ON;;;;;Y;;;;; +299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;; +299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;; +29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;; +29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;; +29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;; +29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;; +29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; +29A5;REVERSED ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; +29A6;OBLIQUE ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;; +29A7;OBLIQUE ANGLE OPENING DOWN;Sm;0;ON;;;;;Y;;;;; +29A8;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT;Sm;0;ON;;;;;Y;;;;; +29A9;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT;Sm;0;ON;;;;;Y;;;;; +29AA;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT;Sm;0;ON;;;;;Y;;;;; +29AB;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT;Sm;0;ON;;;;;Y;;;;; +29AC;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP;Sm;0;ON;;;;;Y;;;;; +29AD;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP;Sm;0;ON;;;;;Y;;;;; +29AE;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN;Sm;0;ON;;;;;Y;;;;; +29AF;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN;Sm;0;ON;;;;;Y;;;;; +29B0;REVERSED EMPTY SET;Sm;0;ON;;;;;N;;;;; +29B1;EMPTY SET WITH OVERBAR;Sm;0;ON;;;;;N;;;;; +29B2;EMPTY SET WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; +29B3;EMPTY SET WITH RIGHT ARROW ABOVE;Sm;0;ON;;;;;N;;;;; +29B4;EMPTY SET WITH LEFT ARROW ABOVE;Sm;0;ON;;;;;N;;;;; +29B5;CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;; +29B6;CIRCLED VERTICAL BAR;Sm;0;ON;;;;;N;;;;; +29B7;CIRCLED PARALLEL;Sm;0;ON;;;;;N;;;;; +29B8;CIRCLED REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;; +29B9;CIRCLED PERPENDICULAR;Sm;0;ON;;;;;N;;;;; +29BA;CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR;Sm;0;ON;;;;;N;;;;; +29BB;CIRCLE WITH SUPERIMPOSED X;Sm;0;ON;;;;;N;;;;; +29BC;CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN;Sm;0;ON;;;;;N;;;;; +29BD;UP ARROW THROUGH CIRCLE;Sm;0;ON;;;;;N;;;;; +29BE;CIRCLED WHITE BULLET;Sm;0;ON;;;;;N;;;;; +29BF;CIRCLED BULLET;Sm;0;ON;;;;;N;;;;; +29C0;CIRCLED LESS-THAN;Sm;0;ON;;;;;Y;;;;; +29C1;CIRCLED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +29C2;CIRCLE WITH SMALL CIRCLE TO THE RIGHT;Sm;0;ON;;;;;Y;;;;; +29C3;CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT;Sm;0;ON;;;;;Y;;;;; +29C4;SQUARED RISING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;; +29C5;SQUARED FALLING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;; +29C6;SQUARED ASTERISK;Sm;0;ON;;;;;N;;;;; +29C7;SQUARED SMALL CIRCLE;Sm;0;ON;;;;;N;;;;; +29C8;SQUARED SQUARE;Sm;0;ON;;;;;N;;;;; +29C9;TWO JOINED SQUARES;Sm;0;ON;;;;;Y;;;;; +29CA;TRIANGLE WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; +29CB;TRIANGLE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; +29CC;S IN TRIANGLE;Sm;0;ON;;;;;N;;;;; +29CD;TRIANGLE WITH SERIFS AT BOTTOM;Sm;0;ON;;;;;N;;;;; +29CE;RIGHT TRIANGLE ABOVE LEFT TRIANGLE;Sm;0;ON;;;;;Y;;;;; +29CF;LEFT TRIANGLE BESIDE VERTICAL BAR;Sm;0;ON;;;;;Y;;;;; +29D0;VERTICAL BAR BESIDE RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;; +29D1;BOWTIE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29D2;BOWTIE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29D3;BLACK BOWTIE;Sm;0;ON;;;;;N;;;;; +29D4;TIMES WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29D5;TIMES WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29D6;WHITE HOURGLASS;Sm;0;ON;;;;;N;;;;; +29D7;BLACK HOURGLASS;Sm;0;ON;;;;;N;;;;; +29D8;LEFT WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;; +29D9;RIGHT WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;; +29DA;LEFT DOUBLE WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;; +29DB;RIGHT DOUBLE WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;; +29DC;INCOMPLETE INFINITY;Sm;0;ON;;;;;Y;;;;; +29DD;TIE OVER INFINITY;Sm;0;ON;;;;;N;;;;; +29DE;INFINITY NEGATED WITH VERTICAL BAR;Sm;0;ON;;;;;N;;;;; +29DF;DOUBLE-ENDED MULTIMAP;Sm;0;ON;;;;;N;;;;; +29E0;SQUARE WITH CONTOURED OUTLINE;Sm;0;ON;;;;;N;;;;; +29E1;INCREASES AS;Sm;0;ON;;;;;Y;;;;; +29E2;SHUFFLE PRODUCT;Sm;0;ON;;;;;N;;;;; +29E3;EQUALS SIGN AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;; +29E4;EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;; +29E5;IDENTICAL TO AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;; +29E6;GLEICH STARK;Sm;0;ON;;;;;N;;;;; +29E7;THERMODYNAMIC;Sm;0;ON;;;;;N;;;;; +29E8;DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29E9;DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;; +29EA;BLACK DIAMOND WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; +29EB;BLACK LOZENGE;Sm;0;ON;;;;;N;;;;; +29EC;WHITE CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; +29ED;BLACK CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;; +29EE;ERROR-BARRED WHITE SQUARE;Sm;0;ON;;;;;N;;;;; +29EF;ERROR-BARRED BLACK SQUARE;Sm;0;ON;;;;;N;;;;; +29F0;ERROR-BARRED WHITE DIAMOND;Sm;0;ON;;;;;N;;;;; +29F1;ERROR-BARRED BLACK DIAMOND;Sm;0;ON;;;;;N;;;;; +29F2;ERROR-BARRED WHITE CIRCLE;Sm;0;ON;;;;;N;;;;; +29F3;ERROR-BARRED BLACK CIRCLE;Sm;0;ON;;;;;N;;;;; +29F4;RULE-DELAYED;Sm;0;ON;;;;;Y;;;;; +29F5;REVERSE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;; +29F6;SOLIDUS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +29F7;REVERSE SOLIDUS WITH HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;; +29F8;BIG SOLIDUS;Sm;0;ON;;;;;Y;;;;; +29F9;BIG REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;; +29FA;DOUBLE PLUS;Sm;0;ON;;;;;N;;;;; +29FB;TRIPLE PLUS;Sm;0;ON;;;;;N;;;;; +29FC;LEFT-POINTING CURVED ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;; +29FD;RIGHT-POINTING CURVED ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;; +29FE;TINY;Sm;0;ON;;;;;N;;;;; +29FF;MINY;Sm;0;ON;;;;;N;;;;; +2A00;N-ARY CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +2A01;N-ARY CIRCLED PLUS OPERATOR;Sm;0;ON;;;;;N;;;;; +2A02;N-ARY CIRCLED TIMES OPERATOR;Sm;0;ON;;;;;N;;;;; +2A03;N-ARY UNION OPERATOR WITH DOT;Sm;0;ON;;;;;N;;;;; +2A04;N-ARY UNION OPERATOR WITH PLUS;Sm;0;ON;;;;;N;;;;; +2A05;N-ARY SQUARE INTERSECTION OPERATOR;Sm;0;ON;;;;;N;;;;; +2A06;N-ARY SQUARE UNION OPERATOR;Sm;0;ON;;;;;N;;;;; +2A07;TWO LOGICAL AND OPERATOR;Sm;0;ON;;;;;N;;;;; +2A08;TWO LOGICAL OR OPERATOR;Sm;0;ON;;;;;N;;;;; +2A09;N-ARY TIMES OPERATOR;Sm;0;ON;;;;;N;;;;; +2A0A;MODULO TWO SUM;Sm;0;ON;;;;;Y;;;;; +2A0B;SUMMATION WITH INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2A0C;QUADRUPLE INTEGRAL OPERATOR;Sm;0;ON;<compat> 222B 222B 222B 222B;;;;Y;;;;; +2A0D;FINITE PART INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2A0E;INTEGRAL WITH DOUBLE STROKE;Sm;0;ON;;;;;Y;;;;; +2A0F;INTEGRAL AVERAGE WITH SLASH;Sm;0;ON;;;;;Y;;;;; +2A10;CIRCULATION FUNCTION;Sm;0;ON;;;;;Y;;;;; +2A11;ANTICLOCKWISE INTEGRATION;Sm;0;ON;;;;;Y;;;;; +2A12;LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;; +2A13;LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;; +2A14;LINE INTEGRATION NOT INCLUDING THE POLE;Sm;0;ON;;;;;Y;;;;; +2A15;INTEGRAL AROUND A POINT OPERATOR;Sm;0;ON;;;;;Y;;;;; +2A16;QUATERNION INTEGRAL OPERATOR;Sm;0;ON;;;;;Y;;;;; +2A17;INTEGRAL WITH LEFTWARDS ARROW WITH HOOK;Sm;0;ON;;;;;Y;;;;; +2A18;INTEGRAL WITH TIMES SIGN;Sm;0;ON;;;;;Y;;;;; +2A19;INTEGRAL WITH INTERSECTION;Sm;0;ON;;;;;Y;;;;; +2A1A;INTEGRAL WITH UNION;Sm;0;ON;;;;;Y;;;;; +2A1B;INTEGRAL WITH OVERBAR;Sm;0;ON;;;;;Y;;;;; +2A1C;INTEGRAL WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; +2A1D;JOIN;Sm;0;ON;;;;;N;;;;; +2A1E;LARGE LEFT TRIANGLE OPERATOR;Sm;0;ON;;;;;Y;;;;; +2A1F;Z NOTATION SCHEMA COMPOSITION;Sm;0;ON;;;;;Y;;;;; +2A20;Z NOTATION SCHEMA PIPING;Sm;0;ON;;;;;Y;;;;; +2A21;Z NOTATION SCHEMA PROJECTION;Sm;0;ON;;;;;Y;;;;; +2A22;PLUS SIGN WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; +2A23;PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE;Sm;0;ON;;;;;N;;;;; +2A24;PLUS SIGN WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;; +2A25;PLUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; +2A26;PLUS SIGN WITH TILDE BELOW;Sm;0;ON;;;;;Y;;;;; +2A27;PLUS SIGN WITH SUBSCRIPT TWO;Sm;0;ON;;;;;N;;;;; +2A28;PLUS SIGN WITH BLACK TRIANGLE;Sm;0;ON;;;;;N;;;;; +2A29;MINUS SIGN WITH COMMA ABOVE;Sm;0;ON;;;;;Y;;;;; +2A2A;MINUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; +2A2B;MINUS SIGN WITH FALLING DOTS;Sm;0;ON;;;;;Y;;;;; +2A2C;MINUS SIGN WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;; +2A2D;PLUS SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; +2A2E;PLUS SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; +2A2F;VECTOR OR CROSS PRODUCT;Sm;0;ON;;;;;N;;;;; +2A30;MULTIPLICATION SIGN WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; +2A31;MULTIPLICATION SIGN WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; +2A32;SEMIDIRECT PRODUCT WITH BOTTOM CLOSED;Sm;0;ON;;;;;N;;;;; +2A33;SMASH PRODUCT;Sm;0;ON;;;;;N;;;;; +2A34;MULTIPLICATION SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; +2A35;MULTIPLICATION SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;; +2A36;CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;N;;;;; +2A37;MULTIPLICATION SIGN IN DOUBLE CIRCLE;Sm;0;ON;;;;;N;;;;; +2A38;CIRCLED DIVISION SIGN;Sm;0;ON;;;;;N;;;;; +2A39;PLUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; +2A3A;MINUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; +2A3B;MULTIPLICATION SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;; +2A3C;INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;; +2A3D;RIGHTHAND INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;; +2A3E;Z NOTATION RELATIONAL COMPOSITION;Sm;0;ON;;;;;Y;;;;; +2A3F;AMALGAMATION OR COPRODUCT;Sm;0;ON;;;;;N;;;;; +2A40;INTERSECTION WITH DOT;Sm;0;ON;;;;;N;;;;; +2A41;UNION WITH MINUS SIGN;Sm;0;ON;;;;;N;;;;; +2A42;UNION WITH OVERBAR;Sm;0;ON;;;;;N;;;;; +2A43;INTERSECTION WITH OVERBAR;Sm;0;ON;;;;;N;;;;; +2A44;INTERSECTION WITH LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2A45;UNION WITH LOGICAL OR;Sm;0;ON;;;;;N;;;;; +2A46;UNION ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;; +2A47;INTERSECTION ABOVE UNION;Sm;0;ON;;;;;N;;;;; +2A48;UNION ABOVE BAR ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;; +2A49;INTERSECTION ABOVE BAR ABOVE UNION;Sm;0;ON;;;;;N;;;;; +2A4A;UNION BESIDE AND JOINED WITH UNION;Sm;0;ON;;;;;N;;;;; +2A4B;INTERSECTION BESIDE AND JOINED WITH INTERSECTION;Sm;0;ON;;;;;N;;;;; +2A4C;CLOSED UNION WITH SERIFS;Sm;0;ON;;;;;N;;;;; +2A4D;CLOSED INTERSECTION WITH SERIFS;Sm;0;ON;;;;;N;;;;; +2A4E;DOUBLE SQUARE INTERSECTION;Sm;0;ON;;;;;N;;;;; +2A4F;DOUBLE SQUARE UNION;Sm;0;ON;;;;;N;;;;; +2A50;CLOSED UNION WITH SERIFS AND SMASH PRODUCT;Sm;0;ON;;;;;N;;;;; +2A51;LOGICAL AND WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; +2A52;LOGICAL OR WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; +2A53;DOUBLE LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2A54;DOUBLE LOGICAL OR;Sm;0;ON;;;;;N;;;;; +2A55;TWO INTERSECTING LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2A56;TWO INTERSECTING LOGICAL OR;Sm;0;ON;;;;;N;;;;; +2A57;SLOPING LARGE OR;Sm;0;ON;;;;;Y;;;;; +2A58;SLOPING LARGE AND;Sm;0;ON;;;;;Y;;;;; +2A59;LOGICAL OR OVERLAPPING LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2A5A;LOGICAL AND WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;; +2A5B;LOGICAL OR WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;; +2A5C;LOGICAL AND WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;; +2A5D;LOGICAL OR WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;; +2A5E;LOGICAL AND WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;; +2A5F;LOGICAL AND WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; +2A60;LOGICAL AND WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;; +2A61;SMALL VEE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; +2A62;LOGICAL OR WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;; +2A63;LOGICAL OR WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;; +2A64;Z NOTATION DOMAIN ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;; +2A65;Z NOTATION RANGE ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;; +2A66;EQUALS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;; +2A67;IDENTICAL WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;; +2A68;TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2A69;TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;; +2A6A;TILDE OPERATOR WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2A6B;TILDE OPERATOR WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;; +2A6C;SIMILAR MINUS SIMILAR;Sm;0;ON;;;;;Y;;;;; +2A6D;CONGRUENT WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2A6E;EQUALS WITH ASTERISK;Sm;0;ON;;;;;N;;;;; +2A6F;ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;Y;;;;; +2A70;APPROXIMATELY EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2A71;EQUALS SIGN ABOVE PLUS SIGN;Sm;0;ON;;;;;N;;;;; +2A72;PLUS SIGN ABOVE EQUALS SIGN;Sm;0;ON;;;;;N;;;;; +2A73;EQUALS SIGN ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +2A74;DOUBLE COLON EQUAL;Sm;0;ON;<compat> 003A 003A 003D;;;;Y;;;;; +2A75;TWO CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D;;;;N;;;;; +2A76;THREE CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D 003D;;;;N;;;;; +2A77;EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW;Sm;0;ON;;;;;N;;;;; +2A78;EQUIVALENT WITH FOUR DOTS ABOVE;Sm;0;ON;;;;;N;;;;; +2A79;LESS-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;; +2A7A;GREATER-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;; +2A7B;LESS-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;; +2A7C;GREATER-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;; +2A7D;LESS-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2A7E;GREATER-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2A7F;LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; +2A80;GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; +2A81;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2A82;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2A83;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT;Sm;0;ON;;;;;Y;;;;; +2A84;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT;Sm;0;ON;;;;;Y;;;;; +2A85;LESS-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;; +2A86;GREATER-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;; +2A87;LESS-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2A88;GREATER-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2A89;LESS-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;; +2A8A;GREATER-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;; +2A8B;LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A8C;GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A8D;LESS-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;; +2A8E;GREATER-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;; +2A8F;LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A90;GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A91;LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;; +2A92;GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;; +2A93;LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; +2A94;GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; +2A95;SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A96;SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A97;SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; +2A98;SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;; +2A99;DOUBLE-LINE EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A9A;DOUBLE-LINE EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A9B;DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A9C;DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A9D;SIMILAR OR LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2A9E;SIMILAR OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2A9F;SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AA0;SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AA1;DOUBLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2AA2;DOUBLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2AA3;DOUBLE NESTED LESS-THAN WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;; +2AA4;GREATER-THAN OVERLAPPING LESS-THAN;Sm;0;ON;;;;;N;;;;; +2AA5;GREATER-THAN BESIDE LESS-THAN;Sm;0;ON;;;;;N;;;;; +2AA6;LESS-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;; +2AA7;GREATER-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;; +2AA8;LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; +2AA9;GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;; +2AAA;SMALLER THAN;Sm;0;ON;;;;;Y;;;;; +2AAB;LARGER THAN;Sm;0;ON;;;;;Y;;;;; +2AAC;SMALLER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AAD;LARGER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AAE;EQUALS SIGN WITH BUMPY ABOVE;Sm;0;ON;;;;;N;;;;; +2AAF;PRECEDES ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AB0;SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AB1;PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB2;SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB3;PRECEDES ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AB4;SUCCEEDS ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AB5;PRECEDES ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB6;SUCCEEDS ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB7;PRECEDES ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB8;SUCCEEDS ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AB9;PRECEDES ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ABA;SUCCEEDS ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ABB;DOUBLE PRECEDES;Sm;0;ON;;;;;Y;;;;; +2ABC;DOUBLE SUCCEEDS;Sm;0;ON;;;;;Y;;;;; +2ABD;SUBSET WITH DOT;Sm;0;ON;;;;;Y;;;;; +2ABE;SUPERSET WITH DOT;Sm;0;ON;;;;;Y;;;;; +2ABF;SUBSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;; +2AC0;SUPERSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;; +2AC1;SUBSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;; +2AC2;SUPERSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;; +2AC3;SUBSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2AC4;SUPERSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;; +2AC5;SUBSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AC6;SUPERSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;; +2AC7;SUBSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +2AC8;SUPERSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +2AC9;SUBSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ACA;SUPERSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ACB;SUBSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ACC;SUPERSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2ACD;SQUARE LEFT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;; +2ACE;SQUARE RIGHT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;; +2ACF;CLOSED SUBSET;Sm;0;ON;;;;;Y;;;;; +2AD0;CLOSED SUPERSET;Sm;0;ON;;;;;Y;;;;; +2AD1;CLOSED SUBSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AD2;CLOSED SUPERSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AD3;SUBSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;; +2AD4;SUPERSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;; +2AD5;SUBSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;; +2AD6;SUPERSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;; +2AD7;SUPERSET BESIDE SUBSET;Sm;0;ON;;;;;N;;;;; +2AD8;SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET;Sm;0;ON;;;;;N;;;;; +2AD9;ELEMENT OF OPENING DOWNWARDS;Sm;0;ON;;;;;N;;;;; +2ADA;PITCHFORK WITH TEE TOP;Sm;0;ON;;;;;N;;;;; +2ADB;TRANSVERSAL INTERSECTION;Sm;0;ON;;;;;N;;;;; +2ADC;FORKING;Sm;0;ON;2ADD 0338;;;;Y;;not independent;;; +2ADD;NONFORKING;Sm;0;ON;;;;;N;;independent;;; +2ADE;SHORT LEFT TACK;Sm;0;ON;;;;;Y;;;;; +2ADF;SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;; +2AE0;SHORT UP TACK;Sm;0;ON;;;;;N;;;;; +2AE1;PERPENDICULAR WITH S;Sm;0;ON;;;;;N;;;;; +2AE2;VERTICAL BAR TRIPLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +2AE3;DOUBLE VERTICAL BAR LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +2AE4;VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +2AE5;DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +2AE6;LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL;Sm;0;ON;;;;;Y;;;;; +2AE7;SHORT DOWN TACK WITH OVERBAR;Sm;0;ON;;;;;N;;;;; +2AE8;SHORT UP TACK WITH UNDERBAR;Sm;0;ON;;;;;N;;;;; +2AE9;SHORT UP TACK ABOVE SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;; +2AEA;DOUBLE DOWN TACK;Sm;0;ON;;;;;N;;;;; +2AEB;DOUBLE UP TACK;Sm;0;ON;;;;;N;;;;; +2AEC;DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;; +2AED;REVERSED DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;; +2AEE;DOES NOT DIVIDE WITH REVERSED NEGATION SLASH;Sm;0;ON;;;;;Y;;;;; +2AEF;VERTICAL LINE WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;; +2AF0;VERTICAL LINE WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;; +2AF1;DOWN TACK WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;; +2AF2;PARALLEL WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +2AF3;PARALLEL WITH TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +2AF4;TRIPLE VERTICAL BAR BINARY RELATION;Sm;0;ON;;;;;N;;;;; +2AF5;TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;; +2AF6;TRIPLE COLON OPERATOR;Sm;0;ON;;;;;N;;;;; +2AF7;TRIPLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;; +2AF8;TRIPLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;; +2AF9;DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AFA;DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2AFB;TRIPLE SOLIDUS BINARY RELATION;Sm;0;ON;;;;;Y;;;;; +2AFC;LARGE TRIPLE VERTICAL BAR OPERATOR;Sm;0;ON;;;;;N;;;;; +2AFD;DOUBLE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;; +2AFE;WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;; +2AFF;N-ARY WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;; +2B00;NORTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;; +2B01;NORTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;; +2B02;SOUTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;; +2B03;SOUTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;; +2B04;LEFT RIGHT WHITE ARROW;So;0;ON;;;;;N;;;;; +2B05;LEFTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; +2B06;UPWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; +2B07;DOWNWARDS BLACK ARROW;So;0;ON;;;;;N;;;;; +2B08;NORTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;; +2B09;NORTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;; +2B0A;SOUTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;; +2B0B;SOUTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;; +2B0C;LEFT RIGHT BLACK ARROW;So;0;ON;;;;;N;;;;; +2B0D;UP DOWN BLACK ARROW;So;0;ON;;;;;N;;;;; +2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; +2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; +2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; +2E83;CJK RADICAL SECOND TWO;So;0;ON;;;;;N;;;;; +2E84;CJK RADICAL SECOND THREE;So;0;ON;;;;;N;;;;; +2E85;CJK RADICAL PERSON;So;0;ON;;;;;N;;;;; +2E86;CJK RADICAL BOX;So;0;ON;;;;;N;;;;; +2E87;CJK RADICAL TABLE;So;0;ON;;;;;N;;;;; +2E88;CJK RADICAL KNIFE ONE;So;0;ON;;;;;N;;;;; +2E89;CJK RADICAL KNIFE TWO;So;0;ON;;;;;N;;;;; +2E8A;CJK RADICAL DIVINATION;So;0;ON;;;;;N;;;;; +2E8B;CJK RADICAL SEAL;So;0;ON;;;;;N;;;;; +2E8C;CJK RADICAL SMALL ONE;So;0;ON;;;;;N;;;;; +2E8D;CJK RADICAL SMALL TWO;So;0;ON;;;;;N;;;;; +2E8E;CJK RADICAL LAME ONE;So;0;ON;;;;;N;;;;; +2E8F;CJK RADICAL LAME TWO;So;0;ON;;;;;N;;;;; +2E90;CJK RADICAL LAME THREE;So;0;ON;;;;;N;;;;; +2E91;CJK RADICAL LAME FOUR;So;0;ON;;;;;N;;;;; +2E92;CJK RADICAL SNAKE;So;0;ON;;;;;N;;;;; +2E93;CJK RADICAL THREAD;So;0;ON;;;;;N;;;;; +2E94;CJK RADICAL SNOUT ONE;So;0;ON;;;;;N;;;;; +2E95;CJK RADICAL SNOUT TWO;So;0;ON;;;;;N;;;;; +2E96;CJK RADICAL HEART ONE;So;0;ON;;;;;N;;;;; +2E97;CJK RADICAL HEART TWO;So;0;ON;;;;;N;;;;; +2E98;CJK RADICAL HAND;So;0;ON;;;;;N;;;;; +2E99;CJK RADICAL RAP;So;0;ON;;;;;N;;;;; +2E9B;CJK RADICAL CHOKE;So;0;ON;;;;;N;;;;; +2E9C;CJK RADICAL SUN;So;0;ON;;;;;N;;;;; +2E9D;CJK RADICAL MOON;So;0;ON;;;;;N;;;;; +2E9E;CJK RADICAL DEATH;So;0;ON;;;;;N;;;;; +2E9F;CJK RADICAL MOTHER;So;0;ON;<compat> 6BCD;;;;N;;;;; +2EA0;CJK RADICAL CIVILIAN;So;0;ON;;;;;N;;;;; +2EA1;CJK RADICAL WATER ONE;So;0;ON;;;;;N;;;;; +2EA2;CJK RADICAL WATER TWO;So;0;ON;;;;;N;;;;; +2EA3;CJK RADICAL FIRE;So;0;ON;;;;;N;;;;; +2EA4;CJK RADICAL PAW ONE;So;0;ON;;;;;N;;;;; +2EA5;CJK RADICAL PAW TWO;So;0;ON;;;;;N;;;;; +2EA6;CJK RADICAL SIMPLIFIED HALF TREE TRUNK;So;0;ON;;;;;N;;;;; +2EA7;CJK RADICAL COW;So;0;ON;;;;;N;;;;; +2EA8;CJK RADICAL DOG;So;0;ON;;;;;N;;;;; +2EA9;CJK RADICAL JADE;So;0;ON;;;;;N;;;;; +2EAA;CJK RADICAL BOLT OF CLOTH;So;0;ON;;;;;N;;;;; +2EAB;CJK RADICAL EYE;So;0;ON;;;;;N;;;;; +2EAC;CJK RADICAL SPIRIT ONE;So;0;ON;;;;;N;;;;; +2EAD;CJK RADICAL SPIRIT TWO;So;0;ON;;;;;N;;;;; +2EAE;CJK RADICAL BAMBOO;So;0;ON;;;;;N;;;;; +2EAF;CJK RADICAL SILK;So;0;ON;;;;;N;;;;; +2EB0;CJK RADICAL C-SIMPLIFIED SILK;So;0;ON;;;;;N;;;;; +2EB1;CJK RADICAL NET ONE;So;0;ON;;;;;N;;;;; +2EB2;CJK RADICAL NET TWO;So;0;ON;;;;;N;;;;; +2EB3;CJK RADICAL NET THREE;So;0;ON;;;;;N;;;;; +2EB4;CJK RADICAL NET FOUR;So;0;ON;;;;;N;;;;; +2EB5;CJK RADICAL MESH;So;0;ON;;;;;N;;;;; +2EB6;CJK RADICAL SHEEP;So;0;ON;;;;;N;;;;; +2EB7;CJK RADICAL RAM;So;0;ON;;;;;N;;;;; +2EB8;CJK RADICAL EWE;So;0;ON;;;;;N;;;;; +2EB9;CJK RADICAL OLD;So;0;ON;;;;;N;;;;; +2EBA;CJK RADICAL BRUSH ONE;So;0;ON;;;;;N;;;;; +2EBB;CJK RADICAL BRUSH TWO;So;0;ON;;;;;N;;;;; +2EBC;CJK RADICAL MEAT;So;0;ON;;;;;N;;;;; +2EBD;CJK RADICAL MORTAR;So;0;ON;;;;;N;;;;; +2EBE;CJK RADICAL GRASS ONE;So;0;ON;;;;;N;;;;; +2EBF;CJK RADICAL GRASS TWO;So;0;ON;;;;;N;;;;; +2EC0;CJK RADICAL GRASS THREE;So;0;ON;;;;;N;;;;; +2EC1;CJK RADICAL TIGER;So;0;ON;;;;;N;;;;; +2EC2;CJK RADICAL CLOTHES;So;0;ON;;;;;N;;;;; +2EC3;CJK RADICAL WEST ONE;So;0;ON;;;;;N;;;;; +2EC4;CJK RADICAL WEST TWO;So;0;ON;;;;;N;;;;; +2EC5;CJK RADICAL C-SIMPLIFIED SEE;So;0;ON;;;;;N;;;;; +2EC6;CJK RADICAL SIMPLIFIED HORN;So;0;ON;;;;;N;;;;; +2EC7;CJK RADICAL HORN;So;0;ON;;;;;N;;;;; +2EC8;CJK RADICAL C-SIMPLIFIED SPEECH;So;0;ON;;;;;N;;;;; +2EC9;CJK RADICAL C-SIMPLIFIED SHELL;So;0;ON;;;;;N;;;;; +2ECA;CJK RADICAL FOOT;So;0;ON;;;;;N;;;;; +2ECB;CJK RADICAL C-SIMPLIFIED CART;So;0;ON;;;;;N;;;;; +2ECC;CJK RADICAL SIMPLIFIED WALK;So;0;ON;;;;;N;;;;; +2ECD;CJK RADICAL WALK ONE;So;0;ON;;;;;N;;;;; +2ECE;CJK RADICAL WALK TWO;So;0;ON;;;;;N;;;;; +2ECF;CJK RADICAL CITY;So;0;ON;;;;;N;;;;; +2ED0;CJK RADICAL C-SIMPLIFIED GOLD;So;0;ON;;;;;N;;;;; +2ED1;CJK RADICAL LONG ONE;So;0;ON;;;;;N;;;;; +2ED2;CJK RADICAL LONG TWO;So;0;ON;;;;;N;;;;; +2ED3;CJK RADICAL C-SIMPLIFIED LONG;So;0;ON;;;;;N;;;;; +2ED4;CJK RADICAL C-SIMPLIFIED GATE;So;0;ON;;;;;N;;;;; +2ED5;CJK RADICAL MOUND ONE;So;0;ON;;;;;N;;;;; +2ED6;CJK RADICAL MOUND TWO;So;0;ON;;;;;N;;;;; +2ED7;CJK RADICAL RAIN;So;0;ON;;;;;N;;;;; +2ED8;CJK RADICAL BLUE;So;0;ON;;;;;N;;;;; +2ED9;CJK RADICAL C-SIMPLIFIED TANNED LEATHER;So;0;ON;;;;;N;;;;; +2EDA;CJK RADICAL C-SIMPLIFIED LEAF;So;0;ON;;;;;N;;;;; +2EDB;CJK RADICAL C-SIMPLIFIED WIND;So;0;ON;;;;;N;;;;; +2EDC;CJK RADICAL C-SIMPLIFIED FLY;So;0;ON;;;;;N;;;;; +2EDD;CJK RADICAL EAT ONE;So;0;ON;;;;;N;;;;; +2EDE;CJK RADICAL EAT TWO;So;0;ON;;;;;N;;;;; +2EDF;CJK RADICAL EAT THREE;So;0;ON;;;;;N;;;;; +2EE0;CJK RADICAL C-SIMPLIFIED EAT;So;0;ON;;;;;N;;;;; +2EE1;CJK RADICAL HEAD;So;0;ON;;;;;N;;;;; +2EE2;CJK RADICAL C-SIMPLIFIED HORSE;So;0;ON;;;;;N;;;;; +2EE3;CJK RADICAL BONE;So;0;ON;;;;;N;;;;; +2EE4;CJK RADICAL GHOST;So;0;ON;;;;;N;;;;; +2EE5;CJK RADICAL C-SIMPLIFIED FISH;So;0;ON;;;;;N;;;;; +2EE6;CJK RADICAL C-SIMPLIFIED BIRD;So;0;ON;;;;;N;;;;; +2EE7;CJK RADICAL C-SIMPLIFIED SALT;So;0;ON;;;;;N;;;;; +2EE8;CJK RADICAL SIMPLIFIED WHEAT;So;0;ON;;;;;N;;;;; +2EE9;CJK RADICAL SIMPLIFIED YELLOW;So;0;ON;;;;;N;;;;; +2EEA;CJK RADICAL C-SIMPLIFIED FROG;So;0;ON;;;;;N;;;;; +2EEB;CJK RADICAL J-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;; +2EEC;CJK RADICAL C-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;; +2EED;CJK RADICAL J-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;; +2EEE;CJK RADICAL C-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;; +2EEF;CJK RADICAL J-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;; +2EF0;CJK RADICAL C-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;; +2EF1;CJK RADICAL TURTLE;So;0;ON;;;;;N;;;;; +2EF2;CJK RADICAL J-SIMPLIFIED TURTLE;So;0;ON;;;;;N;;;;; +2EF3;CJK RADICAL C-SIMPLIFIED TURTLE;So;0;ON;<compat> 9F9F;;;;N;;;;; +2F00;KANGXI RADICAL ONE;So;0;ON;<compat> 4E00;;;;N;;;;; +2F01;KANGXI RADICAL LINE;So;0;ON;<compat> 4E28;;;;N;;;;; +2F02;KANGXI RADICAL DOT;So;0;ON;<compat> 4E36;;;;N;;;;; +2F03;KANGXI RADICAL SLASH;So;0;ON;<compat> 4E3F;;;;N;;;;; +2F04;KANGXI RADICAL SECOND;So;0;ON;<compat> 4E59;;;;N;;;;; +2F05;KANGXI RADICAL HOOK;So;0;ON;<compat> 4E85;;;;N;;;;; +2F06;KANGXI RADICAL TWO;So;0;ON;<compat> 4E8C;;;;N;;;;; +2F07;KANGXI RADICAL LID;So;0;ON;<compat> 4EA0;;;;N;;;;; +2F08;KANGXI RADICAL MAN;So;0;ON;<compat> 4EBA;;;;N;;;;; +2F09;KANGXI RADICAL LEGS;So;0;ON;<compat> 513F;;;;N;;;;; +2F0A;KANGXI RADICAL ENTER;So;0;ON;<compat> 5165;;;;N;;;;; +2F0B;KANGXI RADICAL EIGHT;So;0;ON;<compat> 516B;;;;N;;;;; +2F0C;KANGXI RADICAL DOWN BOX;So;0;ON;<compat> 5182;;;;N;;;;; +2F0D;KANGXI RADICAL COVER;So;0;ON;<compat> 5196;;;;N;;;;; +2F0E;KANGXI RADICAL ICE;So;0;ON;<compat> 51AB;;;;N;;;;; +2F0F;KANGXI RADICAL TABLE;So;0;ON;<compat> 51E0;;;;N;;;;; +2F10;KANGXI RADICAL OPEN BOX;So;0;ON;<compat> 51F5;;;;N;;;;; +2F11;KANGXI RADICAL KNIFE;So;0;ON;<compat> 5200;;;;N;;;;; +2F12;KANGXI RADICAL POWER;So;0;ON;<compat> 529B;;;;N;;;;; +2F13;KANGXI RADICAL WRAP;So;0;ON;<compat> 52F9;;;;N;;;;; +2F14;KANGXI RADICAL SPOON;So;0;ON;<compat> 5315;;;;N;;;;; +2F15;KANGXI RADICAL RIGHT OPEN BOX;So;0;ON;<compat> 531A;;;;N;;;;; +2F16;KANGXI RADICAL HIDING ENCLOSURE;So;0;ON;<compat> 5338;;;;N;;;;; +2F17;KANGXI RADICAL TEN;So;0;ON;<compat> 5341;;;;N;;;;; +2F18;KANGXI RADICAL DIVINATION;So;0;ON;<compat> 535C;;;;N;;;;; +2F19;KANGXI RADICAL SEAL;So;0;ON;<compat> 5369;;;;N;;;;; +2F1A;KANGXI RADICAL CLIFF;So;0;ON;<compat> 5382;;;;N;;;;; +2F1B;KANGXI RADICAL PRIVATE;So;0;ON;<compat> 53B6;;;;N;;;;; +2F1C;KANGXI RADICAL AGAIN;So;0;ON;<compat> 53C8;;;;N;;;;; +2F1D;KANGXI RADICAL MOUTH;So;0;ON;<compat> 53E3;;;;N;;;;; +2F1E;KANGXI RADICAL ENCLOSURE;So;0;ON;<compat> 56D7;;;;N;;;;; +2F1F;KANGXI RADICAL EARTH;So;0;ON;<compat> 571F;;;;N;;;;; +2F20;KANGXI RADICAL SCHOLAR;So;0;ON;<compat> 58EB;;;;N;;;;; +2F21;KANGXI RADICAL GO;So;0;ON;<compat> 5902;;;;N;;;;; +2F22;KANGXI RADICAL GO SLOWLY;So;0;ON;<compat> 590A;;;;N;;;;; +2F23;KANGXI RADICAL EVENING;So;0;ON;<compat> 5915;;;;N;;;;; +2F24;KANGXI RADICAL BIG;So;0;ON;<compat> 5927;;;;N;;;;; +2F25;KANGXI RADICAL WOMAN;So;0;ON;<compat> 5973;;;;N;;;;; +2F26;KANGXI RADICAL CHILD;So;0;ON;<compat> 5B50;;;;N;;;;; +2F27;KANGXI RADICAL ROOF;So;0;ON;<compat> 5B80;;;;N;;;;; +2F28;KANGXI RADICAL INCH;So;0;ON;<compat> 5BF8;;;;N;;;;; +2F29;KANGXI RADICAL SMALL;So;0;ON;<compat> 5C0F;;;;N;;;;; +2F2A;KANGXI RADICAL LAME;So;0;ON;<compat> 5C22;;;;N;;;;; +2F2B;KANGXI RADICAL CORPSE;So;0;ON;<compat> 5C38;;;;N;;;;; +2F2C;KANGXI RADICAL SPROUT;So;0;ON;<compat> 5C6E;;;;N;;;;; +2F2D;KANGXI RADICAL MOUNTAIN;So;0;ON;<compat> 5C71;;;;N;;;;; +2F2E;KANGXI RADICAL RIVER;So;0;ON;<compat> 5DDB;;;;N;;;;; +2F2F;KANGXI RADICAL WORK;So;0;ON;<compat> 5DE5;;;;N;;;;; +2F30;KANGXI RADICAL ONESELF;So;0;ON;<compat> 5DF1;;;;N;;;;; +2F31;KANGXI RADICAL TURBAN;So;0;ON;<compat> 5DFE;;;;N;;;;; +2F32;KANGXI RADICAL DRY;So;0;ON;<compat> 5E72;;;;N;;;;; +2F33;KANGXI RADICAL SHORT THREAD;So;0;ON;<compat> 5E7A;;;;N;;;;; +2F34;KANGXI RADICAL DOTTED CLIFF;So;0;ON;<compat> 5E7F;;;;N;;;;; +2F35;KANGXI RADICAL LONG STRIDE;So;0;ON;<compat> 5EF4;;;;N;;;;; +2F36;KANGXI RADICAL TWO HANDS;So;0;ON;<compat> 5EFE;;;;N;;;;; +2F37;KANGXI RADICAL SHOOT;So;0;ON;<compat> 5F0B;;;;N;;;;; +2F38;KANGXI RADICAL BOW;So;0;ON;<compat> 5F13;;;;N;;;;; +2F39;KANGXI RADICAL SNOUT;So;0;ON;<compat> 5F50;;;;N;;;;; +2F3A;KANGXI RADICAL BRISTLE;So;0;ON;<compat> 5F61;;;;N;;;;; +2F3B;KANGXI RADICAL STEP;So;0;ON;<compat> 5F73;;;;N;;;;; +2F3C;KANGXI RADICAL HEART;So;0;ON;<compat> 5FC3;;;;N;;;;; +2F3D;KANGXI RADICAL HALBERD;So;0;ON;<compat> 6208;;;;N;;;;; +2F3E;KANGXI RADICAL DOOR;So;0;ON;<compat> 6236;;;;N;;;;; +2F3F;KANGXI RADICAL HAND;So;0;ON;<compat> 624B;;;;N;;;;; +2F40;KANGXI RADICAL BRANCH;So;0;ON;<compat> 652F;;;;N;;;;; +2F41;KANGXI RADICAL RAP;So;0;ON;<compat> 6534;;;;N;;;;; +2F42;KANGXI RADICAL SCRIPT;So;0;ON;<compat> 6587;;;;N;;;;; +2F43;KANGXI RADICAL DIPPER;So;0;ON;<compat> 6597;;;;N;;;;; +2F44;KANGXI RADICAL AXE;So;0;ON;<compat> 65A4;;;;N;;;;; +2F45;KANGXI RADICAL SQUARE;So;0;ON;<compat> 65B9;;;;N;;;;; +2F46;KANGXI RADICAL NOT;So;0;ON;<compat> 65E0;;;;N;;;;; +2F47;KANGXI RADICAL SUN;So;0;ON;<compat> 65E5;;;;N;;;;; +2F48;KANGXI RADICAL SAY;So;0;ON;<compat> 66F0;;;;N;;;;; +2F49;KANGXI RADICAL MOON;So;0;ON;<compat> 6708;;;;N;;;;; +2F4A;KANGXI RADICAL TREE;So;0;ON;<compat> 6728;;;;N;;;;; +2F4B;KANGXI RADICAL LACK;So;0;ON;<compat> 6B20;;;;N;;;;; +2F4C;KANGXI RADICAL STOP;So;0;ON;<compat> 6B62;;;;N;;;;; +2F4D;KANGXI RADICAL DEATH;So;0;ON;<compat> 6B79;;;;N;;;;; +2F4E;KANGXI RADICAL WEAPON;So;0;ON;<compat> 6BB3;;;;N;;;;; +2F4F;KANGXI RADICAL DO NOT;So;0;ON;<compat> 6BCB;;;;N;;;;; +2F50;KANGXI RADICAL COMPARE;So;0;ON;<compat> 6BD4;;;;N;;;;; +2F51;KANGXI RADICAL FUR;So;0;ON;<compat> 6BDB;;;;N;;;;; +2F52;KANGXI RADICAL CLAN;So;0;ON;<compat> 6C0F;;;;N;;;;; +2F53;KANGXI RADICAL STEAM;So;0;ON;<compat> 6C14;;;;N;;;;; +2F54;KANGXI RADICAL WATER;So;0;ON;<compat> 6C34;;;;N;;;;; +2F55;KANGXI RADICAL FIRE;So;0;ON;<compat> 706B;;;;N;;;;; +2F56;KANGXI RADICAL CLAW;So;0;ON;<compat> 722A;;;;N;;;;; +2F57;KANGXI RADICAL FATHER;So;0;ON;<compat> 7236;;;;N;;;;; +2F58;KANGXI RADICAL DOUBLE X;So;0;ON;<compat> 723B;;;;N;;;;; +2F59;KANGXI RADICAL HALF TREE TRUNK;So;0;ON;<compat> 723F;;;;N;;;;; +2F5A;KANGXI RADICAL SLICE;So;0;ON;<compat> 7247;;;;N;;;;; +2F5B;KANGXI RADICAL FANG;So;0;ON;<compat> 7259;;;;N;;;;; +2F5C;KANGXI RADICAL COW;So;0;ON;<compat> 725B;;;;N;;;;; +2F5D;KANGXI RADICAL DOG;So;0;ON;<compat> 72AC;;;;N;;;;; +2F5E;KANGXI RADICAL PROFOUND;So;0;ON;<compat> 7384;;;;N;;;;; +2F5F;KANGXI RADICAL JADE;So;0;ON;<compat> 7389;;;;N;;;;; +2F60;KANGXI RADICAL MELON;So;0;ON;<compat> 74DC;;;;N;;;;; +2F61;KANGXI RADICAL TILE;So;0;ON;<compat> 74E6;;;;N;;;;; +2F62;KANGXI RADICAL SWEET;So;0;ON;<compat> 7518;;;;N;;;;; +2F63;KANGXI RADICAL LIFE;So;0;ON;<compat> 751F;;;;N;;;;; +2F64;KANGXI RADICAL USE;So;0;ON;<compat> 7528;;;;N;;;;; +2F65;KANGXI RADICAL FIELD;So;0;ON;<compat> 7530;;;;N;;;;; +2F66;KANGXI RADICAL BOLT OF CLOTH;So;0;ON;<compat> 758B;;;;N;;;;; +2F67;KANGXI RADICAL SICKNESS;So;0;ON;<compat> 7592;;;;N;;;;; +2F68;KANGXI RADICAL DOTTED TENT;So;0;ON;<compat> 7676;;;;N;;;;; +2F69;KANGXI RADICAL WHITE;So;0;ON;<compat> 767D;;;;N;;;;; +2F6A;KANGXI RADICAL SKIN;So;0;ON;<compat> 76AE;;;;N;;;;; +2F6B;KANGXI RADICAL DISH;So;0;ON;<compat> 76BF;;;;N;;;;; +2F6C;KANGXI RADICAL EYE;So;0;ON;<compat> 76EE;;;;N;;;;; +2F6D;KANGXI RADICAL SPEAR;So;0;ON;<compat> 77DB;;;;N;;;;; +2F6E;KANGXI RADICAL ARROW;So;0;ON;<compat> 77E2;;;;N;;;;; +2F6F;KANGXI RADICAL STONE;So;0;ON;<compat> 77F3;;;;N;;;;; +2F70;KANGXI RADICAL SPIRIT;So;0;ON;<compat> 793A;;;;N;;;;; +2F71;KANGXI RADICAL TRACK;So;0;ON;<compat> 79B8;;;;N;;;;; +2F72;KANGXI RADICAL GRAIN;So;0;ON;<compat> 79BE;;;;N;;;;; +2F73;KANGXI RADICAL CAVE;So;0;ON;<compat> 7A74;;;;N;;;;; +2F74;KANGXI RADICAL STAND;So;0;ON;<compat> 7ACB;;;;N;;;;; +2F75;KANGXI RADICAL BAMBOO;So;0;ON;<compat> 7AF9;;;;N;;;;; +2F76;KANGXI RADICAL RICE;So;0;ON;<compat> 7C73;;;;N;;;;; +2F77;KANGXI RADICAL SILK;So;0;ON;<compat> 7CF8;;;;N;;;;; +2F78;KANGXI RADICAL JAR;So;0;ON;<compat> 7F36;;;;N;;;;; +2F79;KANGXI RADICAL NET;So;0;ON;<compat> 7F51;;;;N;;;;; +2F7A;KANGXI RADICAL SHEEP;So;0;ON;<compat> 7F8A;;;;N;;;;; +2F7B;KANGXI RADICAL FEATHER;So;0;ON;<compat> 7FBD;;;;N;;;;; +2F7C;KANGXI RADICAL OLD;So;0;ON;<compat> 8001;;;;N;;;;; +2F7D;KANGXI RADICAL AND;So;0;ON;<compat> 800C;;;;N;;;;; +2F7E;KANGXI RADICAL PLOW;So;0;ON;<compat> 8012;;;;N;;;;; +2F7F;KANGXI RADICAL EAR;So;0;ON;<compat> 8033;;;;N;;;;; +2F80;KANGXI RADICAL BRUSH;So;0;ON;<compat> 807F;;;;N;;;;; +2F81;KANGXI RADICAL MEAT;So;0;ON;<compat> 8089;;;;N;;;;; +2F82;KANGXI RADICAL MINISTER;So;0;ON;<compat> 81E3;;;;N;;;;; +2F83;KANGXI RADICAL SELF;So;0;ON;<compat> 81EA;;;;N;;;;; +2F84;KANGXI RADICAL ARRIVE;So;0;ON;<compat> 81F3;;;;N;;;;; +2F85;KANGXI RADICAL MORTAR;So;0;ON;<compat> 81FC;;;;N;;;;; +2F86;KANGXI RADICAL TONGUE;So;0;ON;<compat> 820C;;;;N;;;;; +2F87;KANGXI RADICAL OPPOSE;So;0;ON;<compat> 821B;;;;N;;;;; +2F88;KANGXI RADICAL BOAT;So;0;ON;<compat> 821F;;;;N;;;;; +2F89;KANGXI RADICAL STOPPING;So;0;ON;<compat> 826E;;;;N;;;;; +2F8A;KANGXI RADICAL COLOR;So;0;ON;<compat> 8272;;;;N;;;;; +2F8B;KANGXI RADICAL GRASS;So;0;ON;<compat> 8278;;;;N;;;;; +2F8C;KANGXI RADICAL TIGER;So;0;ON;<compat> 864D;;;;N;;;;; +2F8D;KANGXI RADICAL INSECT;So;0;ON;<compat> 866B;;;;N;;;;; +2F8E;KANGXI RADICAL BLOOD;So;0;ON;<compat> 8840;;;;N;;;;; +2F8F;KANGXI RADICAL WALK ENCLOSURE;So;0;ON;<compat> 884C;;;;N;;;;; +2F90;KANGXI RADICAL CLOTHES;So;0;ON;<compat> 8863;;;;N;;;;; +2F91;KANGXI RADICAL WEST;So;0;ON;<compat> 897E;;;;N;;;;; +2F92;KANGXI RADICAL SEE;So;0;ON;<compat> 898B;;;;N;;;;; +2F93;KANGXI RADICAL HORN;So;0;ON;<compat> 89D2;;;;N;;;;; +2F94;KANGXI RADICAL SPEECH;So;0;ON;<compat> 8A00;;;;N;;;;; +2F95;KANGXI RADICAL VALLEY;So;0;ON;<compat> 8C37;;;;N;;;;; +2F96;KANGXI RADICAL BEAN;So;0;ON;<compat> 8C46;;;;N;;;;; +2F97;KANGXI RADICAL PIG;So;0;ON;<compat> 8C55;;;;N;;;;; +2F98;KANGXI RADICAL BADGER;So;0;ON;<compat> 8C78;;;;N;;;;; +2F99;KANGXI RADICAL SHELL;So;0;ON;<compat> 8C9D;;;;N;;;;; +2F9A;KANGXI RADICAL RED;So;0;ON;<compat> 8D64;;;;N;;;;; +2F9B;KANGXI RADICAL RUN;So;0;ON;<compat> 8D70;;;;N;;;;; +2F9C;KANGXI RADICAL FOOT;So;0;ON;<compat> 8DB3;;;;N;;;;; +2F9D;KANGXI RADICAL BODY;So;0;ON;<compat> 8EAB;;;;N;;;;; +2F9E;KANGXI RADICAL CART;So;0;ON;<compat> 8ECA;;;;N;;;;; +2F9F;KANGXI RADICAL BITTER;So;0;ON;<compat> 8F9B;;;;N;;;;; +2FA0;KANGXI RADICAL MORNING;So;0;ON;<compat> 8FB0;;;;N;;;;; +2FA1;KANGXI RADICAL WALK;So;0;ON;<compat> 8FB5;;;;N;;;;; +2FA2;KANGXI RADICAL CITY;So;0;ON;<compat> 9091;;;;N;;;;; +2FA3;KANGXI RADICAL WINE;So;0;ON;<compat> 9149;;;;N;;;;; +2FA4;KANGXI RADICAL DISTINGUISH;So;0;ON;<compat> 91C6;;;;N;;;;; +2FA5;KANGXI RADICAL VILLAGE;So;0;ON;<compat> 91CC;;;;N;;;;; +2FA6;KANGXI RADICAL GOLD;So;0;ON;<compat> 91D1;;;;N;;;;; +2FA7;KANGXI RADICAL LONG;So;0;ON;<compat> 9577;;;;N;;;;; +2FA8;KANGXI RADICAL GATE;So;0;ON;<compat> 9580;;;;N;;;;; +2FA9;KANGXI RADICAL MOUND;So;0;ON;<compat> 961C;;;;N;;;;; +2FAA;KANGXI RADICAL SLAVE;So;0;ON;<compat> 96B6;;;;N;;;;; +2FAB;KANGXI RADICAL SHORT TAILED BIRD;So;0;ON;<compat> 96B9;;;;N;;;;; +2FAC;KANGXI RADICAL RAIN;So;0;ON;<compat> 96E8;;;;N;;;;; +2FAD;KANGXI RADICAL BLUE;So;0;ON;<compat> 9751;;;;N;;;;; +2FAE;KANGXI RADICAL WRONG;So;0;ON;<compat> 975E;;;;N;;;;; +2FAF;KANGXI RADICAL FACE;So;0;ON;<compat> 9762;;;;N;;;;; +2FB0;KANGXI RADICAL LEATHER;So;0;ON;<compat> 9769;;;;N;;;;; +2FB1;KANGXI RADICAL TANNED LEATHER;So;0;ON;<compat> 97CB;;;;N;;;;; +2FB2;KANGXI RADICAL LEEK;So;0;ON;<compat> 97ED;;;;N;;;;; +2FB3;KANGXI RADICAL SOUND;So;0;ON;<compat> 97F3;;;;N;;;;; +2FB4;KANGXI RADICAL LEAF;So;0;ON;<compat> 9801;;;;N;;;;; +2FB5;KANGXI RADICAL WIND;So;0;ON;<compat> 98A8;;;;N;;;;; +2FB6;KANGXI RADICAL FLY;So;0;ON;<compat> 98DB;;;;N;;;;; +2FB7;KANGXI RADICAL EAT;So;0;ON;<compat> 98DF;;;;N;;;;; +2FB8;KANGXI RADICAL HEAD;So;0;ON;<compat> 9996;;;;N;;;;; +2FB9;KANGXI RADICAL FRAGRANT;So;0;ON;<compat> 9999;;;;N;;;;; +2FBA;KANGXI RADICAL HORSE;So;0;ON;<compat> 99AC;;;;N;;;;; +2FBB;KANGXI RADICAL BONE;So;0;ON;<compat> 9AA8;;;;N;;;;; +2FBC;KANGXI RADICAL TALL;So;0;ON;<compat> 9AD8;;;;N;;;;; +2FBD;KANGXI RADICAL HAIR;So;0;ON;<compat> 9ADF;;;;N;;;;; +2FBE;KANGXI RADICAL FIGHT;So;0;ON;<compat> 9B25;;;;N;;;;; +2FBF;KANGXI RADICAL SACRIFICIAL WINE;So;0;ON;<compat> 9B2F;;;;N;;;;; +2FC0;KANGXI RADICAL CAULDRON;So;0;ON;<compat> 9B32;;;;N;;;;; +2FC1;KANGXI RADICAL GHOST;So;0;ON;<compat> 9B3C;;;;N;;;;; +2FC2;KANGXI RADICAL FISH;So;0;ON;<compat> 9B5A;;;;N;;;;; +2FC3;KANGXI RADICAL BIRD;So;0;ON;<compat> 9CE5;;;;N;;;;; +2FC4;KANGXI RADICAL SALT;So;0;ON;<compat> 9E75;;;;N;;;;; +2FC5;KANGXI RADICAL DEER;So;0;ON;<compat> 9E7F;;;;N;;;;; +2FC6;KANGXI RADICAL WHEAT;So;0;ON;<compat> 9EA5;;;;N;;;;; +2FC7;KANGXI RADICAL HEMP;So;0;ON;<compat> 9EBB;;;;N;;;;; +2FC8;KANGXI RADICAL YELLOW;So;0;ON;<compat> 9EC3;;;;N;;;;; +2FC9;KANGXI RADICAL MILLET;So;0;ON;<compat> 9ECD;;;;N;;;;; +2FCA;KANGXI RADICAL BLACK;So;0;ON;<compat> 9ED1;;;;N;;;;; +2FCB;KANGXI RADICAL EMBROIDERY;So;0;ON;<compat> 9EF9;;;;N;;;;; +2FCC;KANGXI RADICAL FROG;So;0;ON;<compat> 9EFD;;;;N;;;;; +2FCD;KANGXI RADICAL TRIPOD;So;0;ON;<compat> 9F0E;;;;N;;;;; +2FCE;KANGXI RADICAL DRUM;So;0;ON;<compat> 9F13;;;;N;;;;; +2FCF;KANGXI RADICAL RAT;So;0;ON;<compat> 9F20;;;;N;;;;; +2FD0;KANGXI RADICAL NOSE;So;0;ON;<compat> 9F3B;;;;N;;;;; +2FD1;KANGXI RADICAL EVEN;So;0;ON;<compat> 9F4A;;;;N;;;;; +2FD2;KANGXI RADICAL TOOTH;So;0;ON;<compat> 9F52;;;;N;;;;; +2FD3;KANGXI RADICAL DRAGON;So;0;ON;<compat> 9F8D;;;;N;;;;; +2FD4;KANGXI RADICAL TURTLE;So;0;ON;<compat> 9F9C;;;;N;;;;; +2FD5;KANGXI RADICAL FLUTE;So;0;ON;<compat> 9FA0;;;;N;;;;; +2FF0;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT;So;0;ON;;;;;N;;;;; +2FF1;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW;So;0;ON;;;;;N;;;;; +2FF2;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT;So;0;ON;;;;;N;;;;; +2FF3;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW;So;0;ON;;;;;N;;;;; +2FF4;IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND;So;0;ON;;;;;N;;;;; +2FF5;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE;So;0;ON;;;;;N;;;;; +2FF6;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW;So;0;ON;;;;;N;;;;; +2FF7;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT;So;0;ON;;;;;N;;;;; +2FF8;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT;So;0;ON;;;;;N;;;;; +2FF9;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT;So;0;ON;;;;;N;;;;; +2FFA;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT;So;0;ON;;;;;N;;;;; +2FFB;IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID;So;0;ON;;;;;N;;;;; +3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;; +3001;IDEOGRAPHIC COMMA;Po;0;ON;;;;;N;;;;; +3002;IDEOGRAPHIC FULL STOP;Po;0;ON;;;;;N;IDEOGRAPHIC PERIOD;;;; +3003;DITTO MARK;Po;0;ON;;;;;N;;;;; +3004;JAPANESE INDUSTRIAL STANDARD SYMBOL;So;0;ON;;;;;N;;;;; +3005;IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;; +3006;IDEOGRAPHIC CLOSING MARK;Lo;0;L;;;;;N;;;;; +3007;IDEOGRAPHIC NUMBER ZERO;Nl;0;L;;;;0;N;;;;; +3008;LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING ANGLE BRACKET;;;; +3009;RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING ANGLE BRACKET;;;; +300A;LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING DOUBLE ANGLE BRACKET;;;; +300B;RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING DOUBLE ANGLE BRACKET;;;; +300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;; +300D;RIGHT CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING CORNER BRACKET;;;; +300E;LEFT WHITE CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE CORNER BRACKET;;;; +300F;RIGHT WHITE CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE CORNER BRACKET;;;; +3010;LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING BLACK LENTICULAR BRACKET;;;; +3011;RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING BLACK LENTICULAR BRACKET;;;; +3012;POSTAL MARK;So;0;ON;;;;;N;;;;; +3013;GETA MARK;So;0;ON;;;;;N;;;;; +3014;LEFT TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING TORTOISE SHELL BRACKET;;;; +3015;RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING TORTOISE SHELL BRACKET;;;; +3016;LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE LENTICULAR BRACKET;;;; +3017;RIGHT WHITE LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE LENTICULAR BRACKET;;;; +3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE TORTOISE SHELL BRACKET;;;; +3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE TORTOISE SHELL BRACKET;;;; +301A;LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE SQUARE BRACKET;;;; +301B;RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE SQUARE BRACKET;;;; +301C;WAVE DASH;Pd;0;ON;;;;;N;;;;; +301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps;0;ON;;;;;N;;;;; +301E;DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;; +301F;LOW DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;; +3020;POSTAL MARK FACE;So;0;ON;;;;;N;;;;; +3021;HANGZHOU NUMERAL ONE;Nl;0;L;;;;1;N;;;;; +3022;HANGZHOU NUMERAL TWO;Nl;0;L;;;;2;N;;;;; +3023;HANGZHOU NUMERAL THREE;Nl;0;L;;;;3;N;;;;; +3024;HANGZHOU NUMERAL FOUR;Nl;0;L;;;;4;N;;;;; +3025;HANGZHOU NUMERAL FIVE;Nl;0;L;;;;5;N;;;;; +3026;HANGZHOU NUMERAL SIX;Nl;0;L;;;;6;N;;;;; +3027;HANGZHOU NUMERAL SEVEN;Nl;0;L;;;;7;N;;;;; +3028;HANGZHOU NUMERAL EIGHT;Nl;0;L;;;;8;N;;;;; +3029;HANGZHOU NUMERAL NINE;Nl;0;L;;;;9;N;;;;; +302A;IDEOGRAPHIC LEVEL TONE MARK;Mn;218;NSM;;;;;N;;;;; +302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;; +302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;; +302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;; +302E;HANGUL SINGLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;; +302F;HANGUL DOUBLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;; +3030;WAVY DASH;Pd;0;ON;;;;;N;;;;; +3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;; +3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;; +3033;VERTICAL KANA REPEAT MARK UPPER HALF;Lm;0;L;;;;;N;;;;; +3034;VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF;Lm;0;L;;;;;N;;;;; +3035;VERTICAL KANA REPEAT MARK LOWER HALF;Lm;0;L;;;;;N;;;;; +3036;CIRCLED POSTAL MARK;So;0;ON;<compat> 3012;;;;N;;;;; +3037;IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL;So;0;ON;;;;;N;;;;; +3038;HANGZHOU NUMERAL TEN;Nl;0;L;<compat> 5341;;;10;N;;;;; +3039;HANGZHOU NUMERAL TWENTY;Nl;0;L;<compat> 5344;;;20;N;;;;; +303A;HANGZHOU NUMERAL THIRTY;Nl;0;L;<compat> 5345;;;30;N;;;;; +303B;VERTICAL IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;; +303C;MASU MARK;Lo;0;L;;;;;N;;;;; +303D;PART ALTERNATION MARK;Po;0;ON;;;;;N;;;;; +303E;IDEOGRAPHIC VARIATION INDICATOR;So;0;ON;;;;;N;;;;; +303F;IDEOGRAPHIC HALF FILL SPACE;So;0;ON;;;;;N;;;;; +3041;HIRAGANA LETTER SMALL A;Lo;0;L;;;;;N;;;;; +3042;HIRAGANA LETTER A;Lo;0;L;;;;;N;;;;; +3043;HIRAGANA LETTER SMALL I;Lo;0;L;;;;;N;;;;; +3044;HIRAGANA LETTER I;Lo;0;L;;;;;N;;;;; +3045;HIRAGANA LETTER SMALL U;Lo;0;L;;;;;N;;;;; +3046;HIRAGANA LETTER U;Lo;0;L;;;;;N;;;;; +3047;HIRAGANA LETTER SMALL E;Lo;0;L;;;;;N;;;;; +3048;HIRAGANA LETTER E;Lo;0;L;;;;;N;;;;; +3049;HIRAGANA LETTER SMALL O;Lo;0;L;;;;;N;;;;; +304A;HIRAGANA LETTER O;Lo;0;L;;;;;N;;;;; +304B;HIRAGANA LETTER KA;Lo;0;L;;;;;N;;;;; +304C;HIRAGANA LETTER GA;Lo;0;L;304B 3099;;;;N;;;;; +304D;HIRAGANA LETTER KI;Lo;0;L;;;;;N;;;;; +304E;HIRAGANA LETTER GI;Lo;0;L;304D 3099;;;;N;;;;; +304F;HIRAGANA LETTER KU;Lo;0;L;;;;;N;;;;; +3050;HIRAGANA LETTER GU;Lo;0;L;304F 3099;;;;N;;;;; +3051;HIRAGANA LETTER KE;Lo;0;L;;;;;N;;;;; +3052;HIRAGANA LETTER GE;Lo;0;L;3051 3099;;;;N;;;;; +3053;HIRAGANA LETTER KO;Lo;0;L;;;;;N;;;;; +3054;HIRAGANA LETTER GO;Lo;0;L;3053 3099;;;;N;;;;; +3055;HIRAGANA LETTER SA;Lo;0;L;;;;;N;;;;; +3056;HIRAGANA LETTER ZA;Lo;0;L;3055 3099;;;;N;;;;; +3057;HIRAGANA LETTER SI;Lo;0;L;;;;;N;;;;; +3058;HIRAGANA LETTER ZI;Lo;0;L;3057 3099;;;;N;;;;; +3059;HIRAGANA LETTER SU;Lo;0;L;;;;;N;;;;; +305A;HIRAGANA LETTER ZU;Lo;0;L;3059 3099;;;;N;;;;; +305B;HIRAGANA LETTER SE;Lo;0;L;;;;;N;;;;; +305C;HIRAGANA LETTER ZE;Lo;0;L;305B 3099;;;;N;;;;; +305D;HIRAGANA LETTER SO;Lo;0;L;;;;;N;;;;; +305E;HIRAGANA LETTER ZO;Lo;0;L;305D 3099;;;;N;;;;; +305F;HIRAGANA LETTER TA;Lo;0;L;;;;;N;;;;; +3060;HIRAGANA LETTER DA;Lo;0;L;305F 3099;;;;N;;;;; +3061;HIRAGANA LETTER TI;Lo;0;L;;;;;N;;;;; +3062;HIRAGANA LETTER DI;Lo;0;L;3061 3099;;;;N;;;;; +3063;HIRAGANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;; +3064;HIRAGANA LETTER TU;Lo;0;L;;;;;N;;;;; +3065;HIRAGANA LETTER DU;Lo;0;L;3064 3099;;;;N;;;;; +3066;HIRAGANA LETTER TE;Lo;0;L;;;;;N;;;;; +3067;HIRAGANA LETTER DE;Lo;0;L;3066 3099;;;;N;;;;; +3068;HIRAGANA LETTER TO;Lo;0;L;;;;;N;;;;; +3069;HIRAGANA LETTER DO;Lo;0;L;3068 3099;;;;N;;;;; +306A;HIRAGANA LETTER NA;Lo;0;L;;;;;N;;;;; +306B;HIRAGANA LETTER NI;Lo;0;L;;;;;N;;;;; +306C;HIRAGANA LETTER NU;Lo;0;L;;;;;N;;;;; +306D;HIRAGANA LETTER NE;Lo;0;L;;;;;N;;;;; +306E;HIRAGANA LETTER NO;Lo;0;L;;;;;N;;;;; +306F;HIRAGANA LETTER HA;Lo;0;L;;;;;N;;;;; +3070;HIRAGANA LETTER BA;Lo;0;L;306F 3099;;;;N;;;;; +3071;HIRAGANA LETTER PA;Lo;0;L;306F 309A;;;;N;;;;; +3072;HIRAGANA LETTER HI;Lo;0;L;;;;;N;;;;; +3073;HIRAGANA LETTER BI;Lo;0;L;3072 3099;;;;N;;;;; +3074;HIRAGANA LETTER PI;Lo;0;L;3072 309A;;;;N;;;;; +3075;HIRAGANA LETTER HU;Lo;0;L;;;;;N;;;;; +3076;HIRAGANA LETTER BU;Lo;0;L;3075 3099;;;;N;;;;; +3077;HIRAGANA LETTER PU;Lo;0;L;3075 309A;;;;N;;;;; +3078;HIRAGANA LETTER HE;Lo;0;L;;;;;N;;;;; +3079;HIRAGANA LETTER BE;Lo;0;L;3078 3099;;;;N;;;;; +307A;HIRAGANA LETTER PE;Lo;0;L;3078 309A;;;;N;;;;; +307B;HIRAGANA LETTER HO;Lo;0;L;;;;;N;;;;; +307C;HIRAGANA LETTER BO;Lo;0;L;307B 3099;;;;N;;;;; +307D;HIRAGANA LETTER PO;Lo;0;L;307B 309A;;;;N;;;;; +307E;HIRAGANA LETTER MA;Lo;0;L;;;;;N;;;;; +307F;HIRAGANA LETTER MI;Lo;0;L;;;;;N;;;;; +3080;HIRAGANA LETTER MU;Lo;0;L;;;;;N;;;;; +3081;HIRAGANA LETTER ME;Lo;0;L;;;;;N;;;;; +3082;HIRAGANA LETTER MO;Lo;0;L;;;;;N;;;;; +3083;HIRAGANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;; +3084;HIRAGANA LETTER YA;Lo;0;L;;;;;N;;;;; +3085;HIRAGANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;; +3086;HIRAGANA LETTER YU;Lo;0;L;;;;;N;;;;; +3087;HIRAGANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;; +3088;HIRAGANA LETTER YO;Lo;0;L;;;;;N;;;;; +3089;HIRAGANA LETTER RA;Lo;0;L;;;;;N;;;;; +308A;HIRAGANA LETTER RI;Lo;0;L;;;;;N;;;;; +308B;HIRAGANA LETTER RU;Lo;0;L;;;;;N;;;;; +308C;HIRAGANA LETTER RE;Lo;0;L;;;;;N;;;;; +308D;HIRAGANA LETTER RO;Lo;0;L;;;;;N;;;;; +308E;HIRAGANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;; +308F;HIRAGANA LETTER WA;Lo;0;L;;;;;N;;;;; +3090;HIRAGANA LETTER WI;Lo;0;L;;;;;N;;;;; +3091;HIRAGANA LETTER WE;Lo;0;L;;;;;N;;;;; +3092;HIRAGANA LETTER WO;Lo;0;L;;;;;N;;;;; +3093;HIRAGANA LETTER N;Lo;0;L;;;;;N;;;;; +3094;HIRAGANA LETTER VU;Lo;0;L;3046 3099;;;;N;;;;; +3095;HIRAGANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;; +3096;HIRAGANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;; +3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA VOICED SOUND MARK;;;; +309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;;;; +309B;KATAKANA-HIRAGANA VOICED SOUND MARK;Sk;0;ON;<compat> 0020 3099;;;;N;;;;; +309C;KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Sk;0;ON;<compat> 0020 309A;;;;N;;;;; +309D;HIRAGANA ITERATION MARK;Lm;0;L;;;;;N;;;;; +309E;HIRAGANA VOICED ITERATION MARK;Lm;0;L;309D 3099;;;;N;;;;; +309F;HIRAGANA DIGRAPH YORI;Lo;0;L;<vertical> 3088 308A;;;;N;;;;; +30A0;KATAKANA-HIRAGANA DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;; +30A1;KATAKANA LETTER SMALL A;Lo;0;L;;;;;N;;;;; +30A2;KATAKANA LETTER A;Lo;0;L;;;;;N;;;;; +30A3;KATAKANA LETTER SMALL I;Lo;0;L;;;;;N;;;;; +30A4;KATAKANA LETTER I;Lo;0;L;;;;;N;;;;; +30A5;KATAKANA LETTER SMALL U;Lo;0;L;;;;;N;;;;; +30A6;KATAKANA LETTER U;Lo;0;L;;;;;N;;;;; +30A7;KATAKANA LETTER SMALL E;Lo;0;L;;;;;N;;;;; +30A8;KATAKANA LETTER E;Lo;0;L;;;;;N;;;;; +30A9;KATAKANA LETTER SMALL O;Lo;0;L;;;;;N;;;;; +30AA;KATAKANA LETTER O;Lo;0;L;;;;;N;;;;; +30AB;KATAKANA LETTER KA;Lo;0;L;;;;;N;;;;; +30AC;KATAKANA LETTER GA;Lo;0;L;30AB 3099;;;;N;;;;; +30AD;KATAKANA LETTER KI;Lo;0;L;;;;;N;;;;; +30AE;KATAKANA LETTER GI;Lo;0;L;30AD 3099;;;;N;;;;; +30AF;KATAKANA LETTER KU;Lo;0;L;;;;;N;;;;; +30B0;KATAKANA LETTER GU;Lo;0;L;30AF 3099;;;;N;;;;; +30B1;KATAKANA LETTER KE;Lo;0;L;;;;;N;;;;; +30B2;KATAKANA LETTER GE;Lo;0;L;30B1 3099;;;;N;;;;; +30B3;KATAKANA LETTER KO;Lo;0;L;;;;;N;;;;; +30B4;KATAKANA LETTER GO;Lo;0;L;30B3 3099;;;;N;;;;; +30B5;KATAKANA LETTER SA;Lo;0;L;;;;;N;;;;; +30B6;KATAKANA LETTER ZA;Lo;0;L;30B5 3099;;;;N;;;;; +30B7;KATAKANA LETTER SI;Lo;0;L;;;;;N;;;;; +30B8;KATAKANA LETTER ZI;Lo;0;L;30B7 3099;;;;N;;;;; +30B9;KATAKANA LETTER SU;Lo;0;L;;;;;N;;;;; +30BA;KATAKANA LETTER ZU;Lo;0;L;30B9 3099;;;;N;;;;; +30BB;KATAKANA LETTER SE;Lo;0;L;;;;;N;;;;; +30BC;KATAKANA LETTER ZE;Lo;0;L;30BB 3099;;;;N;;;;; +30BD;KATAKANA LETTER SO;Lo;0;L;;;;;N;;;;; +30BE;KATAKANA LETTER ZO;Lo;0;L;30BD 3099;;;;N;;;;; +30BF;KATAKANA LETTER TA;Lo;0;L;;;;;N;;;;; +30C0;KATAKANA LETTER DA;Lo;0;L;30BF 3099;;;;N;;;;; +30C1;KATAKANA LETTER TI;Lo;0;L;;;;;N;;;;; +30C2;KATAKANA LETTER DI;Lo;0;L;30C1 3099;;;;N;;;;; +30C3;KATAKANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;; +30C4;KATAKANA LETTER TU;Lo;0;L;;;;;N;;;;; +30C5;KATAKANA LETTER DU;Lo;0;L;30C4 3099;;;;N;;;;; +30C6;KATAKANA LETTER TE;Lo;0;L;;;;;N;;;;; +30C7;KATAKANA LETTER DE;Lo;0;L;30C6 3099;;;;N;;;;; +30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;; +30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;; +30CA;KATAKANA LETTER NA;Lo;0;L;;;;;N;;;;; +30CB;KATAKANA LETTER NI;Lo;0;L;;;;;N;;;;; +30CC;KATAKANA LETTER NU;Lo;0;L;;;;;N;;;;; +30CD;KATAKANA LETTER NE;Lo;0;L;;;;;N;;;;; +30CE;KATAKANA LETTER NO;Lo;0;L;;;;;N;;;;; +30CF;KATAKANA LETTER HA;Lo;0;L;;;;;N;;;;; +30D0;KATAKANA LETTER BA;Lo;0;L;30CF 3099;;;;N;;;;; +30D1;KATAKANA LETTER PA;Lo;0;L;30CF 309A;;;;N;;;;; +30D2;KATAKANA LETTER HI;Lo;0;L;;;;;N;;;;; +30D3;KATAKANA LETTER BI;Lo;0;L;30D2 3099;;;;N;;;;; +30D4;KATAKANA LETTER PI;Lo;0;L;30D2 309A;;;;N;;;;; +30D5;KATAKANA LETTER HU;Lo;0;L;;;;;N;;;;; +30D6;KATAKANA LETTER BU;Lo;0;L;30D5 3099;;;;N;;;;; +30D7;KATAKANA LETTER PU;Lo;0;L;30D5 309A;;;;N;;;;; +30D8;KATAKANA LETTER HE;Lo;0;L;;;;;N;;;;; +30D9;KATAKANA LETTER BE;Lo;0;L;30D8 3099;;;;N;;;;; +30DA;KATAKANA LETTER PE;Lo;0;L;30D8 309A;;;;N;;;;; +30DB;KATAKANA LETTER HO;Lo;0;L;;;;;N;;;;; +30DC;KATAKANA LETTER BO;Lo;0;L;30DB 3099;;;;N;;;;; +30DD;KATAKANA LETTER PO;Lo;0;L;30DB 309A;;;;N;;;;; +30DE;KATAKANA LETTER MA;Lo;0;L;;;;;N;;;;; +30DF;KATAKANA LETTER MI;Lo;0;L;;;;;N;;;;; +30E0;KATAKANA LETTER MU;Lo;0;L;;;;;N;;;;; +30E1;KATAKANA LETTER ME;Lo;0;L;;;;;N;;;;; +30E2;KATAKANA LETTER MO;Lo;0;L;;;;;N;;;;; +30E3;KATAKANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;; +30E4;KATAKANA LETTER YA;Lo;0;L;;;;;N;;;;; +30E5;KATAKANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;; +30E6;KATAKANA LETTER YU;Lo;0;L;;;;;N;;;;; +30E7;KATAKANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;; +30E8;KATAKANA LETTER YO;Lo;0;L;;;;;N;;;;; +30E9;KATAKANA LETTER RA;Lo;0;L;;;;;N;;;;; +30EA;KATAKANA LETTER RI;Lo;0;L;;;;;N;;;;; +30EB;KATAKANA LETTER RU;Lo;0;L;;;;;N;;;;; +30EC;KATAKANA LETTER RE;Lo;0;L;;;;;N;;;;; +30ED;KATAKANA LETTER RO;Lo;0;L;;;;;N;;;;; +30EE;KATAKANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;; +30EF;KATAKANA LETTER WA;Lo;0;L;;;;;N;;;;; +30F0;KATAKANA LETTER WI;Lo;0;L;;;;;N;;;;; +30F1;KATAKANA LETTER WE;Lo;0;L;;;;;N;;;;; +30F2;KATAKANA LETTER WO;Lo;0;L;;;;;N;;;;; +30F3;KATAKANA LETTER N;Lo;0;L;;;;;N;;;;; +30F4;KATAKANA LETTER VU;Lo;0;L;30A6 3099;;;;N;;;;; +30F5;KATAKANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;; +30F6;KATAKANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;; +30F7;KATAKANA LETTER VA;Lo;0;L;30EF 3099;;;;N;;;;; +30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;; +30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;; +30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;; +30FB;KATAKANA MIDDLE DOT;Pc;0;ON;;;;;N;;;;; +30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;; +30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;; +30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;; +30FF;KATAKANA DIGRAPH KOTO;Lo;0;L;<vertical> 30B3 30C8;;;;N;;;;; +3105;BOPOMOFO LETTER B;Lo;0;L;;;;;N;;;;; +3106;BOPOMOFO LETTER P;Lo;0;L;;;;;N;;;;; +3107;BOPOMOFO LETTER M;Lo;0;L;;;;;N;;;;; +3108;BOPOMOFO LETTER F;Lo;0;L;;;;;N;;;;; +3109;BOPOMOFO LETTER D;Lo;0;L;;;;;N;;;;; +310A;BOPOMOFO LETTER T;Lo;0;L;;;;;N;;;;; +310B;BOPOMOFO LETTER N;Lo;0;L;;;;;N;;;;; +310C;BOPOMOFO LETTER L;Lo;0;L;;;;;N;;;;; +310D;BOPOMOFO LETTER G;Lo;0;L;;;;;N;;;;; +310E;BOPOMOFO LETTER K;Lo;0;L;;;;;N;;;;; +310F;BOPOMOFO LETTER H;Lo;0;L;;;;;N;;;;; +3110;BOPOMOFO LETTER J;Lo;0;L;;;;;N;;;;; +3111;BOPOMOFO LETTER Q;Lo;0;L;;;;;N;;;;; +3112;BOPOMOFO LETTER X;Lo;0;L;;;;;N;;;;; +3113;BOPOMOFO LETTER ZH;Lo;0;L;;;;;N;;;;; +3114;BOPOMOFO LETTER CH;Lo;0;L;;;;;N;;;;; +3115;BOPOMOFO LETTER SH;Lo;0;L;;;;;N;;;;; +3116;BOPOMOFO LETTER R;Lo;0;L;;;;;N;;;;; +3117;BOPOMOFO LETTER Z;Lo;0;L;;;;;N;;;;; +3118;BOPOMOFO LETTER C;Lo;0;L;;;;;N;;;;; +3119;BOPOMOFO LETTER S;Lo;0;L;;;;;N;;;;; +311A;BOPOMOFO LETTER A;Lo;0;L;;;;;N;;;;; +311B;BOPOMOFO LETTER O;Lo;0;L;;;;;N;;;;; +311C;BOPOMOFO LETTER E;Lo;0;L;;;;;N;;;;; +311D;BOPOMOFO LETTER EH;Lo;0;L;;;;;N;;;;; +311E;BOPOMOFO LETTER AI;Lo;0;L;;;;;N;;;;; +311F;BOPOMOFO LETTER EI;Lo;0;L;;;;;N;;;;; +3120;BOPOMOFO LETTER AU;Lo;0;L;;;;;N;;;;; +3121;BOPOMOFO LETTER OU;Lo;0;L;;;;;N;;;;; +3122;BOPOMOFO LETTER AN;Lo;0;L;;;;;N;;;;; +3123;BOPOMOFO LETTER EN;Lo;0;L;;;;;N;;;;; +3124;BOPOMOFO LETTER ANG;Lo;0;L;;;;;N;;;;; +3125;BOPOMOFO LETTER ENG;Lo;0;L;;;;;N;;;;; +3126;BOPOMOFO LETTER ER;Lo;0;L;;;;;N;;;;; +3127;BOPOMOFO LETTER I;Lo;0;L;;;;;N;;;;; +3128;BOPOMOFO LETTER U;Lo;0;L;;;;;N;;;;; +3129;BOPOMOFO LETTER IU;Lo;0;L;;;;;N;;;;; +312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;; +312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;; +312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;; +3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;; +3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;; +3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;; +3134;HANGUL LETTER NIEUN;Lo;0;L;<compat> 1102;;;;N;;;;; +3135;HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<compat> 11AC;;;;N;HANGUL LETTER NIEUN JIEUJ;;;; +3136;HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<compat> 11AD;;;;N;HANGUL LETTER NIEUN HIEUH;;;; +3137;HANGUL LETTER TIKEUT;Lo;0;L;<compat> 1103;;;;N;HANGUL LETTER DIGEUD;;;; +3138;HANGUL LETTER SSANGTIKEUT;Lo;0;L;<compat> 1104;;;;N;HANGUL LETTER SSANG DIGEUD;;;; +3139;HANGUL LETTER RIEUL;Lo;0;L;<compat> 1105;;;;N;HANGUL LETTER LIEUL;;;; +313A;HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<compat> 11B0;;;;N;HANGUL LETTER LIEUL GIYEOG;;;; +313B;HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<compat> 11B1;;;;N;HANGUL LETTER LIEUL MIEUM;;;; +313C;HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<compat> 11B2;;;;N;HANGUL LETTER LIEUL BIEUB;;;; +313D;HANGUL LETTER RIEUL-SIOS;Lo;0;L;<compat> 11B3;;;;N;HANGUL LETTER LIEUL SIOS;;;; +313E;HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<compat> 11B4;;;;N;HANGUL LETTER LIEUL TIEUT;;;; +313F;HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<compat> 11B5;;;;N;HANGUL LETTER LIEUL PIEUP;;;; +3140;HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<compat> 111A;;;;N;HANGUL LETTER LIEUL HIEUH;;;; +3141;HANGUL LETTER MIEUM;Lo;0;L;<compat> 1106;;;;N;;;;; +3142;HANGUL LETTER PIEUP;Lo;0;L;<compat> 1107;;;;N;HANGUL LETTER BIEUB;;;; +3143;HANGUL LETTER SSANGPIEUP;Lo;0;L;<compat> 1108;;;;N;HANGUL LETTER SSANG BIEUB;;;; +3144;HANGUL LETTER PIEUP-SIOS;Lo;0;L;<compat> 1121;;;;N;HANGUL LETTER BIEUB SIOS;;;; +3145;HANGUL LETTER SIOS;Lo;0;L;<compat> 1109;;;;N;;;;; +3146;HANGUL LETTER SSANGSIOS;Lo;0;L;<compat> 110A;;;;N;HANGUL LETTER SSANG SIOS;;;; +3147;HANGUL LETTER IEUNG;Lo;0;L;<compat> 110B;;;;N;;;;; +3148;HANGUL LETTER CIEUC;Lo;0;L;<compat> 110C;;;;N;HANGUL LETTER JIEUJ;;;; +3149;HANGUL LETTER SSANGCIEUC;Lo;0;L;<compat> 110D;;;;N;HANGUL LETTER SSANG JIEUJ;;;; +314A;HANGUL LETTER CHIEUCH;Lo;0;L;<compat> 110E;;;;N;HANGUL LETTER CIEUC;;;; +314B;HANGUL LETTER KHIEUKH;Lo;0;L;<compat> 110F;;;;N;HANGUL LETTER KIYEOK;;;; +314C;HANGUL LETTER THIEUTH;Lo;0;L;<compat> 1110;;;;N;HANGUL LETTER TIEUT;;;; +314D;HANGUL LETTER PHIEUPH;Lo;0;L;<compat> 1111;;;;N;HANGUL LETTER PIEUP;;;; +314E;HANGUL LETTER HIEUH;Lo;0;L;<compat> 1112;;;;N;;;;; +314F;HANGUL LETTER A;Lo;0;L;<compat> 1161;;;;N;;;;; +3150;HANGUL LETTER AE;Lo;0;L;<compat> 1162;;;;N;;;;; +3151;HANGUL LETTER YA;Lo;0;L;<compat> 1163;;;;N;;;;; +3152;HANGUL LETTER YAE;Lo;0;L;<compat> 1164;;;;N;;;;; +3153;HANGUL LETTER EO;Lo;0;L;<compat> 1165;;;;N;;;;; +3154;HANGUL LETTER E;Lo;0;L;<compat> 1166;;;;N;;;;; +3155;HANGUL LETTER YEO;Lo;0;L;<compat> 1167;;;;N;;;;; +3156;HANGUL LETTER YE;Lo;0;L;<compat> 1168;;;;N;;;;; +3157;HANGUL LETTER O;Lo;0;L;<compat> 1169;;;;N;;;;; +3158;HANGUL LETTER WA;Lo;0;L;<compat> 116A;;;;N;;;;; +3159;HANGUL LETTER WAE;Lo;0;L;<compat> 116B;;;;N;;;;; +315A;HANGUL LETTER OE;Lo;0;L;<compat> 116C;;;;N;;;;; +315B;HANGUL LETTER YO;Lo;0;L;<compat> 116D;;;;N;;;;; +315C;HANGUL LETTER U;Lo;0;L;<compat> 116E;;;;N;;;;; +315D;HANGUL LETTER WEO;Lo;0;L;<compat> 116F;;;;N;;;;; +315E;HANGUL LETTER WE;Lo;0;L;<compat> 1170;;;;N;;;;; +315F;HANGUL LETTER WI;Lo;0;L;<compat> 1171;;;;N;;;;; +3160;HANGUL LETTER YU;Lo;0;L;<compat> 1172;;;;N;;;;; +3161;HANGUL LETTER EU;Lo;0;L;<compat> 1173;;;;N;;;;; +3162;HANGUL LETTER YI;Lo;0;L;<compat> 1174;;;;N;;;;; +3163;HANGUL LETTER I;Lo;0;L;<compat> 1175;;;;N;;;;; +3164;HANGUL FILLER;Lo;0;L;<compat> 1160;;;;N;HANGUL CAE OM;;;; +3165;HANGUL LETTER SSANGNIEUN;Lo;0;L;<compat> 1114;;;;N;HANGUL LETTER SSANG NIEUN;;;; +3166;HANGUL LETTER NIEUN-TIKEUT;Lo;0;L;<compat> 1115;;;;N;HANGUL LETTER NIEUN DIGEUD;;;; +3167;HANGUL LETTER NIEUN-SIOS;Lo;0;L;<compat> 11C7;;;;N;HANGUL LETTER NIEUN SIOS;;;; +3168;HANGUL LETTER NIEUN-PANSIOS;Lo;0;L;<compat> 11C8;;;;N;HANGUL LETTER NIEUN BAN CHI EUM;;;; +3169;HANGUL LETTER RIEUL-KIYEOK-SIOS;Lo;0;L;<compat> 11CC;;;;N;HANGUL LETTER LIEUL GIYEOG SIOS;;;; +316A;HANGUL LETTER RIEUL-TIKEUT;Lo;0;L;<compat> 11CE;;;;N;HANGUL LETTER LIEUL DIGEUD;;;; +316B;HANGUL LETTER RIEUL-PIEUP-SIOS;Lo;0;L;<compat> 11D3;;;;N;HANGUL LETTER LIEUL BIEUB SIOS;;;; +316C;HANGUL LETTER RIEUL-PANSIOS;Lo;0;L;<compat> 11D7;;;;N;HANGUL LETTER LIEUL BAN CHI EUM;;;; +316D;HANGUL LETTER RIEUL-YEORINHIEUH;Lo;0;L;<compat> 11D9;;;;N;HANGUL LETTER LIEUL YEOLIN HIEUH;;;; +316E;HANGUL LETTER MIEUM-PIEUP;Lo;0;L;<compat> 111C;;;;N;HANGUL LETTER MIEUM BIEUB;;;; +316F;HANGUL LETTER MIEUM-SIOS;Lo;0;L;<compat> 11DD;;;;N;HANGUL LETTER MIEUM SIOS;;;; +3170;HANGUL LETTER MIEUM-PANSIOS;Lo;0;L;<compat> 11DF;;;;N;HANGUL LETTER BIEUB BAN CHI EUM;;;; +3171;HANGUL LETTER KAPYEOUNMIEUM;Lo;0;L;<compat> 111D;;;;N;HANGUL LETTER MIEUM SUN GYEONG EUM;;;; +3172;HANGUL LETTER PIEUP-KIYEOK;Lo;0;L;<compat> 111E;;;;N;HANGUL LETTER BIEUB GIYEOG;;;; +3173;HANGUL LETTER PIEUP-TIKEUT;Lo;0;L;<compat> 1120;;;;N;HANGUL LETTER BIEUB DIGEUD;;;; +3174;HANGUL LETTER PIEUP-SIOS-KIYEOK;Lo;0;L;<compat> 1122;;;;N;HANGUL LETTER BIEUB SIOS GIYEOG;;;; +3175;HANGUL LETTER PIEUP-SIOS-TIKEUT;Lo;0;L;<compat> 1123;;;;N;HANGUL LETTER BIEUB SIOS DIGEUD;;;; +3176;HANGUL LETTER PIEUP-CIEUC;Lo;0;L;<compat> 1127;;;;N;HANGUL LETTER BIEUB JIEUJ;;;; +3177;HANGUL LETTER PIEUP-THIEUTH;Lo;0;L;<compat> 1129;;;;N;HANGUL LETTER BIEUB TIEUT;;;; +3178;HANGUL LETTER KAPYEOUNPIEUP;Lo;0;L;<compat> 112B;;;;N;HANGUL LETTER BIEUB SUN GYEONG EUM;;;; +3179;HANGUL LETTER KAPYEOUNSSANGPIEUP;Lo;0;L;<compat> 112C;;;;N;HANGUL LETTER SSANG BIEUB SUN GYEONG EUM;;;; +317A;HANGUL LETTER SIOS-KIYEOK;Lo;0;L;<compat> 112D;;;;N;HANGUL LETTER SIOS GIYEOG;;;; +317B;HANGUL LETTER SIOS-NIEUN;Lo;0;L;<compat> 112E;;;;N;HANGUL LETTER SIOS NIEUN;;;; +317C;HANGUL LETTER SIOS-TIKEUT;Lo;0;L;<compat> 112F;;;;N;HANGUL LETTER SIOS DIGEUD;;;; +317D;HANGUL LETTER SIOS-PIEUP;Lo;0;L;<compat> 1132;;;;N;HANGUL LETTER SIOS BIEUB;;;; +317E;HANGUL LETTER SIOS-CIEUC;Lo;0;L;<compat> 1136;;;;N;HANGUL LETTER SIOS JIEUJ;;;; +317F;HANGUL LETTER PANSIOS;Lo;0;L;<compat> 1140;;;;N;HANGUL LETTER BAN CHI EUM;;;; +3180;HANGUL LETTER SSANGIEUNG;Lo;0;L;<compat> 1147;;;;N;HANGUL LETTER SSANG IEUNG;;;; +3181;HANGUL LETTER YESIEUNG;Lo;0;L;<compat> 114C;;;;N;HANGUL LETTER NGIEUNG;;;; +3182;HANGUL LETTER YESIEUNG-SIOS;Lo;0;L;<compat> 11F1;;;;N;HANGUL LETTER NGIEUNG SIOS;;;; +3183;HANGUL LETTER YESIEUNG-PANSIOS;Lo;0;L;<compat> 11F2;;;;N;HANGUL LETTER NGIEUNG BAN CHI EUM;;;; +3184;HANGUL LETTER KAPYEOUNPHIEUPH;Lo;0;L;<compat> 1157;;;;N;HANGUL LETTER PIEUP SUN GYEONG EUM;;;; +3185;HANGUL LETTER SSANGHIEUH;Lo;0;L;<compat> 1158;;;;N;HANGUL LETTER SSANG HIEUH;;;; +3186;HANGUL LETTER YEORINHIEUH;Lo;0;L;<compat> 1159;;;;N;HANGUL LETTER YEOLIN HIEUH;;;; +3187;HANGUL LETTER YO-YA;Lo;0;L;<compat> 1184;;;;N;HANGUL LETTER YOYA;;;; +3188;HANGUL LETTER YO-YAE;Lo;0;L;<compat> 1185;;;;N;HANGUL LETTER YOYAE;;;; +3189;HANGUL LETTER YO-I;Lo;0;L;<compat> 1188;;;;N;HANGUL LETTER YOI;;;; +318A;HANGUL LETTER YU-YEO;Lo;0;L;<compat> 1191;;;;N;HANGUL LETTER YUYEO;;;; +318B;HANGUL LETTER YU-YE;Lo;0;L;<compat> 1192;;;;N;HANGUL LETTER YUYE;;;; +318C;HANGUL LETTER YU-I;Lo;0;L;<compat> 1194;;;;N;HANGUL LETTER YUI;;;; +318D;HANGUL LETTER ARAEA;Lo;0;L;<compat> 119E;;;;N;HANGUL LETTER ALAE A;;;; +318E;HANGUL LETTER ARAEAE;Lo;0;L;<compat> 11A1;;;;N;HANGUL LETTER ALAE AE;;;; +3190;IDEOGRAPHIC ANNOTATION LINKING MARK;So;0;L;;;;;N;KANBUN TATETEN;Kanbun Tateten;;; +3191;IDEOGRAPHIC ANNOTATION REVERSE MARK;So;0;L;;;;;N;KAERITEN RE;Kaeriten;;; +3192;IDEOGRAPHIC ANNOTATION ONE MARK;No;0;L;<super> 4E00;;;1;N;KAERITEN ITI;Kaeriten;;; +3193;IDEOGRAPHIC ANNOTATION TWO MARK;No;0;L;<super> 4E8C;;;2;N;KAERITEN NI;Kaeriten;;; +3194;IDEOGRAPHIC ANNOTATION THREE MARK;No;0;L;<super> 4E09;;;3;N;KAERITEN SAN;Kaeriten;;; +3195;IDEOGRAPHIC ANNOTATION FOUR MARK;No;0;L;<super> 56DB;;;4;N;KAERITEN SI;Kaeriten;;; +3196;IDEOGRAPHIC ANNOTATION TOP MARK;So;0;L;<super> 4E0A;;;;N;KAERITEN ZYOU;Kaeriten;;; +3197;IDEOGRAPHIC ANNOTATION MIDDLE MARK;So;0;L;<super> 4E2D;;;;N;KAERITEN TYUU;Kaeriten;;; +3198;IDEOGRAPHIC ANNOTATION BOTTOM MARK;So;0;L;<super> 4E0B;;;;N;KAERITEN GE;Kaeriten;;; +3199;IDEOGRAPHIC ANNOTATION FIRST MARK;So;0;L;<super> 7532;;;;N;KAERITEN KOU;Kaeriten;;; +319A;IDEOGRAPHIC ANNOTATION SECOND MARK;So;0;L;<super> 4E59;;;;N;KAERITEN OTU;Kaeriten;;; +319B;IDEOGRAPHIC ANNOTATION THIRD MARK;So;0;L;<super> 4E19;;;;N;KAERITEN HEI;Kaeriten;;; +319C;IDEOGRAPHIC ANNOTATION FOURTH MARK;So;0;L;<super> 4E01;;;;N;KAERITEN TEI;Kaeriten;;; +319D;IDEOGRAPHIC ANNOTATION HEAVEN MARK;So;0;L;<super> 5929;;;;N;KAERITEN TEN;Kaeriten;;; +319E;IDEOGRAPHIC ANNOTATION EARTH MARK;So;0;L;<super> 5730;;;;N;KAERITEN TI;Kaeriten;;; +319F;IDEOGRAPHIC ANNOTATION MAN MARK;So;0;L;<super> 4EBA;;;;N;KAERITEN ZIN;Kaeriten;;; +31A0;BOPOMOFO LETTER BU;Lo;0;L;;;;;N;;;;; +31A1;BOPOMOFO LETTER ZI;Lo;0;L;;;;;N;;;;; +31A2;BOPOMOFO LETTER JI;Lo;0;L;;;;;N;;;;; +31A3;BOPOMOFO LETTER GU;Lo;0;L;;;;;N;;;;; +31A4;BOPOMOFO LETTER EE;Lo;0;L;;;;;N;;;;; +31A5;BOPOMOFO LETTER ENN;Lo;0;L;;;;;N;;;;; +31A6;BOPOMOFO LETTER OO;Lo;0;L;;;;;N;;;;; +31A7;BOPOMOFO LETTER ONN;Lo;0;L;;;;;N;;;;; +31A8;BOPOMOFO LETTER IR;Lo;0;L;;;;;N;;;;; +31A9;BOPOMOFO LETTER ANN;Lo;0;L;;;;;N;;;;; +31AA;BOPOMOFO LETTER INN;Lo;0;L;;;;;N;;;;; +31AB;BOPOMOFO LETTER UNN;Lo;0;L;;;;;N;;;;; +31AC;BOPOMOFO LETTER IM;Lo;0;L;;;;;N;;;;; +31AD;BOPOMOFO LETTER NGG;Lo;0;L;;;;;N;;;;; +31AE;BOPOMOFO LETTER AINN;Lo;0;L;;;;;N;;;;; +31AF;BOPOMOFO LETTER AUNN;Lo;0;L;;;;;N;;;;; +31B0;BOPOMOFO LETTER AM;Lo;0;L;;;;;N;;;;; +31B1;BOPOMOFO LETTER OM;Lo;0;L;;;;;N;;;;; +31B2;BOPOMOFO LETTER ONG;Lo;0;L;;;;;N;;;;; +31B3;BOPOMOFO LETTER INNN;Lo;0;L;;;;;N;;;;; +31B4;BOPOMOFO FINAL LETTER P;Lo;0;L;;;;;N;;;;; +31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;; +31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;; +31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;; +31F0;KATAKANA LETTER SMALL KU;Lo;0;L;;;;;N;;;;; +31F1;KATAKANA LETTER SMALL SI;Lo;0;L;;;;;N;;;;; +31F2;KATAKANA LETTER SMALL SU;Lo;0;L;;;;;N;;;;; +31F3;KATAKANA LETTER SMALL TO;Lo;0;L;;;;;N;;;;; +31F4;KATAKANA LETTER SMALL NU;Lo;0;L;;;;;N;;;;; +31F5;KATAKANA LETTER SMALL HA;Lo;0;L;;;;;N;;;;; +31F6;KATAKANA LETTER SMALL HI;Lo;0;L;;;;;N;;;;; +31F7;KATAKANA LETTER SMALL HU;Lo;0;L;;;;;N;;;;; +31F8;KATAKANA LETTER SMALL HE;Lo;0;L;;;;;N;;;;; +31F9;KATAKANA LETTER SMALL HO;Lo;0;L;;;;;N;;;;; +31FA;KATAKANA LETTER SMALL MU;Lo;0;L;;;;;N;;;;; +31FB;KATAKANA LETTER SMALL RA;Lo;0;L;;;;;N;;;;; +31FC;KATAKANA LETTER SMALL RI;Lo;0;L;;;;;N;;;;; +31FD;KATAKANA LETTER SMALL RU;Lo;0;L;;;;;N;;;;; +31FE;KATAKANA LETTER SMALL RE;Lo;0;L;;;;;N;;;;; +31FF;KATAKANA LETTER SMALL RO;Lo;0;L;;;;;N;;;;; +3200;PARENTHESIZED HANGUL KIYEOK;So;0;L;<compat> 0028 1100 0029;;;;N;PARENTHESIZED HANGUL GIYEOG;;;; +3201;PARENTHESIZED HANGUL NIEUN;So;0;L;<compat> 0028 1102 0029;;;;N;;;;; +3202;PARENTHESIZED HANGUL TIKEUT;So;0;L;<compat> 0028 1103 0029;;;;N;PARENTHESIZED HANGUL DIGEUD;;;; +3203;PARENTHESIZED HANGUL RIEUL;So;0;L;<compat> 0028 1105 0029;;;;N;PARENTHESIZED HANGUL LIEUL;;;; +3204;PARENTHESIZED HANGUL MIEUM;So;0;L;<compat> 0028 1106 0029;;;;N;;;;; +3205;PARENTHESIZED HANGUL PIEUP;So;0;L;<compat> 0028 1107 0029;;;;N;PARENTHESIZED HANGUL BIEUB;;;; +3206;PARENTHESIZED HANGUL SIOS;So;0;L;<compat> 0028 1109 0029;;;;N;;;;; +3207;PARENTHESIZED HANGUL IEUNG;So;0;L;<compat> 0028 110B 0029;;;;N;;;;; +3208;PARENTHESIZED HANGUL CIEUC;So;0;L;<compat> 0028 110C 0029;;;;N;PARENTHESIZED HANGUL JIEUJ;;;; +3209;PARENTHESIZED HANGUL CHIEUCH;So;0;L;<compat> 0028 110E 0029;;;;N;PARENTHESIZED HANGUL CIEUC;;;; +320A;PARENTHESIZED HANGUL KHIEUKH;So;0;L;<compat> 0028 110F 0029;;;;N;PARENTHESIZED HANGUL KIYEOK;;;; +320B;PARENTHESIZED HANGUL THIEUTH;So;0;L;<compat> 0028 1110 0029;;;;N;PARENTHESIZED HANGUL TIEUT;;;; +320C;PARENTHESIZED HANGUL PHIEUPH;So;0;L;<compat> 0028 1111 0029;;;;N;PARENTHESIZED HANGUL PIEUP;;;; +320D;PARENTHESIZED HANGUL HIEUH;So;0;L;<compat> 0028 1112 0029;;;;N;;;;; +320E;PARENTHESIZED HANGUL KIYEOK A;So;0;L;<compat> 0028 1100 1161 0029;;;;N;PARENTHESIZED HANGUL GA;;;; +320F;PARENTHESIZED HANGUL NIEUN A;So;0;L;<compat> 0028 1102 1161 0029;;;;N;PARENTHESIZED HANGUL NA;;;; +3210;PARENTHESIZED HANGUL TIKEUT A;So;0;L;<compat> 0028 1103 1161 0029;;;;N;PARENTHESIZED HANGUL DA;;;; +3211;PARENTHESIZED HANGUL RIEUL A;So;0;L;<compat> 0028 1105 1161 0029;;;;N;PARENTHESIZED HANGUL LA;;;; +3212;PARENTHESIZED HANGUL MIEUM A;So;0;L;<compat> 0028 1106 1161 0029;;;;N;PARENTHESIZED HANGUL MA;;;; +3213;PARENTHESIZED HANGUL PIEUP A;So;0;L;<compat> 0028 1107 1161 0029;;;;N;PARENTHESIZED HANGUL BA;;;; +3214;PARENTHESIZED HANGUL SIOS A;So;0;L;<compat> 0028 1109 1161 0029;;;;N;PARENTHESIZED HANGUL SA;;;; +3215;PARENTHESIZED HANGUL IEUNG A;So;0;L;<compat> 0028 110B 1161 0029;;;;N;PARENTHESIZED HANGUL A;;;; +3216;PARENTHESIZED HANGUL CIEUC A;So;0;L;<compat> 0028 110C 1161 0029;;;;N;PARENTHESIZED HANGUL JA;;;; +3217;PARENTHESIZED HANGUL CHIEUCH A;So;0;L;<compat> 0028 110E 1161 0029;;;;N;PARENTHESIZED HANGUL CA;;;; +3218;PARENTHESIZED HANGUL KHIEUKH A;So;0;L;<compat> 0028 110F 1161 0029;;;;N;PARENTHESIZED HANGUL KA;;;; +3219;PARENTHESIZED HANGUL THIEUTH A;So;0;L;<compat> 0028 1110 1161 0029;;;;N;PARENTHESIZED HANGUL TA;;;; +321A;PARENTHESIZED HANGUL PHIEUPH A;So;0;L;<compat> 0028 1111 1161 0029;;;;N;PARENTHESIZED HANGUL PA;;;; +321B;PARENTHESIZED HANGUL HIEUH A;So;0;L;<compat> 0028 1112 1161 0029;;;;N;PARENTHESIZED HANGUL HA;;;; +321C;PARENTHESIZED HANGUL CIEUC U;So;0;L;<compat> 0028 110C 116E 0029;;;;N;PARENTHESIZED HANGUL JU;;;; +321D;PARENTHESIZED KOREAN CHARACTER OJEON;So;0;ON;<compat> 0028 110B 1169 110C 1165 11AB 0029;;;;N;;;;; +321E;PARENTHESIZED KOREAN CHARACTER O HU;So;0;ON;<compat> 0028 110B 1169 1112 116E 0029;;;;N;;;;; +3220;PARENTHESIZED IDEOGRAPH ONE;No;0;L;<compat> 0028 4E00 0029;;;1;N;;;;; +3221;PARENTHESIZED IDEOGRAPH TWO;No;0;L;<compat> 0028 4E8C 0029;;;2;N;;;;; +3222;PARENTHESIZED IDEOGRAPH THREE;No;0;L;<compat> 0028 4E09 0029;;;3;N;;;;; +3223;PARENTHESIZED IDEOGRAPH FOUR;No;0;L;<compat> 0028 56DB 0029;;;4;N;;;;; +3224;PARENTHESIZED IDEOGRAPH FIVE;No;0;L;<compat> 0028 4E94 0029;;;5;N;;;;; +3225;PARENTHESIZED IDEOGRAPH SIX;No;0;L;<compat> 0028 516D 0029;;;6;N;;;;; +3226;PARENTHESIZED IDEOGRAPH SEVEN;No;0;L;<compat> 0028 4E03 0029;;;7;N;;;;; +3227;PARENTHESIZED IDEOGRAPH EIGHT;No;0;L;<compat> 0028 516B 0029;;;8;N;;;;; +3228;PARENTHESIZED IDEOGRAPH NINE;No;0;L;<compat> 0028 4E5D 0029;;;9;N;;;;; +3229;PARENTHESIZED IDEOGRAPH TEN;No;0;L;<compat> 0028 5341 0029;;;10;N;;;;; +322A;PARENTHESIZED IDEOGRAPH MOON;So;0;L;<compat> 0028 6708 0029;;;;N;;;;; +322B;PARENTHESIZED IDEOGRAPH FIRE;So;0;L;<compat> 0028 706B 0029;;;;N;;;;; +322C;PARENTHESIZED IDEOGRAPH WATER;So;0;L;<compat> 0028 6C34 0029;;;;N;;;;; +322D;PARENTHESIZED IDEOGRAPH WOOD;So;0;L;<compat> 0028 6728 0029;;;;N;;;;; +322E;PARENTHESIZED IDEOGRAPH METAL;So;0;L;<compat> 0028 91D1 0029;;;;N;;;;; +322F;PARENTHESIZED IDEOGRAPH EARTH;So;0;L;<compat> 0028 571F 0029;;;;N;;;;; +3230;PARENTHESIZED IDEOGRAPH SUN;So;0;L;<compat> 0028 65E5 0029;;;;N;;;;; +3231;PARENTHESIZED IDEOGRAPH STOCK;So;0;L;<compat> 0028 682A 0029;;;;N;;;;; +3232;PARENTHESIZED IDEOGRAPH HAVE;So;0;L;<compat> 0028 6709 0029;;;;N;;;;; +3233;PARENTHESIZED IDEOGRAPH SOCIETY;So;0;L;<compat> 0028 793E 0029;;;;N;;;;; +3234;PARENTHESIZED IDEOGRAPH NAME;So;0;L;<compat> 0028 540D 0029;;;;N;;;;; +3235;PARENTHESIZED IDEOGRAPH SPECIAL;So;0;L;<compat> 0028 7279 0029;;;;N;;;;; +3236;PARENTHESIZED IDEOGRAPH FINANCIAL;So;0;L;<compat> 0028 8CA1 0029;;;;N;;;;; +3237;PARENTHESIZED IDEOGRAPH CONGRATULATION;So;0;L;<compat> 0028 795D 0029;;;;N;;;;; +3238;PARENTHESIZED IDEOGRAPH LABOR;So;0;L;<compat> 0028 52B4 0029;;;;N;;;;; +3239;PARENTHESIZED IDEOGRAPH REPRESENT;So;0;L;<compat> 0028 4EE3 0029;;;;N;;;;; +323A;PARENTHESIZED IDEOGRAPH CALL;So;0;L;<compat> 0028 547C 0029;;;;N;;;;; +323B;PARENTHESIZED IDEOGRAPH STUDY;So;0;L;<compat> 0028 5B66 0029;;;;N;;;;; +323C;PARENTHESIZED IDEOGRAPH SUPERVISE;So;0;L;<compat> 0028 76E3 0029;;;;N;;;;; +323D;PARENTHESIZED IDEOGRAPH ENTERPRISE;So;0;L;<compat> 0028 4F01 0029;;;;N;;;;; +323E;PARENTHESIZED IDEOGRAPH RESOURCE;So;0;L;<compat> 0028 8CC7 0029;;;;N;;;;; +323F;PARENTHESIZED IDEOGRAPH ALLIANCE;So;0;L;<compat> 0028 5354 0029;;;;N;;;;; +3240;PARENTHESIZED IDEOGRAPH FESTIVAL;So;0;L;<compat> 0028 796D 0029;;;;N;;;;; +3241;PARENTHESIZED IDEOGRAPH REST;So;0;L;<compat> 0028 4F11 0029;;;;N;;;;; +3242;PARENTHESIZED IDEOGRAPH SELF;So;0;L;<compat> 0028 81EA 0029;;;;N;;;;; +3243;PARENTHESIZED IDEOGRAPH REACH;So;0;L;<compat> 0028 81F3 0029;;;;N;;;;; +3250;PARTNERSHIP SIGN;So;0;ON;<square> 0050 0054 0045;;;;N;;;;; +3251;CIRCLED NUMBER TWENTY ONE;No;0;ON;<circle> 0032 0031;;;21;N;;;;; +3252;CIRCLED NUMBER TWENTY TWO;No;0;ON;<circle> 0032 0032;;;22;N;;;;; +3253;CIRCLED NUMBER TWENTY THREE;No;0;ON;<circle> 0032 0033;;;23;N;;;;; +3254;CIRCLED NUMBER TWENTY FOUR;No;0;ON;<circle> 0032 0034;;;24;N;;;;; +3255;CIRCLED NUMBER TWENTY FIVE;No;0;ON;<circle> 0032 0035;;;25;N;;;;; +3256;CIRCLED NUMBER TWENTY SIX;No;0;ON;<circle> 0032 0036;;;26;N;;;;; +3257;CIRCLED NUMBER TWENTY SEVEN;No;0;ON;<circle> 0032 0037;;;27;N;;;;; +3258;CIRCLED NUMBER TWENTY EIGHT;No;0;ON;<circle> 0032 0038;;;28;N;;;;; +3259;CIRCLED NUMBER TWENTY NINE;No;0;ON;<circle> 0032 0039;;;29;N;;;;; +325A;CIRCLED NUMBER THIRTY;No;0;ON;<circle> 0033 0030;;;30;N;;;;; +325B;CIRCLED NUMBER THIRTY ONE;No;0;ON;<circle> 0033 0031;;;31;N;;;;; +325C;CIRCLED NUMBER THIRTY TWO;No;0;ON;<circle> 0033 0032;;;32;N;;;;; +325D;CIRCLED NUMBER THIRTY THREE;No;0;ON;<circle> 0033 0033;;;33;N;;;;; +325E;CIRCLED NUMBER THIRTY FOUR;No;0;ON;<circle> 0033 0034;;;34;N;;;;; +325F;CIRCLED NUMBER THIRTY FIVE;No;0;ON;<circle> 0033 0035;;;35;N;;;;; +3260;CIRCLED HANGUL KIYEOK;So;0;L;<circle> 1100;;;;N;CIRCLED HANGUL GIYEOG;;;; +3261;CIRCLED HANGUL NIEUN;So;0;L;<circle> 1102;;;;N;;;;; +3262;CIRCLED HANGUL TIKEUT;So;0;L;<circle> 1103;;;;N;CIRCLED HANGUL DIGEUD;;;; +3263;CIRCLED HANGUL RIEUL;So;0;L;<circle> 1105;;;;N;CIRCLED HANGUL LIEUL;;;; +3264;CIRCLED HANGUL MIEUM;So;0;L;<circle> 1106;;;;N;;;;; +3265;CIRCLED HANGUL PIEUP;So;0;L;<circle> 1107;;;;N;CIRCLED HANGUL BIEUB;;;; +3266;CIRCLED HANGUL SIOS;So;0;L;<circle> 1109;;;;N;;;;; +3267;CIRCLED HANGUL IEUNG;So;0;L;<circle> 110B;;;;N;;;;; +3268;CIRCLED HANGUL CIEUC;So;0;L;<circle> 110C;;;;N;CIRCLED HANGUL JIEUJ;;;; +3269;CIRCLED HANGUL CHIEUCH;So;0;L;<circle> 110E;;;;N;CIRCLED HANGUL CIEUC;;;; +326A;CIRCLED HANGUL KHIEUKH;So;0;L;<circle> 110F;;;;N;CIRCLED HANGUL KIYEOK;;;; +326B;CIRCLED HANGUL THIEUTH;So;0;L;<circle> 1110;;;;N;CIRCLED HANGUL TIEUT;;;; +326C;CIRCLED HANGUL PHIEUPH;So;0;L;<circle> 1111;;;;N;CIRCLED HANGUL PIEUP;;;; +326D;CIRCLED HANGUL HIEUH;So;0;L;<circle> 1112;;;;N;;;;; +326E;CIRCLED HANGUL KIYEOK A;So;0;L;<circle> 1100 1161;;;;N;CIRCLED HANGUL GA;;;; +326F;CIRCLED HANGUL NIEUN A;So;0;L;<circle> 1102 1161;;;;N;CIRCLED HANGUL NA;;;; +3270;CIRCLED HANGUL TIKEUT A;So;0;L;<circle> 1103 1161;;;;N;CIRCLED HANGUL DA;;;; +3271;CIRCLED HANGUL RIEUL A;So;0;L;<circle> 1105 1161;;;;N;CIRCLED HANGUL LA;;;; +3272;CIRCLED HANGUL MIEUM A;So;0;L;<circle> 1106 1161;;;;N;CIRCLED HANGUL MA;;;; +3273;CIRCLED HANGUL PIEUP A;So;0;L;<circle> 1107 1161;;;;N;CIRCLED HANGUL BA;;;; +3274;CIRCLED HANGUL SIOS A;So;0;L;<circle> 1109 1161;;;;N;CIRCLED HANGUL SA;;;; +3275;CIRCLED HANGUL IEUNG A;So;0;L;<circle> 110B 1161;;;;N;CIRCLED HANGUL A;;;; +3276;CIRCLED HANGUL CIEUC A;So;0;L;<circle> 110C 1161;;;;N;CIRCLED HANGUL JA;;;; +3277;CIRCLED HANGUL CHIEUCH A;So;0;L;<circle> 110E 1161;;;;N;CIRCLED HANGUL CA;;;; +3278;CIRCLED HANGUL KHIEUKH A;So;0;L;<circle> 110F 1161;;;;N;CIRCLED HANGUL KA;;;; +3279;CIRCLED HANGUL THIEUTH A;So;0;L;<circle> 1110 1161;;;;N;CIRCLED HANGUL TA;;;; +327A;CIRCLED HANGUL PHIEUPH A;So;0;L;<circle> 1111 1161;;;;N;CIRCLED HANGUL PA;;;; +327B;CIRCLED HANGUL HIEUH A;So;0;L;<circle> 1112 1161;;;;N;CIRCLED HANGUL HA;;;; +327C;CIRCLED KOREAN CHARACTER CHAMKO;So;0;ON;<circle> 110E 1161 11B7 1100 1169;;;;N;;;;; +327D;CIRCLED KOREAN CHARACTER JUEUI;So;0;ON;<circle> 110C 116E 110B 1174;;;;N;;;;; +327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;; +3280;CIRCLED IDEOGRAPH ONE;No;0;L;<circle> 4E00;;;1;N;;;;; +3281;CIRCLED IDEOGRAPH TWO;No;0;L;<circle> 4E8C;;;2;N;;;;; +3282;CIRCLED IDEOGRAPH THREE;No;0;L;<circle> 4E09;;;3;N;;;;; +3283;CIRCLED IDEOGRAPH FOUR;No;0;L;<circle> 56DB;;;4;N;;;;; +3284;CIRCLED IDEOGRAPH FIVE;No;0;L;<circle> 4E94;;;5;N;;;;; +3285;CIRCLED IDEOGRAPH SIX;No;0;L;<circle> 516D;;;6;N;;;;; +3286;CIRCLED IDEOGRAPH SEVEN;No;0;L;<circle> 4E03;;;7;N;;;;; +3287;CIRCLED IDEOGRAPH EIGHT;No;0;L;<circle> 516B;;;8;N;;;;; +3288;CIRCLED IDEOGRAPH NINE;No;0;L;<circle> 4E5D;;;9;N;;;;; +3289;CIRCLED IDEOGRAPH TEN;No;0;L;<circle> 5341;;;10;N;;;;; +328A;CIRCLED IDEOGRAPH MOON;So;0;L;<circle> 6708;;;;N;;;;; +328B;CIRCLED IDEOGRAPH FIRE;So;0;L;<circle> 706B;;;;N;;;;; +328C;CIRCLED IDEOGRAPH WATER;So;0;L;<circle> 6C34;;;;N;;;;; +328D;CIRCLED IDEOGRAPH WOOD;So;0;L;<circle> 6728;;;;N;;;;; +328E;CIRCLED IDEOGRAPH METAL;So;0;L;<circle> 91D1;;;;N;;;;; +328F;CIRCLED IDEOGRAPH EARTH;So;0;L;<circle> 571F;;;;N;;;;; +3290;CIRCLED IDEOGRAPH SUN;So;0;L;<circle> 65E5;;;;N;;;;; +3291;CIRCLED IDEOGRAPH STOCK;So;0;L;<circle> 682A;;;;N;;;;; +3292;CIRCLED IDEOGRAPH HAVE;So;0;L;<circle> 6709;;;;N;;;;; +3293;CIRCLED IDEOGRAPH SOCIETY;So;0;L;<circle> 793E;;;;N;;;;; +3294;CIRCLED IDEOGRAPH NAME;So;0;L;<circle> 540D;;;;N;;;;; +3295;CIRCLED IDEOGRAPH SPECIAL;So;0;L;<circle> 7279;;;;N;;;;; +3296;CIRCLED IDEOGRAPH FINANCIAL;So;0;L;<circle> 8CA1;;;;N;;;;; +3297;CIRCLED IDEOGRAPH CONGRATULATION;So;0;L;<circle> 795D;;;;N;;;;; +3298;CIRCLED IDEOGRAPH LABOR;So;0;L;<circle> 52B4;;;;N;;;;; +3299;CIRCLED IDEOGRAPH SECRET;So;0;L;<circle> 79D8;;;;N;;;;; +329A;CIRCLED IDEOGRAPH MALE;So;0;L;<circle> 7537;;;;N;;;;; +329B;CIRCLED IDEOGRAPH FEMALE;So;0;L;<circle> 5973;;;;N;;;;; +329C;CIRCLED IDEOGRAPH SUITABLE;So;0;L;<circle> 9069;;;;N;;;;; +329D;CIRCLED IDEOGRAPH EXCELLENT;So;0;L;<circle> 512A;;;;N;;;;; +329E;CIRCLED IDEOGRAPH PRINT;So;0;L;<circle> 5370;;;;N;;;;; +329F;CIRCLED IDEOGRAPH ATTENTION;So;0;L;<circle> 6CE8;;;;N;;;;; +32A0;CIRCLED IDEOGRAPH ITEM;So;0;L;<circle> 9805;;;;N;;;;; +32A1;CIRCLED IDEOGRAPH REST;So;0;L;<circle> 4F11;;;;N;;;;; +32A2;CIRCLED IDEOGRAPH COPY;So;0;L;<circle> 5199;;;;N;;;;; +32A3;CIRCLED IDEOGRAPH CORRECT;So;0;L;<circle> 6B63;;;;N;;;;; +32A4;CIRCLED IDEOGRAPH HIGH;So;0;L;<circle> 4E0A;;;;N;;;;; +32A5;CIRCLED IDEOGRAPH CENTRE;So;0;L;<circle> 4E2D;;;;N;CIRCLED IDEOGRAPH CENTER;;;; +32A6;CIRCLED IDEOGRAPH LOW;So;0;L;<circle> 4E0B;;;;N;;;;; +32A7;CIRCLED IDEOGRAPH LEFT;So;0;L;<circle> 5DE6;;;;N;;;;; +32A8;CIRCLED IDEOGRAPH RIGHT;So;0;L;<circle> 53F3;;;;N;;;;; +32A9;CIRCLED IDEOGRAPH MEDICINE;So;0;L;<circle> 533B;;;;N;;;;; +32AA;CIRCLED IDEOGRAPH RELIGION;So;0;L;<circle> 5B97;;;;N;;;;; +32AB;CIRCLED IDEOGRAPH STUDY;So;0;L;<circle> 5B66;;;;N;;;;; +32AC;CIRCLED IDEOGRAPH SUPERVISE;So;0;L;<circle> 76E3;;;;N;;;;; +32AD;CIRCLED IDEOGRAPH ENTERPRISE;So;0;L;<circle> 4F01;;;;N;;;;; +32AE;CIRCLED IDEOGRAPH RESOURCE;So;0;L;<circle> 8CC7;;;;N;;;;; +32AF;CIRCLED IDEOGRAPH ALLIANCE;So;0;L;<circle> 5354;;;;N;;;;; +32B0;CIRCLED IDEOGRAPH NIGHT;So;0;L;<circle> 591C;;;;N;;;;; +32B1;CIRCLED NUMBER THIRTY SIX;No;0;ON;<circle> 0033 0036;;;36;N;;;;; +32B2;CIRCLED NUMBER THIRTY SEVEN;No;0;ON;<circle> 0033 0037;;;37;N;;;;; +32B3;CIRCLED NUMBER THIRTY EIGHT;No;0;ON;<circle> 0033 0038;;;38;N;;;;; +32B4;CIRCLED NUMBER THIRTY NINE;No;0;ON;<circle> 0033 0039;;;39;N;;;;; +32B5;CIRCLED NUMBER FORTY;No;0;ON;<circle> 0034 0030;;;40;N;;;;; +32B6;CIRCLED NUMBER FORTY ONE;No;0;ON;<circle> 0034 0031;;;41;N;;;;; +32B7;CIRCLED NUMBER FORTY TWO;No;0;ON;<circle> 0034 0032;;;42;N;;;;; +32B8;CIRCLED NUMBER FORTY THREE;No;0;ON;<circle> 0034 0033;;;43;N;;;;; +32B9;CIRCLED NUMBER FORTY FOUR;No;0;ON;<circle> 0034 0034;;;44;N;;;;; +32BA;CIRCLED NUMBER FORTY FIVE;No;0;ON;<circle> 0034 0035;;;45;N;;;;; +32BB;CIRCLED NUMBER FORTY SIX;No;0;ON;<circle> 0034 0036;;;46;N;;;;; +32BC;CIRCLED NUMBER FORTY SEVEN;No;0;ON;<circle> 0034 0037;;;47;N;;;;; +32BD;CIRCLED NUMBER FORTY EIGHT;No;0;ON;<circle> 0034 0038;;;48;N;;;;; +32BE;CIRCLED NUMBER FORTY NINE;No;0;ON;<circle> 0034 0039;;;49;N;;;;; +32BF;CIRCLED NUMBER FIFTY;No;0;ON;<circle> 0035 0030;;;50;N;;;;; +32C0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY;So;0;L;<compat> 0031 6708;;;;N;;;;; +32C1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY;So;0;L;<compat> 0032 6708;;;;N;;;;; +32C2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH;So;0;L;<compat> 0033 6708;;;;N;;;;; +32C3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL;So;0;L;<compat> 0034 6708;;;;N;;;;; +32C4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY;So;0;L;<compat> 0035 6708;;;;N;;;;; +32C5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE;So;0;L;<compat> 0036 6708;;;;N;;;;; +32C6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY;So;0;L;<compat> 0037 6708;;;;N;;;;; +32C7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST;So;0;L;<compat> 0038 6708;;;;N;;;;; +32C8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER;So;0;L;<compat> 0039 6708;;;;N;;;;; +32C9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER;So;0;L;<compat> 0031 0030 6708;;;;N;;;;; +32CA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER;So;0;L;<compat> 0031 0031 6708;;;;N;;;;; +32CB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER;So;0;L;<compat> 0031 0032 6708;;;;N;;;;; +32CC;SQUARE HG;So;0;ON;<square> 0048 0067;;;;N;;;;; +32CD;SQUARE ERG;So;0;ON;<square> 0065 0072 0067;;;;N;;;;; +32CE;SQUARE EV;So;0;ON;<square> 0065 0056;;;;N;;;;; +32CF;LIMITED LIABILITY SIGN;So;0;ON;<square> 004C 0054 0044;;;;N;;;;; +32D0;CIRCLED KATAKANA A;So;0;L;<circle> 30A2;;;;N;;;;; +32D1;CIRCLED KATAKANA I;So;0;L;<circle> 30A4;;;;N;;;;; +32D2;CIRCLED KATAKANA U;So;0;L;<circle> 30A6;;;;N;;;;; +32D3;CIRCLED KATAKANA E;So;0;L;<circle> 30A8;;;;N;;;;; +32D4;CIRCLED KATAKANA O;So;0;L;<circle> 30AA;;;;N;;;;; +32D5;CIRCLED KATAKANA KA;So;0;L;<circle> 30AB;;;;N;;;;; +32D6;CIRCLED KATAKANA KI;So;0;L;<circle> 30AD;;;;N;;;;; +32D7;CIRCLED KATAKANA KU;So;0;L;<circle> 30AF;;;;N;;;;; +32D8;CIRCLED KATAKANA KE;So;0;L;<circle> 30B1;;;;N;;;;; +32D9;CIRCLED KATAKANA KO;So;0;L;<circle> 30B3;;;;N;;;;; +32DA;CIRCLED KATAKANA SA;So;0;L;<circle> 30B5;;;;N;;;;; +32DB;CIRCLED KATAKANA SI;So;0;L;<circle> 30B7;;;;N;;;;; +32DC;CIRCLED KATAKANA SU;So;0;L;<circle> 30B9;;;;N;;;;; +32DD;CIRCLED KATAKANA SE;So;0;L;<circle> 30BB;;;;N;;;;; +32DE;CIRCLED KATAKANA SO;So;0;L;<circle> 30BD;;;;N;;;;; +32DF;CIRCLED KATAKANA TA;So;0;L;<circle> 30BF;;;;N;;;;; +32E0;CIRCLED KATAKANA TI;So;0;L;<circle> 30C1;;;;N;;;;; +32E1;CIRCLED KATAKANA TU;So;0;L;<circle> 30C4;;;;N;;;;; +32E2;CIRCLED KATAKANA TE;So;0;L;<circle> 30C6;;;;N;;;;; +32E3;CIRCLED KATAKANA TO;So;0;L;<circle> 30C8;;;;N;;;;; +32E4;CIRCLED KATAKANA NA;So;0;L;<circle> 30CA;;;;N;;;;; +32E5;CIRCLED KATAKANA NI;So;0;L;<circle> 30CB;;;;N;;;;; +32E6;CIRCLED KATAKANA NU;So;0;L;<circle> 30CC;;;;N;;;;; +32E7;CIRCLED KATAKANA NE;So;0;L;<circle> 30CD;;;;N;;;;; +32E8;CIRCLED KATAKANA NO;So;0;L;<circle> 30CE;;;;N;;;;; +32E9;CIRCLED KATAKANA HA;So;0;L;<circle> 30CF;;;;N;;;;; +32EA;CIRCLED KATAKANA HI;So;0;L;<circle> 30D2;;;;N;;;;; +32EB;CIRCLED KATAKANA HU;So;0;L;<circle> 30D5;;;;N;;;;; +32EC;CIRCLED KATAKANA HE;So;0;L;<circle> 30D8;;;;N;;;;; +32ED;CIRCLED KATAKANA HO;So;0;L;<circle> 30DB;;;;N;;;;; +32EE;CIRCLED KATAKANA MA;So;0;L;<circle> 30DE;;;;N;;;;; +32EF;CIRCLED KATAKANA MI;So;0;L;<circle> 30DF;;;;N;;;;; +32F0;CIRCLED KATAKANA MU;So;0;L;<circle> 30E0;;;;N;;;;; +32F1;CIRCLED KATAKANA ME;So;0;L;<circle> 30E1;;;;N;;;;; +32F2;CIRCLED KATAKANA MO;So;0;L;<circle> 30E2;;;;N;;;;; +32F3;CIRCLED KATAKANA YA;So;0;L;<circle> 30E4;;;;N;;;;; +32F4;CIRCLED KATAKANA YU;So;0;L;<circle> 30E6;;;;N;;;;; +32F5;CIRCLED KATAKANA YO;So;0;L;<circle> 30E8;;;;N;;;;; +32F6;CIRCLED KATAKANA RA;So;0;L;<circle> 30E9;;;;N;;;;; +32F7;CIRCLED KATAKANA RI;So;0;L;<circle> 30EA;;;;N;;;;; +32F8;CIRCLED KATAKANA RU;So;0;L;<circle> 30EB;;;;N;;;;; +32F9;CIRCLED KATAKANA RE;So;0;L;<circle> 30EC;;;;N;;;;; +32FA;CIRCLED KATAKANA RO;So;0;L;<circle> 30ED;;;;N;;;;; +32FB;CIRCLED KATAKANA WA;So;0;L;<circle> 30EF;;;;N;;;;; +32FC;CIRCLED KATAKANA WI;So;0;L;<circle> 30F0;;;;N;;;;; +32FD;CIRCLED KATAKANA WE;So;0;L;<circle> 30F1;;;;N;;;;; +32FE;CIRCLED KATAKANA WO;So;0;L;<circle> 30F2;;;;N;;;;; +3300;SQUARE APAATO;So;0;L;<square> 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;; +3301;SQUARE ARUHUA;So;0;L;<square> 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;; +3302;SQUARE ANPEA;So;0;L;<square> 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;; +3303;SQUARE AARU;So;0;L;<square> 30A2 30FC 30EB;;;;N;SQUARED AARU;;;; +3304;SQUARE ININGU;So;0;L;<square> 30A4 30CB 30F3 30B0;;;;N;SQUARED ININGU;;;; +3305;SQUARE INTI;So;0;L;<square> 30A4 30F3 30C1;;;;N;SQUARED INTI;;;; +3306;SQUARE UON;So;0;L;<square> 30A6 30A9 30F3;;;;N;SQUARED UON;;;; +3307;SQUARE ESUKUUDO;So;0;L;<square> 30A8 30B9 30AF 30FC 30C9;;;;N;SQUARED ESUKUUDO;;;; +3308;SQUARE EEKAA;So;0;L;<square> 30A8 30FC 30AB 30FC;;;;N;SQUARED EEKAA;;;; +3309;SQUARE ONSU;So;0;L;<square> 30AA 30F3 30B9;;;;N;SQUARED ONSU;;;; +330A;SQUARE OOMU;So;0;L;<square> 30AA 30FC 30E0;;;;N;SQUARED OOMU;;;; +330B;SQUARE KAIRI;So;0;L;<square> 30AB 30A4 30EA;;;;N;SQUARED KAIRI;;;; +330C;SQUARE KARATTO;So;0;L;<square> 30AB 30E9 30C3 30C8;;;;N;SQUARED KARATTO;;;; +330D;SQUARE KARORII;So;0;L;<square> 30AB 30ED 30EA 30FC;;;;N;SQUARED KARORII;;;; +330E;SQUARE GARON;So;0;L;<square> 30AC 30ED 30F3;;;;N;SQUARED GARON;;;; +330F;SQUARE GANMA;So;0;L;<square> 30AC 30F3 30DE;;;;N;SQUARED GANMA;;;; +3310;SQUARE GIGA;So;0;L;<square> 30AE 30AC;;;;N;SQUARED GIGA;;;; +3311;SQUARE GINII;So;0;L;<square> 30AE 30CB 30FC;;;;N;SQUARED GINII;;;; +3312;SQUARE KYURII;So;0;L;<square> 30AD 30E5 30EA 30FC;;;;N;SQUARED KYURII;;;; +3313;SQUARE GIRUDAA;So;0;L;<square> 30AE 30EB 30C0 30FC;;;;N;SQUARED GIRUDAA;;;; +3314;SQUARE KIRO;So;0;L;<square> 30AD 30ED;;;;N;SQUARED KIRO;;;; +3315;SQUARE KIROGURAMU;So;0;L;<square> 30AD 30ED 30B0 30E9 30E0;;;;N;SQUARED KIROGURAMU;;;; +3316;SQUARE KIROMEETORU;So;0;L;<square> 30AD 30ED 30E1 30FC 30C8 30EB;;;;N;SQUARED KIROMEETORU;;;; +3317;SQUARE KIROWATTO;So;0;L;<square> 30AD 30ED 30EF 30C3 30C8;;;;N;SQUARED KIROWATTO;;;; +3318;SQUARE GURAMU;So;0;L;<square> 30B0 30E9 30E0;;;;N;SQUARED GURAMU;;;; +3319;SQUARE GURAMUTON;So;0;L;<square> 30B0 30E9 30E0 30C8 30F3;;;;N;SQUARED GURAMUTON;;;; +331A;SQUARE KURUZEIRO;So;0;L;<square> 30AF 30EB 30BC 30A4 30ED;;;;N;SQUARED KURUZEIRO;;;; +331B;SQUARE KUROONE;So;0;L;<square> 30AF 30ED 30FC 30CD;;;;N;SQUARED KUROONE;;;; +331C;SQUARE KEESU;So;0;L;<square> 30B1 30FC 30B9;;;;N;SQUARED KEESU;;;; +331D;SQUARE KORUNA;So;0;L;<square> 30B3 30EB 30CA;;;;N;SQUARED KORUNA;;;; +331E;SQUARE KOOPO;So;0;L;<square> 30B3 30FC 30DD;;;;N;SQUARED KOOPO;;;; +331F;SQUARE SAIKURU;So;0;L;<square> 30B5 30A4 30AF 30EB;;;;N;SQUARED SAIKURU;;;; +3320;SQUARE SANTIIMU;So;0;L;<square> 30B5 30F3 30C1 30FC 30E0;;;;N;SQUARED SANTIIMU;;;; +3321;SQUARE SIRINGU;So;0;L;<square> 30B7 30EA 30F3 30B0;;;;N;SQUARED SIRINGU;;;; +3322;SQUARE SENTI;So;0;L;<square> 30BB 30F3 30C1;;;;N;SQUARED SENTI;;;; +3323;SQUARE SENTO;So;0;L;<square> 30BB 30F3 30C8;;;;N;SQUARED SENTO;;;; +3324;SQUARE DAASU;So;0;L;<square> 30C0 30FC 30B9;;;;N;SQUARED DAASU;;;; +3325;SQUARE DESI;So;0;L;<square> 30C7 30B7;;;;N;SQUARED DESI;;;; +3326;SQUARE DORU;So;0;L;<square> 30C9 30EB;;;;N;SQUARED DORU;;;; +3327;SQUARE TON;So;0;L;<square> 30C8 30F3;;;;N;SQUARED TON;;;; +3328;SQUARE NANO;So;0;L;<square> 30CA 30CE;;;;N;SQUARED NANO;;;; +3329;SQUARE NOTTO;So;0;L;<square> 30CE 30C3 30C8;;;;N;SQUARED NOTTO;;;; +332A;SQUARE HAITU;So;0;L;<square> 30CF 30A4 30C4;;;;N;SQUARED HAITU;;;; +332B;SQUARE PAASENTO;So;0;L;<square> 30D1 30FC 30BB 30F3 30C8;;;;N;SQUARED PAASENTO;;;; +332C;SQUARE PAATU;So;0;L;<square> 30D1 30FC 30C4;;;;N;SQUARED PAATU;;;; +332D;SQUARE BAARERU;So;0;L;<square> 30D0 30FC 30EC 30EB;;;;N;SQUARED BAARERU;;;; +332E;SQUARE PIASUTORU;So;0;L;<square> 30D4 30A2 30B9 30C8 30EB;;;;N;SQUARED PIASUTORU;;;; +332F;SQUARE PIKURU;So;0;L;<square> 30D4 30AF 30EB;;;;N;SQUARED PIKURU;;;; +3330;SQUARE PIKO;So;0;L;<square> 30D4 30B3;;;;N;SQUARED PIKO;;;; +3331;SQUARE BIRU;So;0;L;<square> 30D3 30EB;;;;N;SQUARED BIRU;;;; +3332;SQUARE HUARADDO;So;0;L;<square> 30D5 30A1 30E9 30C3 30C9;;;;N;SQUARED HUARADDO;;;; +3333;SQUARE HUIITO;So;0;L;<square> 30D5 30A3 30FC 30C8;;;;N;SQUARED HUIITO;;;; +3334;SQUARE BUSSYERU;So;0;L;<square> 30D6 30C3 30B7 30A7 30EB;;;;N;SQUARED BUSSYERU;;;; +3335;SQUARE HURAN;So;0;L;<square> 30D5 30E9 30F3;;;;N;SQUARED HURAN;;;; +3336;SQUARE HEKUTAARU;So;0;L;<square> 30D8 30AF 30BF 30FC 30EB;;;;N;SQUARED HEKUTAARU;;;; +3337;SQUARE PESO;So;0;L;<square> 30DA 30BD;;;;N;SQUARED PESO;;;; +3338;SQUARE PENIHI;So;0;L;<square> 30DA 30CB 30D2;;;;N;SQUARED PENIHI;;;; +3339;SQUARE HERUTU;So;0;L;<square> 30D8 30EB 30C4;;;;N;SQUARED HERUTU;;;; +333A;SQUARE PENSU;So;0;L;<square> 30DA 30F3 30B9;;;;N;SQUARED PENSU;;;; +333B;SQUARE PEEZI;So;0;L;<square> 30DA 30FC 30B8;;;;N;SQUARED PEEZI;;;; +333C;SQUARE BEETA;So;0;L;<square> 30D9 30FC 30BF;;;;N;SQUARED BEETA;;;; +333D;SQUARE POINTO;So;0;L;<square> 30DD 30A4 30F3 30C8;;;;N;SQUARED POINTO;;;; +333E;SQUARE BORUTO;So;0;L;<square> 30DC 30EB 30C8;;;;N;SQUARED BORUTO;;;; +333F;SQUARE HON;So;0;L;<square> 30DB 30F3;;;;N;SQUARED HON;;;; +3340;SQUARE PONDO;So;0;L;<square> 30DD 30F3 30C9;;;;N;SQUARED PONDO;;;; +3341;SQUARE HOORU;So;0;L;<square> 30DB 30FC 30EB;;;;N;SQUARED HOORU;;;; +3342;SQUARE HOON;So;0;L;<square> 30DB 30FC 30F3;;;;N;SQUARED HOON;;;; +3343;SQUARE MAIKURO;So;0;L;<square> 30DE 30A4 30AF 30ED;;;;N;SQUARED MAIKURO;;;; +3344;SQUARE MAIRU;So;0;L;<square> 30DE 30A4 30EB;;;;N;SQUARED MAIRU;;;; +3345;SQUARE MAHHA;So;0;L;<square> 30DE 30C3 30CF;;;;N;SQUARED MAHHA;;;; +3346;SQUARE MARUKU;So;0;L;<square> 30DE 30EB 30AF;;;;N;SQUARED MARUKU;;;; +3347;SQUARE MANSYON;So;0;L;<square> 30DE 30F3 30B7 30E7 30F3;;;;N;SQUARED MANSYON;;;; +3348;SQUARE MIKURON;So;0;L;<square> 30DF 30AF 30ED 30F3;;;;N;SQUARED MIKURON;;;; +3349;SQUARE MIRI;So;0;L;<square> 30DF 30EA;;;;N;SQUARED MIRI;;;; +334A;SQUARE MIRIBAARU;So;0;L;<square> 30DF 30EA 30D0 30FC 30EB;;;;N;SQUARED MIRIBAARU;;;; +334B;SQUARE MEGA;So;0;L;<square> 30E1 30AC;;;;N;SQUARED MEGA;;;; +334C;SQUARE MEGATON;So;0;L;<square> 30E1 30AC 30C8 30F3;;;;N;SQUARED MEGATON;;;; +334D;SQUARE MEETORU;So;0;L;<square> 30E1 30FC 30C8 30EB;;;;N;SQUARED MEETORU;;;; +334E;SQUARE YAADO;So;0;L;<square> 30E4 30FC 30C9;;;;N;SQUARED YAADO;;;; +334F;SQUARE YAARU;So;0;L;<square> 30E4 30FC 30EB;;;;N;SQUARED YAARU;;;; +3350;SQUARE YUAN;So;0;L;<square> 30E6 30A2 30F3;;;;N;SQUARED YUAN;;;; +3351;SQUARE RITTORU;So;0;L;<square> 30EA 30C3 30C8 30EB;;;;N;SQUARED RITTORU;;;; +3352;SQUARE RIRA;So;0;L;<square> 30EA 30E9;;;;N;SQUARED RIRA;;;; +3353;SQUARE RUPII;So;0;L;<square> 30EB 30D4 30FC;;;;N;SQUARED RUPII;;;; +3354;SQUARE RUUBURU;So;0;L;<square> 30EB 30FC 30D6 30EB;;;;N;SQUARED RUUBURU;;;; +3355;SQUARE REMU;So;0;L;<square> 30EC 30E0;;;;N;SQUARED REMU;;;; +3356;SQUARE RENTOGEN;So;0;L;<square> 30EC 30F3 30C8 30B2 30F3;;;;N;SQUARED RENTOGEN;;;; +3357;SQUARE WATTO;So;0;L;<square> 30EF 30C3 30C8;;;;N;SQUARED WATTO;;;; +3358;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO;So;0;L;<compat> 0030 70B9;;;;N;;;;; +3359;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE;So;0;L;<compat> 0031 70B9;;;;N;;;;; +335A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO;So;0;L;<compat> 0032 70B9;;;;N;;;;; +335B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE;So;0;L;<compat> 0033 70B9;;;;N;;;;; +335C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR;So;0;L;<compat> 0034 70B9;;;;N;;;;; +335D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE;So;0;L;<compat> 0035 70B9;;;;N;;;;; +335E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX;So;0;L;<compat> 0036 70B9;;;;N;;;;; +335F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN;So;0;L;<compat> 0037 70B9;;;;N;;;;; +3360;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT;So;0;L;<compat> 0038 70B9;;;;N;;;;; +3361;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE;So;0;L;<compat> 0039 70B9;;;;N;;;;; +3362;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN;So;0;L;<compat> 0031 0030 70B9;;;;N;;;;; +3363;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN;So;0;L;<compat> 0031 0031 70B9;;;;N;;;;; +3364;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE;So;0;L;<compat> 0031 0032 70B9;;;;N;;;;; +3365;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN;So;0;L;<compat> 0031 0033 70B9;;;;N;;;;; +3366;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN;So;0;L;<compat> 0031 0034 70B9;;;;N;;;;; +3367;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN;So;0;L;<compat> 0031 0035 70B9;;;;N;;;;; +3368;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN;So;0;L;<compat> 0031 0036 70B9;;;;N;;;;; +3369;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN;So;0;L;<compat> 0031 0037 70B9;;;;N;;;;; +336A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN;So;0;L;<compat> 0031 0038 70B9;;;;N;;;;; +336B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN;So;0;L;<compat> 0031 0039 70B9;;;;N;;;;; +336C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY;So;0;L;<compat> 0032 0030 70B9;;;;N;;;;; +336D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE;So;0;L;<compat> 0032 0031 70B9;;;;N;;;;; +336E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO;So;0;L;<compat> 0032 0032 70B9;;;;N;;;;; +336F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE;So;0;L;<compat> 0032 0033 70B9;;;;N;;;;; +3370;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR;So;0;L;<compat> 0032 0034 70B9;;;;N;;;;; +3371;SQUARE HPA;So;0;L;<square> 0068 0050 0061;;;;N;;;;; +3372;SQUARE DA;So;0;L;<square> 0064 0061;;;;N;;;;; +3373;SQUARE AU;So;0;L;<square> 0041 0055;;;;N;;;;; +3374;SQUARE BAR;So;0;L;<square> 0062 0061 0072;;;;N;;;;; +3375;SQUARE OV;So;0;L;<square> 006F 0056;;;;N;;;;; +3376;SQUARE PC;So;0;L;<square> 0070 0063;;;;N;;;;; +3377;SQUARE DM;So;0;ON;<square> 0064 006D;;;;N;;;;; +3378;SQUARE DM SQUARED;So;0;ON;<square> 0064 006D 00B2;;;;N;;;;; +3379;SQUARE DM CUBED;So;0;ON;<square> 0064 006D 00B3;;;;N;;;;; +337A;SQUARE IU;So;0;ON;<square> 0049 0055;;;;N;;;;; +337B;SQUARE ERA NAME HEISEI;So;0;L;<square> 5E73 6210;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME HEISEI;;;; +337C;SQUARE ERA NAME SYOUWA;So;0;L;<square> 662D 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME SYOUWA;;;; +337D;SQUARE ERA NAME TAISYOU;So;0;L;<square> 5927 6B63;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME TAISYOU;;;; +337E;SQUARE ERA NAME MEIZI;So;0;L;<square> 660E 6CBB;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME MEIZI;;;; +337F;SQUARE CORPORATION;So;0;L;<square> 682A 5F0F 4F1A 793E;;;;N;SQUARED FOUR IDEOGRAPHS CORPORATION;;;; +3380;SQUARE PA AMPS;So;0;L;<square> 0070 0041;;;;N;SQUARED PA AMPS;;;; +3381;SQUARE NA;So;0;L;<square> 006E 0041;;;;N;SQUARED NA;;;; +3382;SQUARE MU A;So;0;L;<square> 03BC 0041;;;;N;SQUARED MU A;;;; +3383;SQUARE MA;So;0;L;<square> 006D 0041;;;;N;SQUARED MA;;;; +3384;SQUARE KA;So;0;L;<square> 006B 0041;;;;N;SQUARED KA;;;; +3385;SQUARE KB;So;0;L;<square> 004B 0042;;;;N;SQUARED KB;;;; +3386;SQUARE MB;So;0;L;<square> 004D 0042;;;;N;SQUARED MB;;;; +3387;SQUARE GB;So;0;L;<square> 0047 0042;;;;N;SQUARED GB;;;; +3388;SQUARE CAL;So;0;L;<square> 0063 0061 006C;;;;N;SQUARED CAL;;;; +3389;SQUARE KCAL;So;0;L;<square> 006B 0063 0061 006C;;;;N;SQUARED KCAL;;;; +338A;SQUARE PF;So;0;L;<square> 0070 0046;;;;N;SQUARED PF;;;; +338B;SQUARE NF;So;0;L;<square> 006E 0046;;;;N;SQUARED NF;;;; +338C;SQUARE MU F;So;0;L;<square> 03BC 0046;;;;N;SQUARED MU F;;;; +338D;SQUARE MU G;So;0;L;<square> 03BC 0067;;;;N;SQUARED MU G;;;; +338E;SQUARE MG;So;0;L;<square> 006D 0067;;;;N;SQUARED MG;;;; +338F;SQUARE KG;So;0;L;<square> 006B 0067;;;;N;SQUARED KG;;;; +3390;SQUARE HZ;So;0;L;<square> 0048 007A;;;;N;SQUARED HZ;;;; +3391;SQUARE KHZ;So;0;L;<square> 006B 0048 007A;;;;N;SQUARED KHZ;;;; +3392;SQUARE MHZ;So;0;L;<square> 004D 0048 007A;;;;N;SQUARED MHZ;;;; +3393;SQUARE GHZ;So;0;L;<square> 0047 0048 007A;;;;N;SQUARED GHZ;;;; +3394;SQUARE THZ;So;0;L;<square> 0054 0048 007A;;;;N;SQUARED THZ;;;; +3395;SQUARE MU L;So;0;L;<square> 03BC 2113;;;;N;SQUARED MU L;;;; +3396;SQUARE ML;So;0;L;<square> 006D 2113;;;;N;SQUARED ML;;;; +3397;SQUARE DL;So;0;L;<square> 0064 2113;;;;N;SQUARED DL;;;; +3398;SQUARE KL;So;0;L;<square> 006B 2113;;;;N;SQUARED KL;;;; +3399;SQUARE FM;So;0;L;<square> 0066 006D;;;;N;SQUARED FM;;;; +339A;SQUARE NM;So;0;L;<square> 006E 006D;;;;N;SQUARED NM;;;; +339B;SQUARE MU M;So;0;L;<square> 03BC 006D;;;;N;SQUARED MU M;;;; +339C;SQUARE MM;So;0;L;<square> 006D 006D;;;;N;SQUARED MM;;;; +339D;SQUARE CM;So;0;L;<square> 0063 006D;;;;N;SQUARED CM;;;; +339E;SQUARE KM;So;0;L;<square> 006B 006D;;;;N;SQUARED KM;;;; +339F;SQUARE MM SQUARED;So;0;L;<square> 006D 006D 00B2;;;;N;SQUARED MM SQUARED;;;; +33A0;SQUARE CM SQUARED;So;0;L;<square> 0063 006D 00B2;;;;N;SQUARED CM SQUARED;;;; +33A1;SQUARE M SQUARED;So;0;L;<square> 006D 00B2;;;;N;SQUARED M SQUARED;;;; +33A2;SQUARE KM SQUARED;So;0;L;<square> 006B 006D 00B2;;;;N;SQUARED KM SQUARED;;;; +33A3;SQUARE MM CUBED;So;0;L;<square> 006D 006D 00B3;;;;N;SQUARED MM CUBED;;;; +33A4;SQUARE CM CUBED;So;0;L;<square> 0063 006D 00B3;;;;N;SQUARED CM CUBED;;;; +33A5;SQUARE M CUBED;So;0;L;<square> 006D 00B3;;;;N;SQUARED M CUBED;;;; +33A6;SQUARE KM CUBED;So;0;L;<square> 006B 006D 00B3;;;;N;SQUARED KM CUBED;;;; +33A7;SQUARE M OVER S;So;0;L;<square> 006D 2215 0073;;;;N;SQUARED M OVER S;;;; +33A8;SQUARE M OVER S SQUARED;So;0;L;<square> 006D 2215 0073 00B2;;;;N;SQUARED M OVER S SQUARED;;;; +33A9;SQUARE PA;So;0;L;<square> 0050 0061;;;;N;SQUARED PA;;;; +33AA;SQUARE KPA;So;0;L;<square> 006B 0050 0061;;;;N;SQUARED KPA;;;; +33AB;SQUARE MPA;So;0;L;<square> 004D 0050 0061;;;;N;SQUARED MPA;;;; +33AC;SQUARE GPA;So;0;L;<square> 0047 0050 0061;;;;N;SQUARED GPA;;;; +33AD;SQUARE RAD;So;0;L;<square> 0072 0061 0064;;;;N;SQUARED RAD;;;; +33AE;SQUARE RAD OVER S;So;0;L;<square> 0072 0061 0064 2215 0073;;;;N;SQUARED RAD OVER S;;;; +33AF;SQUARE RAD OVER S SQUARED;So;0;L;<square> 0072 0061 0064 2215 0073 00B2;;;;N;SQUARED RAD OVER S SQUARED;;;; +33B0;SQUARE PS;So;0;L;<square> 0070 0073;;;;N;SQUARED PS;;;; +33B1;SQUARE NS;So;0;L;<square> 006E 0073;;;;N;SQUARED NS;;;; +33B2;SQUARE MU S;So;0;L;<square> 03BC 0073;;;;N;SQUARED MU S;;;; +33B3;SQUARE MS;So;0;L;<square> 006D 0073;;;;N;SQUARED MS;;;; +33B4;SQUARE PV;So;0;L;<square> 0070 0056;;;;N;SQUARED PV;;;; +33B5;SQUARE NV;So;0;L;<square> 006E 0056;;;;N;SQUARED NV;;;; +33B6;SQUARE MU V;So;0;L;<square> 03BC 0056;;;;N;SQUARED MU V;;;; +33B7;SQUARE MV;So;0;L;<square> 006D 0056;;;;N;SQUARED MV;;;; +33B8;SQUARE KV;So;0;L;<square> 006B 0056;;;;N;SQUARED KV;;;; +33B9;SQUARE MV MEGA;So;0;L;<square> 004D 0056;;;;N;SQUARED MV MEGA;;;; +33BA;SQUARE PW;So;0;L;<square> 0070 0057;;;;N;SQUARED PW;;;; +33BB;SQUARE NW;So;0;L;<square> 006E 0057;;;;N;SQUARED NW;;;; +33BC;SQUARE MU W;So;0;L;<square> 03BC 0057;;;;N;SQUARED MU W;;;; +33BD;SQUARE MW;So;0;L;<square> 006D 0057;;;;N;SQUARED MW;;;; +33BE;SQUARE KW;So;0;L;<square> 006B 0057;;;;N;SQUARED KW;;;; +33BF;SQUARE MW MEGA;So;0;L;<square> 004D 0057;;;;N;SQUARED MW MEGA;;;; +33C0;SQUARE K OHM;So;0;L;<square> 006B 03A9;;;;N;SQUARED K OHM;;;; +33C1;SQUARE M OHM;So;0;L;<square> 004D 03A9;;;;N;SQUARED M OHM;;;; +33C2;SQUARE AM;So;0;L;<square> 0061 002E 006D 002E;;;;N;SQUARED AM;;;; +33C3;SQUARE BQ;So;0;L;<square> 0042 0071;;;;N;SQUARED BQ;;;; +33C4;SQUARE CC;So;0;L;<square> 0063 0063;;;;N;SQUARED CC;;;; +33C5;SQUARE CD;So;0;L;<square> 0063 0064;;;;N;SQUARED CD;;;; +33C6;SQUARE C OVER KG;So;0;L;<square> 0043 2215 006B 0067;;;;N;SQUARED C OVER KG;;;; +33C7;SQUARE CO;So;0;L;<square> 0043 006F 002E;;;;N;SQUARED CO;;;; +33C8;SQUARE DB;So;0;L;<square> 0064 0042;;;;N;SQUARED DB;;;; +33C9;SQUARE GY;So;0;L;<square> 0047 0079;;;;N;SQUARED GY;;;; +33CA;SQUARE HA;So;0;L;<square> 0068 0061;;;;N;SQUARED HA;;;; +33CB;SQUARE HP;So;0;L;<square> 0048 0050;;;;N;SQUARED HP;;;; +33CC;SQUARE IN;So;0;L;<square> 0069 006E;;;;N;SQUARED IN;;;; +33CD;SQUARE KK;So;0;L;<square> 004B 004B;;;;N;SQUARED KK;;;; +33CE;SQUARE KM CAPITAL;So;0;L;<square> 004B 004D;;;;N;SQUARED KM CAPITAL;;;; +33CF;SQUARE KT;So;0;L;<square> 006B 0074;;;;N;SQUARED KT;;;; +33D0;SQUARE LM;So;0;L;<square> 006C 006D;;;;N;SQUARED LM;;;; +33D1;SQUARE LN;So;0;L;<square> 006C 006E;;;;N;SQUARED LN;;;; +33D2;SQUARE LOG;So;0;L;<square> 006C 006F 0067;;;;N;SQUARED LOG;;;; +33D3;SQUARE LX;So;0;L;<square> 006C 0078;;;;N;SQUARED LX;;;; +33D4;SQUARE MB SMALL;So;0;L;<square> 006D 0062;;;;N;SQUARED MB SMALL;;;; +33D5;SQUARE MIL;So;0;L;<square> 006D 0069 006C;;;;N;SQUARED MIL;;;; +33D6;SQUARE MOL;So;0;L;<square> 006D 006F 006C;;;;N;SQUARED MOL;;;; +33D7;SQUARE PH;So;0;L;<square> 0050 0048;;;;N;SQUARED PH;;;; +33D8;SQUARE PM;So;0;L;<square> 0070 002E 006D 002E;;;;N;SQUARED PM;;;; +33D9;SQUARE PPM;So;0;L;<square> 0050 0050 004D;;;;N;SQUARED PPM;;;; +33DA;SQUARE PR;So;0;L;<square> 0050 0052;;;;N;SQUARED PR;;;; +33DB;SQUARE SR;So;0;L;<square> 0073 0072;;;;N;SQUARED SR;;;; +33DC;SQUARE SV;So;0;L;<square> 0053 0076;;;;N;SQUARED SV;;;; +33DD;SQUARE WB;So;0;L;<square> 0057 0062;;;;N;SQUARED WB;;;; +33DE;SQUARE V OVER M;So;0;ON;<square> 0056 2215 006D;;;;N;;;;; +33DF;SQUARE A OVER M;So;0;ON;<square> 0041 2215 006D;;;;N;;;;; +33E0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE;So;0;L;<compat> 0031 65E5;;;;N;;;;; +33E1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO;So;0;L;<compat> 0032 65E5;;;;N;;;;; +33E2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE;So;0;L;<compat> 0033 65E5;;;;N;;;;; +33E3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR;So;0;L;<compat> 0034 65E5;;;;N;;;;; +33E4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE;So;0;L;<compat> 0035 65E5;;;;N;;;;; +33E5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX;So;0;L;<compat> 0036 65E5;;;;N;;;;; +33E6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN;So;0;L;<compat> 0037 65E5;;;;N;;;;; +33E7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT;So;0;L;<compat> 0038 65E5;;;;N;;;;; +33E8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE;So;0;L;<compat> 0039 65E5;;;;N;;;;; +33E9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN;So;0;L;<compat> 0031 0030 65E5;;;;N;;;;; +33EA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN;So;0;L;<compat> 0031 0031 65E5;;;;N;;;;; +33EB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE;So;0;L;<compat> 0031 0032 65E5;;;;N;;;;; +33EC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN;So;0;L;<compat> 0031 0033 65E5;;;;N;;;;; +33ED;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN;So;0;L;<compat> 0031 0034 65E5;;;;N;;;;; +33EE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN;So;0;L;<compat> 0031 0035 65E5;;;;N;;;;; +33EF;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN;So;0;L;<compat> 0031 0036 65E5;;;;N;;;;; +33F0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN;So;0;L;<compat> 0031 0037 65E5;;;;N;;;;; +33F1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN;So;0;L;<compat> 0031 0038 65E5;;;;N;;;;; +33F2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN;So;0;L;<compat> 0031 0039 65E5;;;;N;;;;; +33F3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY;So;0;L;<compat> 0032 0030 65E5;;;;N;;;;; +33F4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE;So;0;L;<compat> 0032 0031 65E5;;;;N;;;;; +33F5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO;So;0;L;<compat> 0032 0032 65E5;;;;N;;;;; +33F6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE;So;0;L;<compat> 0032 0033 65E5;;;;N;;;;; +33F7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR;So;0;L;<compat> 0032 0034 65E5;;;;N;;;;; +33F8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE;So;0;L;<compat> 0032 0035 65E5;;;;N;;;;; +33F9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX;So;0;L;<compat> 0032 0036 65E5;;;;N;;;;; +33FA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN;So;0;L;<compat> 0032 0037 65E5;;;;N;;;;; +33FB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT;So;0;L;<compat> 0032 0038 65E5;;;;N;;;;; +33FC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE;So;0;L;<compat> 0032 0039 65E5;;;;N;;;;; +33FD;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY;So;0;L;<compat> 0033 0030 65E5;;;;N;;;;; +33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L;<compat> 0033 0031 65E5;;;;N;;;;; +33FF;SQUARE GAL;So;0;ON;<square> 0067 0061 006C;;;;N;;;;; +3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;; +4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;; +4DC0;HEXAGRAM FOR THE CREATIVE HEAVEN;So;0;ON;;;;;N;;;;; +4DC1;HEXAGRAM FOR THE RECEPTIVE EARTH;So;0;ON;;;;;N;;;;; +4DC2;HEXAGRAM FOR DIFFICULTY AT THE BEGINNING;So;0;ON;;;;;N;;;;; +4DC3;HEXAGRAM FOR YOUTHFUL FOLLY;So;0;ON;;;;;N;;;;; +4DC4;HEXAGRAM FOR WAITING;So;0;ON;;;;;N;;;;; +4DC5;HEXAGRAM FOR CONFLICT;So;0;ON;;;;;N;;;;; +4DC6;HEXAGRAM FOR THE ARMY;So;0;ON;;;;;N;;;;; +4DC7;HEXAGRAM FOR HOLDING TOGETHER;So;0;ON;;;;;N;;;;; +4DC8;HEXAGRAM FOR SMALL TAMING;So;0;ON;;;;;N;;;;; +4DC9;HEXAGRAM FOR TREADING;So;0;ON;;;;;N;;;;; +4DCA;HEXAGRAM FOR PEACE;So;0;ON;;;;;N;;;;; +4DCB;HEXAGRAM FOR STANDSTILL;So;0;ON;;;;;N;;;;; +4DCC;HEXAGRAM FOR FELLOWSHIP;So;0;ON;;;;;N;;;;; +4DCD;HEXAGRAM FOR GREAT POSSESSION;So;0;ON;;;;;N;;;;; +4DCE;HEXAGRAM FOR MODESTY;So;0;ON;;;;;N;;;;; +4DCF;HEXAGRAM FOR ENTHUSIASM;So;0;ON;;;;;N;;;;; +4DD0;HEXAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;; +4DD1;HEXAGRAM FOR WORK ON THE DECAYED;So;0;ON;;;;;N;;;;; +4DD2;HEXAGRAM FOR APPROACH;So;0;ON;;;;;N;;;;; +4DD3;HEXAGRAM FOR CONTEMPLATION;So;0;ON;;;;;N;;;;; +4DD4;HEXAGRAM FOR BITING THROUGH;So;0;ON;;;;;N;;;;; +4DD5;HEXAGRAM FOR GRACE;So;0;ON;;;;;N;;;;; +4DD6;HEXAGRAM FOR SPLITTING APART;So;0;ON;;;;;N;;;;; +4DD7;HEXAGRAM FOR RETURN;So;0;ON;;;;;N;;;;; +4DD8;HEXAGRAM FOR INNOCENCE;So;0;ON;;;;;N;;;;; +4DD9;HEXAGRAM FOR GREAT TAMING;So;0;ON;;;;;N;;;;; +4DDA;HEXAGRAM FOR MOUTH CORNERS;So;0;ON;;;;;N;;;;; +4DDB;HEXAGRAM FOR GREAT PREPONDERANCE;So;0;ON;;;;;N;;;;; +4DDC;HEXAGRAM FOR THE ABYSMAL WATER;So;0;ON;;;;;N;;;;; +4DDD;HEXAGRAM FOR THE CLINGING FIRE;So;0;ON;;;;;N;;;;; +4DDE;HEXAGRAM FOR INFLUENCE;So;0;ON;;;;;N;;;;; +4DDF;HEXAGRAM FOR DURATION;So;0;ON;;;;;N;;;;; +4DE0;HEXAGRAM FOR RETREAT;So;0;ON;;;;;N;;;;; +4DE1;HEXAGRAM FOR GREAT POWER;So;0;ON;;;;;N;;;;; +4DE2;HEXAGRAM FOR PROGRESS;So;0;ON;;;;;N;;;;; +4DE3;HEXAGRAM FOR DARKENING OF THE LIGHT;So;0;ON;;;;;N;;;;; +4DE4;HEXAGRAM FOR THE FAMILY;So;0;ON;;;;;N;;;;; +4DE5;HEXAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;; +4DE6;HEXAGRAM FOR OBSTRUCTION;So;0;ON;;;;;N;;;;; +4DE7;HEXAGRAM FOR DELIVERANCE;So;0;ON;;;;;N;;;;; +4DE8;HEXAGRAM FOR DECREASE;So;0;ON;;;;;N;;;;; +4DE9;HEXAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;; +4DEA;HEXAGRAM FOR BREAKTHROUGH;So;0;ON;;;;;N;;;;; +4DEB;HEXAGRAM FOR COMING TO MEET;So;0;ON;;;;;N;;;;; +4DEC;HEXAGRAM FOR GATHERING TOGETHER;So;0;ON;;;;;N;;;;; +4DED;HEXAGRAM FOR PUSHING UPWARD;So;0;ON;;;;;N;;;;; +4DEE;HEXAGRAM FOR OPPRESSION;So;0;ON;;;;;N;;;;; +4DEF;HEXAGRAM FOR THE WELL;So;0;ON;;;;;N;;;;; +4DF0;HEXAGRAM FOR REVOLUTION;So;0;ON;;;;;N;;;;; +4DF1;HEXAGRAM FOR THE CAULDRON;So;0;ON;;;;;N;;;;; +4DF2;HEXAGRAM FOR THE AROUSING THUNDER;So;0;ON;;;;;N;;;;; +4DF3;HEXAGRAM FOR THE KEEPING STILL MOUNTAIN;So;0;ON;;;;;N;;;;; +4DF4;HEXAGRAM FOR DEVELOPMENT;So;0;ON;;;;;N;;;;; +4DF5;HEXAGRAM FOR THE MARRYING MAIDEN;So;0;ON;;;;;N;;;;; +4DF6;HEXAGRAM FOR ABUNDANCE;So;0;ON;;;;;N;;;;; +4DF7;HEXAGRAM FOR THE WANDERER;So;0;ON;;;;;N;;;;; +4DF8;HEXAGRAM FOR THE GENTLE WIND;So;0;ON;;;;;N;;;;; +4DF9;HEXAGRAM FOR THE JOYOUS LAKE;So;0;ON;;;;;N;;;;; +4DFA;HEXAGRAM FOR DISPERSION;So;0;ON;;;;;N;;;;; +4DFB;HEXAGRAM FOR LIMITATION;So;0;ON;;;;;N;;;;; +4DFC;HEXAGRAM FOR INNER TRUTH;So;0;ON;;;;;N;;;;; +4DFD;HEXAGRAM FOR SMALL PREPONDERANCE;So;0;ON;;;;;N;;;;; +4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;; +4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;; +4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;; +9FA5;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;; +A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; +A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; +A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; +A003;YI SYLLABLE IP;Lo;0;L;;;;;N;;;;; +A004;YI SYLLABLE IET;Lo;0;L;;;;;N;;;;; +A005;YI SYLLABLE IEX;Lo;0;L;;;;;N;;;;; +A006;YI SYLLABLE IE;Lo;0;L;;;;;N;;;;; +A007;YI SYLLABLE IEP;Lo;0;L;;;;;N;;;;; +A008;YI SYLLABLE AT;Lo;0;L;;;;;N;;;;; +A009;YI SYLLABLE AX;Lo;0;L;;;;;N;;;;; +A00A;YI SYLLABLE A;Lo;0;L;;;;;N;;;;; +A00B;YI SYLLABLE AP;Lo;0;L;;;;;N;;;;; +A00C;YI SYLLABLE UOX;Lo;0;L;;;;;N;;;;; +A00D;YI SYLLABLE UO;Lo;0;L;;;;;N;;;;; +A00E;YI SYLLABLE UOP;Lo;0;L;;;;;N;;;;; +A00F;YI SYLLABLE OT;Lo;0;L;;;;;N;;;;; +A010;YI SYLLABLE OX;Lo;0;L;;;;;N;;;;; +A011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;; +A012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;; +A013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;; +A014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;; +A015;YI SYLLABLE WU;Lo;0;L;;;;;N;;;;; +A016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;; +A017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;; +A018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;; +A019;YI SYLLABLE BIP;Lo;0;L;;;;;N;;;;; +A01A;YI SYLLABLE BIET;Lo;0;L;;;;;N;;;;; +A01B;YI SYLLABLE BIEX;Lo;0;L;;;;;N;;;;; +A01C;YI SYLLABLE BIE;Lo;0;L;;;;;N;;;;; +A01D;YI SYLLABLE BIEP;Lo;0;L;;;;;N;;;;; +A01E;YI SYLLABLE BAT;Lo;0;L;;;;;N;;;;; +A01F;YI SYLLABLE BAX;Lo;0;L;;;;;N;;;;; +A020;YI SYLLABLE BA;Lo;0;L;;;;;N;;;;; +A021;YI SYLLABLE BAP;Lo;0;L;;;;;N;;;;; +A022;YI SYLLABLE BUOX;Lo;0;L;;;;;N;;;;; +A023;YI SYLLABLE BUO;Lo;0;L;;;;;N;;;;; +A024;YI SYLLABLE BUOP;Lo;0;L;;;;;N;;;;; +A025;YI SYLLABLE BOT;Lo;0;L;;;;;N;;;;; +A026;YI SYLLABLE BOX;Lo;0;L;;;;;N;;;;; +A027;YI SYLLABLE BO;Lo;0;L;;;;;N;;;;; +A028;YI SYLLABLE BOP;Lo;0;L;;;;;N;;;;; +A029;YI SYLLABLE BEX;Lo;0;L;;;;;N;;;;; +A02A;YI SYLLABLE BE;Lo;0;L;;;;;N;;;;; +A02B;YI SYLLABLE BEP;Lo;0;L;;;;;N;;;;; +A02C;YI SYLLABLE BUT;Lo;0;L;;;;;N;;;;; +A02D;YI SYLLABLE BUX;Lo;0;L;;;;;N;;;;; +A02E;YI SYLLABLE BU;Lo;0;L;;;;;N;;;;; +A02F;YI SYLLABLE BUP;Lo;0;L;;;;;N;;;;; +A030;YI SYLLABLE BURX;Lo;0;L;;;;;N;;;;; +A031;YI SYLLABLE BUR;Lo;0;L;;;;;N;;;;; +A032;YI SYLLABLE BYT;Lo;0;L;;;;;N;;;;; +A033;YI SYLLABLE BYX;Lo;0;L;;;;;N;;;;; +A034;YI SYLLABLE BY;Lo;0;L;;;;;N;;;;; +A035;YI SYLLABLE BYP;Lo;0;L;;;;;N;;;;; +A036;YI SYLLABLE BYRX;Lo;0;L;;;;;N;;;;; +A037;YI SYLLABLE BYR;Lo;0;L;;;;;N;;;;; +A038;YI SYLLABLE PIT;Lo;0;L;;;;;N;;;;; +A039;YI SYLLABLE PIX;Lo;0;L;;;;;N;;;;; +A03A;YI SYLLABLE PI;Lo;0;L;;;;;N;;;;; +A03B;YI SYLLABLE PIP;Lo;0;L;;;;;N;;;;; +A03C;YI SYLLABLE PIEX;Lo;0;L;;;;;N;;;;; +A03D;YI SYLLABLE PIE;Lo;0;L;;;;;N;;;;; +A03E;YI SYLLABLE PIEP;Lo;0;L;;;;;N;;;;; +A03F;YI SYLLABLE PAT;Lo;0;L;;;;;N;;;;; +A040;YI SYLLABLE PAX;Lo;0;L;;;;;N;;;;; +A041;YI SYLLABLE PA;Lo;0;L;;;;;N;;;;; +A042;YI SYLLABLE PAP;Lo;0;L;;;;;N;;;;; +A043;YI SYLLABLE PUOX;Lo;0;L;;;;;N;;;;; +A044;YI SYLLABLE PUO;Lo;0;L;;;;;N;;;;; +A045;YI SYLLABLE PUOP;Lo;0;L;;;;;N;;;;; +A046;YI SYLLABLE POT;Lo;0;L;;;;;N;;;;; +A047;YI SYLLABLE POX;Lo;0;L;;;;;N;;;;; +A048;YI SYLLABLE PO;Lo;0;L;;;;;N;;;;; +A049;YI SYLLABLE POP;Lo;0;L;;;;;N;;;;; +A04A;YI SYLLABLE PUT;Lo;0;L;;;;;N;;;;; +A04B;YI SYLLABLE PUX;Lo;0;L;;;;;N;;;;; +A04C;YI SYLLABLE PU;Lo;0;L;;;;;N;;;;; +A04D;YI SYLLABLE PUP;Lo;0;L;;;;;N;;;;; +A04E;YI SYLLABLE PURX;Lo;0;L;;;;;N;;;;; +A04F;YI SYLLABLE PUR;Lo;0;L;;;;;N;;;;; +A050;YI SYLLABLE PYT;Lo;0;L;;;;;N;;;;; +A051;YI SYLLABLE PYX;Lo;0;L;;;;;N;;;;; +A052;YI SYLLABLE PY;Lo;0;L;;;;;N;;;;; +A053;YI SYLLABLE PYP;Lo;0;L;;;;;N;;;;; +A054;YI SYLLABLE PYRX;Lo;0;L;;;;;N;;;;; +A055;YI SYLLABLE PYR;Lo;0;L;;;;;N;;;;; +A056;YI SYLLABLE BBIT;Lo;0;L;;;;;N;;;;; +A057;YI SYLLABLE BBIX;Lo;0;L;;;;;N;;;;; +A058;YI SYLLABLE BBI;Lo;0;L;;;;;N;;;;; +A059;YI SYLLABLE BBIP;Lo;0;L;;;;;N;;;;; +A05A;YI SYLLABLE BBIET;Lo;0;L;;;;;N;;;;; +A05B;YI SYLLABLE BBIEX;Lo;0;L;;;;;N;;;;; +A05C;YI SYLLABLE BBIE;Lo;0;L;;;;;N;;;;; +A05D;YI SYLLABLE BBIEP;Lo;0;L;;;;;N;;;;; +A05E;YI SYLLABLE BBAT;Lo;0;L;;;;;N;;;;; +A05F;YI SYLLABLE BBAX;Lo;0;L;;;;;N;;;;; +A060;YI SYLLABLE BBA;Lo;0;L;;;;;N;;;;; +A061;YI SYLLABLE BBAP;Lo;0;L;;;;;N;;;;; +A062;YI SYLLABLE BBUOX;Lo;0;L;;;;;N;;;;; +A063;YI SYLLABLE BBUO;Lo;0;L;;;;;N;;;;; +A064;YI SYLLABLE BBUOP;Lo;0;L;;;;;N;;;;; +A065;YI SYLLABLE BBOT;Lo;0;L;;;;;N;;;;; +A066;YI SYLLABLE BBOX;Lo;0;L;;;;;N;;;;; +A067;YI SYLLABLE BBO;Lo;0;L;;;;;N;;;;; +A068;YI SYLLABLE BBOP;Lo;0;L;;;;;N;;;;; +A069;YI SYLLABLE BBEX;Lo;0;L;;;;;N;;;;; +A06A;YI SYLLABLE BBE;Lo;0;L;;;;;N;;;;; +A06B;YI SYLLABLE BBEP;Lo;0;L;;;;;N;;;;; +A06C;YI SYLLABLE BBUT;Lo;0;L;;;;;N;;;;; +A06D;YI SYLLABLE BBUX;Lo;0;L;;;;;N;;;;; +A06E;YI SYLLABLE BBU;Lo;0;L;;;;;N;;;;; +A06F;YI SYLLABLE BBUP;Lo;0;L;;;;;N;;;;; +A070;YI SYLLABLE BBURX;Lo;0;L;;;;;N;;;;; +A071;YI SYLLABLE BBUR;Lo;0;L;;;;;N;;;;; +A072;YI SYLLABLE BBYT;Lo;0;L;;;;;N;;;;; +A073;YI SYLLABLE BBYX;Lo;0;L;;;;;N;;;;; +A074;YI SYLLABLE BBY;Lo;0;L;;;;;N;;;;; +A075;YI SYLLABLE BBYP;Lo;0;L;;;;;N;;;;; +A076;YI SYLLABLE NBIT;Lo;0;L;;;;;N;;;;; +A077;YI SYLLABLE NBIX;Lo;0;L;;;;;N;;;;; +A078;YI SYLLABLE NBI;Lo;0;L;;;;;N;;;;; +A079;YI SYLLABLE NBIP;Lo;0;L;;;;;N;;;;; +A07A;YI SYLLABLE NBIEX;Lo;0;L;;;;;N;;;;; +A07B;YI SYLLABLE NBIE;Lo;0;L;;;;;N;;;;; +A07C;YI SYLLABLE NBIEP;Lo;0;L;;;;;N;;;;; +A07D;YI SYLLABLE NBAT;Lo;0;L;;;;;N;;;;; +A07E;YI SYLLABLE NBAX;Lo;0;L;;;;;N;;;;; +A07F;YI SYLLABLE NBA;Lo;0;L;;;;;N;;;;; +A080;YI SYLLABLE NBAP;Lo;0;L;;;;;N;;;;; +A081;YI SYLLABLE NBOT;Lo;0;L;;;;;N;;;;; +A082;YI SYLLABLE NBOX;Lo;0;L;;;;;N;;;;; +A083;YI SYLLABLE NBO;Lo;0;L;;;;;N;;;;; +A084;YI SYLLABLE NBOP;Lo;0;L;;;;;N;;;;; +A085;YI SYLLABLE NBUT;Lo;0;L;;;;;N;;;;; +A086;YI SYLLABLE NBUX;Lo;0;L;;;;;N;;;;; +A087;YI SYLLABLE NBU;Lo;0;L;;;;;N;;;;; +A088;YI SYLLABLE NBUP;Lo;0;L;;;;;N;;;;; +A089;YI SYLLABLE NBURX;Lo;0;L;;;;;N;;;;; +A08A;YI SYLLABLE NBUR;Lo;0;L;;;;;N;;;;; +A08B;YI SYLLABLE NBYT;Lo;0;L;;;;;N;;;;; +A08C;YI SYLLABLE NBYX;Lo;0;L;;;;;N;;;;; +A08D;YI SYLLABLE NBY;Lo;0;L;;;;;N;;;;; +A08E;YI SYLLABLE NBYP;Lo;0;L;;;;;N;;;;; +A08F;YI SYLLABLE NBYRX;Lo;0;L;;;;;N;;;;; +A090;YI SYLLABLE NBYR;Lo;0;L;;;;;N;;;;; +A091;YI SYLLABLE HMIT;Lo;0;L;;;;;N;;;;; +A092;YI SYLLABLE HMIX;Lo;0;L;;;;;N;;;;; +A093;YI SYLLABLE HMI;Lo;0;L;;;;;N;;;;; +A094;YI SYLLABLE HMIP;Lo;0;L;;;;;N;;;;; +A095;YI SYLLABLE HMIEX;Lo;0;L;;;;;N;;;;; +A096;YI SYLLABLE HMIE;Lo;0;L;;;;;N;;;;; +A097;YI SYLLABLE HMIEP;Lo;0;L;;;;;N;;;;; +A098;YI SYLLABLE HMAT;Lo;0;L;;;;;N;;;;; +A099;YI SYLLABLE HMAX;Lo;0;L;;;;;N;;;;; +A09A;YI SYLLABLE HMA;Lo;0;L;;;;;N;;;;; +A09B;YI SYLLABLE HMAP;Lo;0;L;;;;;N;;;;; +A09C;YI SYLLABLE HMUOX;Lo;0;L;;;;;N;;;;; +A09D;YI SYLLABLE HMUO;Lo;0;L;;;;;N;;;;; +A09E;YI SYLLABLE HMUOP;Lo;0;L;;;;;N;;;;; +A09F;YI SYLLABLE HMOT;Lo;0;L;;;;;N;;;;; +A0A0;YI SYLLABLE HMOX;Lo;0;L;;;;;N;;;;; +A0A1;YI SYLLABLE HMO;Lo;0;L;;;;;N;;;;; +A0A2;YI SYLLABLE HMOP;Lo;0;L;;;;;N;;;;; +A0A3;YI SYLLABLE HMUT;Lo;0;L;;;;;N;;;;; +A0A4;YI SYLLABLE HMUX;Lo;0;L;;;;;N;;;;; +A0A5;YI SYLLABLE HMU;Lo;0;L;;;;;N;;;;; +A0A6;YI SYLLABLE HMUP;Lo;0;L;;;;;N;;;;; +A0A7;YI SYLLABLE HMURX;Lo;0;L;;;;;N;;;;; +A0A8;YI SYLLABLE HMUR;Lo;0;L;;;;;N;;;;; +A0A9;YI SYLLABLE HMYX;Lo;0;L;;;;;N;;;;; +A0AA;YI SYLLABLE HMY;Lo;0;L;;;;;N;;;;; +A0AB;YI SYLLABLE HMYP;Lo;0;L;;;;;N;;;;; +A0AC;YI SYLLABLE HMYRX;Lo;0;L;;;;;N;;;;; +A0AD;YI SYLLABLE HMYR;Lo;0;L;;;;;N;;;;; +A0AE;YI SYLLABLE MIT;Lo;0;L;;;;;N;;;;; +A0AF;YI SYLLABLE MIX;Lo;0;L;;;;;N;;;;; +A0B0;YI SYLLABLE MI;Lo;0;L;;;;;N;;;;; +A0B1;YI SYLLABLE MIP;Lo;0;L;;;;;N;;;;; +A0B2;YI SYLLABLE MIEX;Lo;0;L;;;;;N;;;;; +A0B3;YI SYLLABLE MIE;Lo;0;L;;;;;N;;;;; +A0B4;YI SYLLABLE MIEP;Lo;0;L;;;;;N;;;;; +A0B5;YI SYLLABLE MAT;Lo;0;L;;;;;N;;;;; +A0B6;YI SYLLABLE MAX;Lo;0;L;;;;;N;;;;; +A0B7;YI SYLLABLE MA;Lo;0;L;;;;;N;;;;; +A0B8;YI SYLLABLE MAP;Lo;0;L;;;;;N;;;;; +A0B9;YI SYLLABLE MUOT;Lo;0;L;;;;;N;;;;; +A0BA;YI SYLLABLE MUOX;Lo;0;L;;;;;N;;;;; +A0BB;YI SYLLABLE MUO;Lo;0;L;;;;;N;;;;; +A0BC;YI SYLLABLE MUOP;Lo;0;L;;;;;N;;;;; +A0BD;YI SYLLABLE MOT;Lo;0;L;;;;;N;;;;; +A0BE;YI SYLLABLE MOX;Lo;0;L;;;;;N;;;;; +A0BF;YI SYLLABLE MO;Lo;0;L;;;;;N;;;;; +A0C0;YI SYLLABLE MOP;Lo;0;L;;;;;N;;;;; +A0C1;YI SYLLABLE MEX;Lo;0;L;;;;;N;;;;; +A0C2;YI SYLLABLE ME;Lo;0;L;;;;;N;;;;; +A0C3;YI SYLLABLE MUT;Lo;0;L;;;;;N;;;;; +A0C4;YI SYLLABLE MUX;Lo;0;L;;;;;N;;;;; +A0C5;YI SYLLABLE MU;Lo;0;L;;;;;N;;;;; +A0C6;YI SYLLABLE MUP;Lo;0;L;;;;;N;;;;; +A0C7;YI SYLLABLE MURX;Lo;0;L;;;;;N;;;;; +A0C8;YI SYLLABLE MUR;Lo;0;L;;;;;N;;;;; +A0C9;YI SYLLABLE MYT;Lo;0;L;;;;;N;;;;; +A0CA;YI SYLLABLE MYX;Lo;0;L;;;;;N;;;;; +A0CB;YI SYLLABLE MY;Lo;0;L;;;;;N;;;;; +A0CC;YI SYLLABLE MYP;Lo;0;L;;;;;N;;;;; +A0CD;YI SYLLABLE FIT;Lo;0;L;;;;;N;;;;; +A0CE;YI SYLLABLE FIX;Lo;0;L;;;;;N;;;;; +A0CF;YI SYLLABLE FI;Lo;0;L;;;;;N;;;;; +A0D0;YI SYLLABLE FIP;Lo;0;L;;;;;N;;;;; +A0D1;YI SYLLABLE FAT;Lo;0;L;;;;;N;;;;; +A0D2;YI SYLLABLE FAX;Lo;0;L;;;;;N;;;;; +A0D3;YI SYLLABLE FA;Lo;0;L;;;;;N;;;;; +A0D4;YI SYLLABLE FAP;Lo;0;L;;;;;N;;;;; +A0D5;YI SYLLABLE FOX;Lo;0;L;;;;;N;;;;; +A0D6;YI SYLLABLE FO;Lo;0;L;;;;;N;;;;; +A0D7;YI SYLLABLE FOP;Lo;0;L;;;;;N;;;;; +A0D8;YI SYLLABLE FUT;Lo;0;L;;;;;N;;;;; +A0D9;YI SYLLABLE FUX;Lo;0;L;;;;;N;;;;; +A0DA;YI SYLLABLE FU;Lo;0;L;;;;;N;;;;; +A0DB;YI SYLLABLE FUP;Lo;0;L;;;;;N;;;;; +A0DC;YI SYLLABLE FURX;Lo;0;L;;;;;N;;;;; +A0DD;YI SYLLABLE FUR;Lo;0;L;;;;;N;;;;; +A0DE;YI SYLLABLE FYT;Lo;0;L;;;;;N;;;;; +A0DF;YI SYLLABLE FYX;Lo;0;L;;;;;N;;;;; +A0E0;YI SYLLABLE FY;Lo;0;L;;;;;N;;;;; +A0E1;YI SYLLABLE FYP;Lo;0;L;;;;;N;;;;; +A0E2;YI SYLLABLE VIT;Lo;0;L;;;;;N;;;;; +A0E3;YI SYLLABLE VIX;Lo;0;L;;;;;N;;;;; +A0E4;YI SYLLABLE VI;Lo;0;L;;;;;N;;;;; +A0E5;YI SYLLABLE VIP;Lo;0;L;;;;;N;;;;; +A0E6;YI SYLLABLE VIET;Lo;0;L;;;;;N;;;;; +A0E7;YI SYLLABLE VIEX;Lo;0;L;;;;;N;;;;; +A0E8;YI SYLLABLE VIE;Lo;0;L;;;;;N;;;;; +A0E9;YI SYLLABLE VIEP;Lo;0;L;;;;;N;;;;; +A0EA;YI SYLLABLE VAT;Lo;0;L;;;;;N;;;;; +A0EB;YI SYLLABLE VAX;Lo;0;L;;;;;N;;;;; +A0EC;YI SYLLABLE VA;Lo;0;L;;;;;N;;;;; +A0ED;YI SYLLABLE VAP;Lo;0;L;;;;;N;;;;; +A0EE;YI SYLLABLE VOT;Lo;0;L;;;;;N;;;;; +A0EF;YI SYLLABLE VOX;Lo;0;L;;;;;N;;;;; +A0F0;YI SYLLABLE VO;Lo;0;L;;;;;N;;;;; +A0F1;YI SYLLABLE VOP;Lo;0;L;;;;;N;;;;; +A0F2;YI SYLLABLE VEX;Lo;0;L;;;;;N;;;;; +A0F3;YI SYLLABLE VEP;Lo;0;L;;;;;N;;;;; +A0F4;YI SYLLABLE VUT;Lo;0;L;;;;;N;;;;; +A0F5;YI SYLLABLE VUX;Lo;0;L;;;;;N;;;;; +A0F6;YI SYLLABLE VU;Lo;0;L;;;;;N;;;;; +A0F7;YI SYLLABLE VUP;Lo;0;L;;;;;N;;;;; +A0F8;YI SYLLABLE VURX;Lo;0;L;;;;;N;;;;; +A0F9;YI SYLLABLE VUR;Lo;0;L;;;;;N;;;;; +A0FA;YI SYLLABLE VYT;Lo;0;L;;;;;N;;;;; +A0FB;YI SYLLABLE VYX;Lo;0;L;;;;;N;;;;; +A0FC;YI SYLLABLE VY;Lo;0;L;;;;;N;;;;; +A0FD;YI SYLLABLE VYP;Lo;0;L;;;;;N;;;;; +A0FE;YI SYLLABLE VYRX;Lo;0;L;;;;;N;;;;; +A0FF;YI SYLLABLE VYR;Lo;0;L;;;;;N;;;;; +A100;YI SYLLABLE DIT;Lo;0;L;;;;;N;;;;; +A101;YI SYLLABLE DIX;Lo;0;L;;;;;N;;;;; +A102;YI SYLLABLE DI;Lo;0;L;;;;;N;;;;; +A103;YI SYLLABLE DIP;Lo;0;L;;;;;N;;;;; +A104;YI SYLLABLE DIEX;Lo;0;L;;;;;N;;;;; +A105;YI SYLLABLE DIE;Lo;0;L;;;;;N;;;;; +A106;YI SYLLABLE DIEP;Lo;0;L;;;;;N;;;;; +A107;YI SYLLABLE DAT;Lo;0;L;;;;;N;;;;; +A108;YI SYLLABLE DAX;Lo;0;L;;;;;N;;;;; +A109;YI SYLLABLE DA;Lo;0;L;;;;;N;;;;; +A10A;YI SYLLABLE DAP;Lo;0;L;;;;;N;;;;; +A10B;YI SYLLABLE DUOX;Lo;0;L;;;;;N;;;;; +A10C;YI SYLLABLE DUO;Lo;0;L;;;;;N;;;;; +A10D;YI SYLLABLE DOT;Lo;0;L;;;;;N;;;;; +A10E;YI SYLLABLE DOX;Lo;0;L;;;;;N;;;;; +A10F;YI SYLLABLE DO;Lo;0;L;;;;;N;;;;; +A110;YI SYLLABLE DOP;Lo;0;L;;;;;N;;;;; +A111;YI SYLLABLE DEX;Lo;0;L;;;;;N;;;;; +A112;YI SYLLABLE DE;Lo;0;L;;;;;N;;;;; +A113;YI SYLLABLE DEP;Lo;0;L;;;;;N;;;;; +A114;YI SYLLABLE DUT;Lo;0;L;;;;;N;;;;; +A115;YI SYLLABLE DUX;Lo;0;L;;;;;N;;;;; +A116;YI SYLLABLE DU;Lo;0;L;;;;;N;;;;; +A117;YI SYLLABLE DUP;Lo;0;L;;;;;N;;;;; +A118;YI SYLLABLE DURX;Lo;0;L;;;;;N;;;;; +A119;YI SYLLABLE DUR;Lo;0;L;;;;;N;;;;; +A11A;YI SYLLABLE TIT;Lo;0;L;;;;;N;;;;; +A11B;YI SYLLABLE TIX;Lo;0;L;;;;;N;;;;; +A11C;YI SYLLABLE TI;Lo;0;L;;;;;N;;;;; +A11D;YI SYLLABLE TIP;Lo;0;L;;;;;N;;;;; +A11E;YI SYLLABLE TIEX;Lo;0;L;;;;;N;;;;; +A11F;YI SYLLABLE TIE;Lo;0;L;;;;;N;;;;; +A120;YI SYLLABLE TIEP;Lo;0;L;;;;;N;;;;; +A121;YI SYLLABLE TAT;Lo;0;L;;;;;N;;;;; +A122;YI SYLLABLE TAX;Lo;0;L;;;;;N;;;;; +A123;YI SYLLABLE TA;Lo;0;L;;;;;N;;;;; +A124;YI SYLLABLE TAP;Lo;0;L;;;;;N;;;;; +A125;YI SYLLABLE TUOT;Lo;0;L;;;;;N;;;;; +A126;YI SYLLABLE TUOX;Lo;0;L;;;;;N;;;;; +A127;YI SYLLABLE TUO;Lo;0;L;;;;;N;;;;; +A128;YI SYLLABLE TUOP;Lo;0;L;;;;;N;;;;; +A129;YI SYLLABLE TOT;Lo;0;L;;;;;N;;;;; +A12A;YI SYLLABLE TOX;Lo;0;L;;;;;N;;;;; +A12B;YI SYLLABLE TO;Lo;0;L;;;;;N;;;;; +A12C;YI SYLLABLE TOP;Lo;0;L;;;;;N;;;;; +A12D;YI SYLLABLE TEX;Lo;0;L;;;;;N;;;;; +A12E;YI SYLLABLE TE;Lo;0;L;;;;;N;;;;; +A12F;YI SYLLABLE TEP;Lo;0;L;;;;;N;;;;; +A130;YI SYLLABLE TUT;Lo;0;L;;;;;N;;;;; +A131;YI SYLLABLE TUX;Lo;0;L;;;;;N;;;;; +A132;YI SYLLABLE TU;Lo;0;L;;;;;N;;;;; +A133;YI SYLLABLE TUP;Lo;0;L;;;;;N;;;;; +A134;YI SYLLABLE TURX;Lo;0;L;;;;;N;;;;; +A135;YI SYLLABLE TUR;Lo;0;L;;;;;N;;;;; +A136;YI SYLLABLE DDIT;Lo;0;L;;;;;N;;;;; +A137;YI SYLLABLE DDIX;Lo;0;L;;;;;N;;;;; +A138;YI SYLLABLE DDI;Lo;0;L;;;;;N;;;;; +A139;YI SYLLABLE DDIP;Lo;0;L;;;;;N;;;;; +A13A;YI SYLLABLE DDIEX;Lo;0;L;;;;;N;;;;; +A13B;YI SYLLABLE DDIE;Lo;0;L;;;;;N;;;;; +A13C;YI SYLLABLE DDIEP;Lo;0;L;;;;;N;;;;; +A13D;YI SYLLABLE DDAT;Lo;0;L;;;;;N;;;;; +A13E;YI SYLLABLE DDAX;Lo;0;L;;;;;N;;;;; +A13F;YI SYLLABLE DDA;Lo;0;L;;;;;N;;;;; +A140;YI SYLLABLE DDAP;Lo;0;L;;;;;N;;;;; +A141;YI SYLLABLE DDUOX;Lo;0;L;;;;;N;;;;; +A142;YI SYLLABLE DDUO;Lo;0;L;;;;;N;;;;; +A143;YI SYLLABLE DDUOP;Lo;0;L;;;;;N;;;;; +A144;YI SYLLABLE DDOT;Lo;0;L;;;;;N;;;;; +A145;YI SYLLABLE DDOX;Lo;0;L;;;;;N;;;;; +A146;YI SYLLABLE DDO;Lo;0;L;;;;;N;;;;; +A147;YI SYLLABLE DDOP;Lo;0;L;;;;;N;;;;; +A148;YI SYLLABLE DDEX;Lo;0;L;;;;;N;;;;; +A149;YI SYLLABLE DDE;Lo;0;L;;;;;N;;;;; +A14A;YI SYLLABLE DDEP;Lo;0;L;;;;;N;;;;; +A14B;YI SYLLABLE DDUT;Lo;0;L;;;;;N;;;;; +A14C;YI SYLLABLE DDUX;Lo;0;L;;;;;N;;;;; +A14D;YI SYLLABLE DDU;Lo;0;L;;;;;N;;;;; +A14E;YI SYLLABLE DDUP;Lo;0;L;;;;;N;;;;; +A14F;YI SYLLABLE DDURX;Lo;0;L;;;;;N;;;;; +A150;YI SYLLABLE DDUR;Lo;0;L;;;;;N;;;;; +A151;YI SYLLABLE NDIT;Lo;0;L;;;;;N;;;;; +A152;YI SYLLABLE NDIX;Lo;0;L;;;;;N;;;;; +A153;YI SYLLABLE NDI;Lo;0;L;;;;;N;;;;; +A154;YI SYLLABLE NDIP;Lo;0;L;;;;;N;;;;; +A155;YI SYLLABLE NDIEX;Lo;0;L;;;;;N;;;;; +A156;YI SYLLABLE NDIE;Lo;0;L;;;;;N;;;;; +A157;YI SYLLABLE NDAT;Lo;0;L;;;;;N;;;;; +A158;YI SYLLABLE NDAX;Lo;0;L;;;;;N;;;;; +A159;YI SYLLABLE NDA;Lo;0;L;;;;;N;;;;; +A15A;YI SYLLABLE NDAP;Lo;0;L;;;;;N;;;;; +A15B;YI SYLLABLE NDOT;Lo;0;L;;;;;N;;;;; +A15C;YI SYLLABLE NDOX;Lo;0;L;;;;;N;;;;; +A15D;YI SYLLABLE NDO;Lo;0;L;;;;;N;;;;; +A15E;YI SYLLABLE NDOP;Lo;0;L;;;;;N;;;;; +A15F;YI SYLLABLE NDEX;Lo;0;L;;;;;N;;;;; +A160;YI SYLLABLE NDE;Lo;0;L;;;;;N;;;;; +A161;YI SYLLABLE NDEP;Lo;0;L;;;;;N;;;;; +A162;YI SYLLABLE NDUT;Lo;0;L;;;;;N;;;;; +A163;YI SYLLABLE NDUX;Lo;0;L;;;;;N;;;;; +A164;YI SYLLABLE NDU;Lo;0;L;;;;;N;;;;; +A165;YI SYLLABLE NDUP;Lo;0;L;;;;;N;;;;; +A166;YI SYLLABLE NDURX;Lo;0;L;;;;;N;;;;; +A167;YI SYLLABLE NDUR;Lo;0;L;;;;;N;;;;; +A168;YI SYLLABLE HNIT;Lo;0;L;;;;;N;;;;; +A169;YI SYLLABLE HNIX;Lo;0;L;;;;;N;;;;; +A16A;YI SYLLABLE HNI;Lo;0;L;;;;;N;;;;; +A16B;YI SYLLABLE HNIP;Lo;0;L;;;;;N;;;;; +A16C;YI SYLLABLE HNIET;Lo;0;L;;;;;N;;;;; +A16D;YI SYLLABLE HNIEX;Lo;0;L;;;;;N;;;;; +A16E;YI SYLLABLE HNIE;Lo;0;L;;;;;N;;;;; +A16F;YI SYLLABLE HNIEP;Lo;0;L;;;;;N;;;;; +A170;YI SYLLABLE HNAT;Lo;0;L;;;;;N;;;;; +A171;YI SYLLABLE HNAX;Lo;0;L;;;;;N;;;;; +A172;YI SYLLABLE HNA;Lo;0;L;;;;;N;;;;; +A173;YI SYLLABLE HNAP;Lo;0;L;;;;;N;;;;; +A174;YI SYLLABLE HNUOX;Lo;0;L;;;;;N;;;;; +A175;YI SYLLABLE HNUO;Lo;0;L;;;;;N;;;;; +A176;YI SYLLABLE HNOT;Lo;0;L;;;;;N;;;;; +A177;YI SYLLABLE HNOX;Lo;0;L;;;;;N;;;;; +A178;YI SYLLABLE HNOP;Lo;0;L;;;;;N;;;;; +A179;YI SYLLABLE HNEX;Lo;0;L;;;;;N;;;;; +A17A;YI SYLLABLE HNE;Lo;0;L;;;;;N;;;;; +A17B;YI SYLLABLE HNEP;Lo;0;L;;;;;N;;;;; +A17C;YI SYLLABLE HNUT;Lo;0;L;;;;;N;;;;; +A17D;YI SYLLABLE NIT;Lo;0;L;;;;;N;;;;; +A17E;YI SYLLABLE NIX;Lo;0;L;;;;;N;;;;; +A17F;YI SYLLABLE NI;Lo;0;L;;;;;N;;;;; +A180;YI SYLLABLE NIP;Lo;0;L;;;;;N;;;;; +A181;YI SYLLABLE NIEX;Lo;0;L;;;;;N;;;;; +A182;YI SYLLABLE NIE;Lo;0;L;;;;;N;;;;; +A183;YI SYLLABLE NIEP;Lo;0;L;;;;;N;;;;; +A184;YI SYLLABLE NAX;Lo;0;L;;;;;N;;;;; +A185;YI SYLLABLE NA;Lo;0;L;;;;;N;;;;; +A186;YI SYLLABLE NAP;Lo;0;L;;;;;N;;;;; +A187;YI SYLLABLE NUOX;Lo;0;L;;;;;N;;;;; +A188;YI SYLLABLE NUO;Lo;0;L;;;;;N;;;;; +A189;YI SYLLABLE NUOP;Lo;0;L;;;;;N;;;;; +A18A;YI SYLLABLE NOT;Lo;0;L;;;;;N;;;;; +A18B;YI SYLLABLE NOX;Lo;0;L;;;;;N;;;;; +A18C;YI SYLLABLE NO;Lo;0;L;;;;;N;;;;; +A18D;YI SYLLABLE NOP;Lo;0;L;;;;;N;;;;; +A18E;YI SYLLABLE NEX;Lo;0;L;;;;;N;;;;; +A18F;YI SYLLABLE NE;Lo;0;L;;;;;N;;;;; +A190;YI SYLLABLE NEP;Lo;0;L;;;;;N;;;;; +A191;YI SYLLABLE NUT;Lo;0;L;;;;;N;;;;; +A192;YI SYLLABLE NUX;Lo;0;L;;;;;N;;;;; +A193;YI SYLLABLE NU;Lo;0;L;;;;;N;;;;; +A194;YI SYLLABLE NUP;Lo;0;L;;;;;N;;;;; +A195;YI SYLLABLE NURX;Lo;0;L;;;;;N;;;;; +A196;YI SYLLABLE NUR;Lo;0;L;;;;;N;;;;; +A197;YI SYLLABLE HLIT;Lo;0;L;;;;;N;;;;; +A198;YI SYLLABLE HLIX;Lo;0;L;;;;;N;;;;; +A199;YI SYLLABLE HLI;Lo;0;L;;;;;N;;;;; +A19A;YI SYLLABLE HLIP;Lo;0;L;;;;;N;;;;; +A19B;YI SYLLABLE HLIEX;Lo;0;L;;;;;N;;;;; +A19C;YI SYLLABLE HLIE;Lo;0;L;;;;;N;;;;; +A19D;YI SYLLABLE HLIEP;Lo;0;L;;;;;N;;;;; +A19E;YI SYLLABLE HLAT;Lo;0;L;;;;;N;;;;; +A19F;YI SYLLABLE HLAX;Lo;0;L;;;;;N;;;;; +A1A0;YI SYLLABLE HLA;Lo;0;L;;;;;N;;;;; +A1A1;YI SYLLABLE HLAP;Lo;0;L;;;;;N;;;;; +A1A2;YI SYLLABLE HLUOX;Lo;0;L;;;;;N;;;;; +A1A3;YI SYLLABLE HLUO;Lo;0;L;;;;;N;;;;; +A1A4;YI SYLLABLE HLUOP;Lo;0;L;;;;;N;;;;; +A1A5;YI SYLLABLE HLOX;Lo;0;L;;;;;N;;;;; +A1A6;YI SYLLABLE HLO;Lo;0;L;;;;;N;;;;; +A1A7;YI SYLLABLE HLOP;Lo;0;L;;;;;N;;;;; +A1A8;YI SYLLABLE HLEX;Lo;0;L;;;;;N;;;;; +A1A9;YI SYLLABLE HLE;Lo;0;L;;;;;N;;;;; +A1AA;YI SYLLABLE HLEP;Lo;0;L;;;;;N;;;;; +A1AB;YI SYLLABLE HLUT;Lo;0;L;;;;;N;;;;; +A1AC;YI SYLLABLE HLUX;Lo;0;L;;;;;N;;;;; +A1AD;YI SYLLABLE HLU;Lo;0;L;;;;;N;;;;; +A1AE;YI SYLLABLE HLUP;Lo;0;L;;;;;N;;;;; +A1AF;YI SYLLABLE HLURX;Lo;0;L;;;;;N;;;;; +A1B0;YI SYLLABLE HLUR;Lo;0;L;;;;;N;;;;; +A1B1;YI SYLLABLE HLYT;Lo;0;L;;;;;N;;;;; +A1B2;YI SYLLABLE HLYX;Lo;0;L;;;;;N;;;;; +A1B3;YI SYLLABLE HLY;Lo;0;L;;;;;N;;;;; +A1B4;YI SYLLABLE HLYP;Lo;0;L;;;;;N;;;;; +A1B5;YI SYLLABLE HLYRX;Lo;0;L;;;;;N;;;;; +A1B6;YI SYLLABLE HLYR;Lo;0;L;;;;;N;;;;; +A1B7;YI SYLLABLE LIT;Lo;0;L;;;;;N;;;;; +A1B8;YI SYLLABLE LIX;Lo;0;L;;;;;N;;;;; +A1B9;YI SYLLABLE LI;Lo;0;L;;;;;N;;;;; +A1BA;YI SYLLABLE LIP;Lo;0;L;;;;;N;;;;; +A1BB;YI SYLLABLE LIET;Lo;0;L;;;;;N;;;;; +A1BC;YI SYLLABLE LIEX;Lo;0;L;;;;;N;;;;; +A1BD;YI SYLLABLE LIE;Lo;0;L;;;;;N;;;;; +A1BE;YI SYLLABLE LIEP;Lo;0;L;;;;;N;;;;; +A1BF;YI SYLLABLE LAT;Lo;0;L;;;;;N;;;;; +A1C0;YI SYLLABLE LAX;Lo;0;L;;;;;N;;;;; +A1C1;YI SYLLABLE LA;Lo;0;L;;;;;N;;;;; +A1C2;YI SYLLABLE LAP;Lo;0;L;;;;;N;;;;; +A1C3;YI SYLLABLE LUOT;Lo;0;L;;;;;N;;;;; +A1C4;YI SYLLABLE LUOX;Lo;0;L;;;;;N;;;;; +A1C5;YI SYLLABLE LUO;Lo;0;L;;;;;N;;;;; +A1C6;YI SYLLABLE LUOP;Lo;0;L;;;;;N;;;;; +A1C7;YI SYLLABLE LOT;Lo;0;L;;;;;N;;;;; +A1C8;YI SYLLABLE LOX;Lo;0;L;;;;;N;;;;; +A1C9;YI SYLLABLE LO;Lo;0;L;;;;;N;;;;; +A1CA;YI SYLLABLE LOP;Lo;0;L;;;;;N;;;;; +A1CB;YI SYLLABLE LEX;Lo;0;L;;;;;N;;;;; +A1CC;YI SYLLABLE LE;Lo;0;L;;;;;N;;;;; +A1CD;YI SYLLABLE LEP;Lo;0;L;;;;;N;;;;; +A1CE;YI SYLLABLE LUT;Lo;0;L;;;;;N;;;;; +A1CF;YI SYLLABLE LUX;Lo;0;L;;;;;N;;;;; +A1D0;YI SYLLABLE LU;Lo;0;L;;;;;N;;;;; +A1D1;YI SYLLABLE LUP;Lo;0;L;;;;;N;;;;; +A1D2;YI SYLLABLE LURX;Lo;0;L;;;;;N;;;;; +A1D3;YI SYLLABLE LUR;Lo;0;L;;;;;N;;;;; +A1D4;YI SYLLABLE LYT;Lo;0;L;;;;;N;;;;; +A1D5;YI SYLLABLE LYX;Lo;0;L;;;;;N;;;;; +A1D6;YI SYLLABLE LY;Lo;0;L;;;;;N;;;;; +A1D7;YI SYLLABLE LYP;Lo;0;L;;;;;N;;;;; +A1D8;YI SYLLABLE LYRX;Lo;0;L;;;;;N;;;;; +A1D9;YI SYLLABLE LYR;Lo;0;L;;;;;N;;;;; +A1DA;YI SYLLABLE GIT;Lo;0;L;;;;;N;;;;; +A1DB;YI SYLLABLE GIX;Lo;0;L;;;;;N;;;;; +A1DC;YI SYLLABLE GI;Lo;0;L;;;;;N;;;;; +A1DD;YI SYLLABLE GIP;Lo;0;L;;;;;N;;;;; +A1DE;YI SYLLABLE GIET;Lo;0;L;;;;;N;;;;; +A1DF;YI SYLLABLE GIEX;Lo;0;L;;;;;N;;;;; +A1E0;YI SYLLABLE GIE;Lo;0;L;;;;;N;;;;; +A1E1;YI SYLLABLE GIEP;Lo;0;L;;;;;N;;;;; +A1E2;YI SYLLABLE GAT;Lo;0;L;;;;;N;;;;; +A1E3;YI SYLLABLE GAX;Lo;0;L;;;;;N;;;;; +A1E4;YI SYLLABLE GA;Lo;0;L;;;;;N;;;;; +A1E5;YI SYLLABLE GAP;Lo;0;L;;;;;N;;;;; +A1E6;YI SYLLABLE GUOT;Lo;0;L;;;;;N;;;;; +A1E7;YI SYLLABLE GUOX;Lo;0;L;;;;;N;;;;; +A1E8;YI SYLLABLE GUO;Lo;0;L;;;;;N;;;;; +A1E9;YI SYLLABLE GUOP;Lo;0;L;;;;;N;;;;; +A1EA;YI SYLLABLE GOT;Lo;0;L;;;;;N;;;;; +A1EB;YI SYLLABLE GOX;Lo;0;L;;;;;N;;;;; +A1EC;YI SYLLABLE GO;Lo;0;L;;;;;N;;;;; +A1ED;YI SYLLABLE GOP;Lo;0;L;;;;;N;;;;; +A1EE;YI SYLLABLE GET;Lo;0;L;;;;;N;;;;; +A1EF;YI SYLLABLE GEX;Lo;0;L;;;;;N;;;;; +A1F0;YI SYLLABLE GE;Lo;0;L;;;;;N;;;;; +A1F1;YI SYLLABLE GEP;Lo;0;L;;;;;N;;;;; +A1F2;YI SYLLABLE GUT;Lo;0;L;;;;;N;;;;; +A1F3;YI SYLLABLE GUX;Lo;0;L;;;;;N;;;;; +A1F4;YI SYLLABLE GU;Lo;0;L;;;;;N;;;;; +A1F5;YI SYLLABLE GUP;Lo;0;L;;;;;N;;;;; +A1F6;YI SYLLABLE GURX;Lo;0;L;;;;;N;;;;; +A1F7;YI SYLLABLE GUR;Lo;0;L;;;;;N;;;;; +A1F8;YI SYLLABLE KIT;Lo;0;L;;;;;N;;;;; +A1F9;YI SYLLABLE KIX;Lo;0;L;;;;;N;;;;; +A1FA;YI SYLLABLE KI;Lo;0;L;;;;;N;;;;; +A1FB;YI SYLLABLE KIP;Lo;0;L;;;;;N;;;;; +A1FC;YI SYLLABLE KIEX;Lo;0;L;;;;;N;;;;; +A1FD;YI SYLLABLE KIE;Lo;0;L;;;;;N;;;;; +A1FE;YI SYLLABLE KIEP;Lo;0;L;;;;;N;;;;; +A1FF;YI SYLLABLE KAT;Lo;0;L;;;;;N;;;;; +A200;YI SYLLABLE KAX;Lo;0;L;;;;;N;;;;; +A201;YI SYLLABLE KA;Lo;0;L;;;;;N;;;;; +A202;YI SYLLABLE KAP;Lo;0;L;;;;;N;;;;; +A203;YI SYLLABLE KUOX;Lo;0;L;;;;;N;;;;; +A204;YI SYLLABLE KUO;Lo;0;L;;;;;N;;;;; +A205;YI SYLLABLE KUOP;Lo;0;L;;;;;N;;;;; +A206;YI SYLLABLE KOT;Lo;0;L;;;;;N;;;;; +A207;YI SYLLABLE KOX;Lo;0;L;;;;;N;;;;; +A208;YI SYLLABLE KO;Lo;0;L;;;;;N;;;;; +A209;YI SYLLABLE KOP;Lo;0;L;;;;;N;;;;; +A20A;YI SYLLABLE KET;Lo;0;L;;;;;N;;;;; +A20B;YI SYLLABLE KEX;Lo;0;L;;;;;N;;;;; +A20C;YI SYLLABLE KE;Lo;0;L;;;;;N;;;;; +A20D;YI SYLLABLE KEP;Lo;0;L;;;;;N;;;;; +A20E;YI SYLLABLE KUT;Lo;0;L;;;;;N;;;;; +A20F;YI SYLLABLE KUX;Lo;0;L;;;;;N;;;;; +A210;YI SYLLABLE KU;Lo;0;L;;;;;N;;;;; +A211;YI SYLLABLE KUP;Lo;0;L;;;;;N;;;;; +A212;YI SYLLABLE KURX;Lo;0;L;;;;;N;;;;; +A213;YI SYLLABLE KUR;Lo;0;L;;;;;N;;;;; +A214;YI SYLLABLE GGIT;Lo;0;L;;;;;N;;;;; +A215;YI SYLLABLE GGIX;Lo;0;L;;;;;N;;;;; +A216;YI SYLLABLE GGI;Lo;0;L;;;;;N;;;;; +A217;YI SYLLABLE GGIEX;Lo;0;L;;;;;N;;;;; +A218;YI SYLLABLE GGIE;Lo;0;L;;;;;N;;;;; +A219;YI SYLLABLE GGIEP;Lo;0;L;;;;;N;;;;; +A21A;YI SYLLABLE GGAT;Lo;0;L;;;;;N;;;;; +A21B;YI SYLLABLE GGAX;Lo;0;L;;;;;N;;;;; +A21C;YI SYLLABLE GGA;Lo;0;L;;;;;N;;;;; +A21D;YI SYLLABLE GGAP;Lo;0;L;;;;;N;;;;; +A21E;YI SYLLABLE GGUOT;Lo;0;L;;;;;N;;;;; +A21F;YI SYLLABLE GGUOX;Lo;0;L;;;;;N;;;;; +A220;YI SYLLABLE GGUO;Lo;0;L;;;;;N;;;;; +A221;YI SYLLABLE GGUOP;Lo;0;L;;;;;N;;;;; +A222;YI SYLLABLE GGOT;Lo;0;L;;;;;N;;;;; +A223;YI SYLLABLE GGOX;Lo;0;L;;;;;N;;;;; +A224;YI SYLLABLE GGO;Lo;0;L;;;;;N;;;;; +A225;YI SYLLABLE GGOP;Lo;0;L;;;;;N;;;;; +A226;YI SYLLABLE GGET;Lo;0;L;;;;;N;;;;; +A227;YI SYLLABLE GGEX;Lo;0;L;;;;;N;;;;; +A228;YI SYLLABLE GGE;Lo;0;L;;;;;N;;;;; +A229;YI SYLLABLE GGEP;Lo;0;L;;;;;N;;;;; +A22A;YI SYLLABLE GGUT;Lo;0;L;;;;;N;;;;; +A22B;YI SYLLABLE GGUX;Lo;0;L;;;;;N;;;;; +A22C;YI SYLLABLE GGU;Lo;0;L;;;;;N;;;;; +A22D;YI SYLLABLE GGUP;Lo;0;L;;;;;N;;;;; +A22E;YI SYLLABLE GGURX;Lo;0;L;;;;;N;;;;; +A22F;YI SYLLABLE GGUR;Lo;0;L;;;;;N;;;;; +A230;YI SYLLABLE MGIEX;Lo;0;L;;;;;N;;;;; +A231;YI SYLLABLE MGIE;Lo;0;L;;;;;N;;;;; +A232;YI SYLLABLE MGAT;Lo;0;L;;;;;N;;;;; +A233;YI SYLLABLE MGAX;Lo;0;L;;;;;N;;;;; +A234;YI SYLLABLE MGA;Lo;0;L;;;;;N;;;;; +A235;YI SYLLABLE MGAP;Lo;0;L;;;;;N;;;;; +A236;YI SYLLABLE MGUOX;Lo;0;L;;;;;N;;;;; +A237;YI SYLLABLE MGUO;Lo;0;L;;;;;N;;;;; +A238;YI SYLLABLE MGUOP;Lo;0;L;;;;;N;;;;; +A239;YI SYLLABLE MGOT;Lo;0;L;;;;;N;;;;; +A23A;YI SYLLABLE MGOX;Lo;0;L;;;;;N;;;;; +A23B;YI SYLLABLE MGO;Lo;0;L;;;;;N;;;;; +A23C;YI SYLLABLE MGOP;Lo;0;L;;;;;N;;;;; +A23D;YI SYLLABLE MGEX;Lo;0;L;;;;;N;;;;; +A23E;YI SYLLABLE MGE;Lo;0;L;;;;;N;;;;; +A23F;YI SYLLABLE MGEP;Lo;0;L;;;;;N;;;;; +A240;YI SYLLABLE MGUT;Lo;0;L;;;;;N;;;;; +A241;YI SYLLABLE MGUX;Lo;0;L;;;;;N;;;;; +A242;YI SYLLABLE MGU;Lo;0;L;;;;;N;;;;; +A243;YI SYLLABLE MGUP;Lo;0;L;;;;;N;;;;; +A244;YI SYLLABLE MGURX;Lo;0;L;;;;;N;;;;; +A245;YI SYLLABLE MGUR;Lo;0;L;;;;;N;;;;; +A246;YI SYLLABLE HXIT;Lo;0;L;;;;;N;;;;; +A247;YI SYLLABLE HXIX;Lo;0;L;;;;;N;;;;; +A248;YI SYLLABLE HXI;Lo;0;L;;;;;N;;;;; +A249;YI SYLLABLE HXIP;Lo;0;L;;;;;N;;;;; +A24A;YI SYLLABLE HXIET;Lo;0;L;;;;;N;;;;; +A24B;YI SYLLABLE HXIEX;Lo;0;L;;;;;N;;;;; +A24C;YI SYLLABLE HXIE;Lo;0;L;;;;;N;;;;; +A24D;YI SYLLABLE HXIEP;Lo;0;L;;;;;N;;;;; +A24E;YI SYLLABLE HXAT;Lo;0;L;;;;;N;;;;; +A24F;YI SYLLABLE HXAX;Lo;0;L;;;;;N;;;;; +A250;YI SYLLABLE HXA;Lo;0;L;;;;;N;;;;; +A251;YI SYLLABLE HXAP;Lo;0;L;;;;;N;;;;; +A252;YI SYLLABLE HXUOT;Lo;0;L;;;;;N;;;;; +A253;YI SYLLABLE HXUOX;Lo;0;L;;;;;N;;;;; +A254;YI SYLLABLE HXUO;Lo;0;L;;;;;N;;;;; +A255;YI SYLLABLE HXUOP;Lo;0;L;;;;;N;;;;; +A256;YI SYLLABLE HXOT;Lo;0;L;;;;;N;;;;; +A257;YI SYLLABLE HXOX;Lo;0;L;;;;;N;;;;; +A258;YI SYLLABLE HXO;Lo;0;L;;;;;N;;;;; +A259;YI SYLLABLE HXOP;Lo;0;L;;;;;N;;;;; +A25A;YI SYLLABLE HXEX;Lo;0;L;;;;;N;;;;; +A25B;YI SYLLABLE HXE;Lo;0;L;;;;;N;;;;; +A25C;YI SYLLABLE HXEP;Lo;0;L;;;;;N;;;;; +A25D;YI SYLLABLE NGIEX;Lo;0;L;;;;;N;;;;; +A25E;YI SYLLABLE NGIE;Lo;0;L;;;;;N;;;;; +A25F;YI SYLLABLE NGIEP;Lo;0;L;;;;;N;;;;; +A260;YI SYLLABLE NGAT;Lo;0;L;;;;;N;;;;; +A261;YI SYLLABLE NGAX;Lo;0;L;;;;;N;;;;; +A262;YI SYLLABLE NGA;Lo;0;L;;;;;N;;;;; +A263;YI SYLLABLE NGAP;Lo;0;L;;;;;N;;;;; +A264;YI SYLLABLE NGUOT;Lo;0;L;;;;;N;;;;; +A265;YI SYLLABLE NGUOX;Lo;0;L;;;;;N;;;;; +A266;YI SYLLABLE NGUO;Lo;0;L;;;;;N;;;;; +A267;YI SYLLABLE NGOT;Lo;0;L;;;;;N;;;;; +A268;YI SYLLABLE NGOX;Lo;0;L;;;;;N;;;;; +A269;YI SYLLABLE NGO;Lo;0;L;;;;;N;;;;; +A26A;YI SYLLABLE NGOP;Lo;0;L;;;;;N;;;;; +A26B;YI SYLLABLE NGEX;Lo;0;L;;;;;N;;;;; +A26C;YI SYLLABLE NGE;Lo;0;L;;;;;N;;;;; +A26D;YI SYLLABLE NGEP;Lo;0;L;;;;;N;;;;; +A26E;YI SYLLABLE HIT;Lo;0;L;;;;;N;;;;; +A26F;YI SYLLABLE HIEX;Lo;0;L;;;;;N;;;;; +A270;YI SYLLABLE HIE;Lo;0;L;;;;;N;;;;; +A271;YI SYLLABLE HAT;Lo;0;L;;;;;N;;;;; +A272;YI SYLLABLE HAX;Lo;0;L;;;;;N;;;;; +A273;YI SYLLABLE HA;Lo;0;L;;;;;N;;;;; +A274;YI SYLLABLE HAP;Lo;0;L;;;;;N;;;;; +A275;YI SYLLABLE HUOT;Lo;0;L;;;;;N;;;;; +A276;YI SYLLABLE HUOX;Lo;0;L;;;;;N;;;;; +A277;YI SYLLABLE HUO;Lo;0;L;;;;;N;;;;; +A278;YI SYLLABLE HUOP;Lo;0;L;;;;;N;;;;; +A279;YI SYLLABLE HOT;Lo;0;L;;;;;N;;;;; +A27A;YI SYLLABLE HOX;Lo;0;L;;;;;N;;;;; +A27B;YI SYLLABLE HO;Lo;0;L;;;;;N;;;;; +A27C;YI SYLLABLE HOP;Lo;0;L;;;;;N;;;;; +A27D;YI SYLLABLE HEX;Lo;0;L;;;;;N;;;;; +A27E;YI SYLLABLE HE;Lo;0;L;;;;;N;;;;; +A27F;YI SYLLABLE HEP;Lo;0;L;;;;;N;;;;; +A280;YI SYLLABLE WAT;Lo;0;L;;;;;N;;;;; +A281;YI SYLLABLE WAX;Lo;0;L;;;;;N;;;;; +A282;YI SYLLABLE WA;Lo;0;L;;;;;N;;;;; +A283;YI SYLLABLE WAP;Lo;0;L;;;;;N;;;;; +A284;YI SYLLABLE WUOX;Lo;0;L;;;;;N;;;;; +A285;YI SYLLABLE WUO;Lo;0;L;;;;;N;;;;; +A286;YI SYLLABLE WUOP;Lo;0;L;;;;;N;;;;; +A287;YI SYLLABLE WOX;Lo;0;L;;;;;N;;;;; +A288;YI SYLLABLE WO;Lo;0;L;;;;;N;;;;; +A289;YI SYLLABLE WOP;Lo;0;L;;;;;N;;;;; +A28A;YI SYLLABLE WEX;Lo;0;L;;;;;N;;;;; +A28B;YI SYLLABLE WE;Lo;0;L;;;;;N;;;;; +A28C;YI SYLLABLE WEP;Lo;0;L;;;;;N;;;;; +A28D;YI SYLLABLE ZIT;Lo;0;L;;;;;N;;;;; +A28E;YI SYLLABLE ZIX;Lo;0;L;;;;;N;;;;; +A28F;YI SYLLABLE ZI;Lo;0;L;;;;;N;;;;; +A290;YI SYLLABLE ZIP;Lo;0;L;;;;;N;;;;; +A291;YI SYLLABLE ZIEX;Lo;0;L;;;;;N;;;;; +A292;YI SYLLABLE ZIE;Lo;0;L;;;;;N;;;;; +A293;YI SYLLABLE ZIEP;Lo;0;L;;;;;N;;;;; +A294;YI SYLLABLE ZAT;Lo;0;L;;;;;N;;;;; +A295;YI SYLLABLE ZAX;Lo;0;L;;;;;N;;;;; +A296;YI SYLLABLE ZA;Lo;0;L;;;;;N;;;;; +A297;YI SYLLABLE ZAP;Lo;0;L;;;;;N;;;;; +A298;YI SYLLABLE ZUOX;Lo;0;L;;;;;N;;;;; +A299;YI SYLLABLE ZUO;Lo;0;L;;;;;N;;;;; +A29A;YI SYLLABLE ZUOP;Lo;0;L;;;;;N;;;;; +A29B;YI SYLLABLE ZOT;Lo;0;L;;;;;N;;;;; +A29C;YI SYLLABLE ZOX;Lo;0;L;;;;;N;;;;; +A29D;YI SYLLABLE ZO;Lo;0;L;;;;;N;;;;; +A29E;YI SYLLABLE ZOP;Lo;0;L;;;;;N;;;;; +A29F;YI SYLLABLE ZEX;Lo;0;L;;;;;N;;;;; +A2A0;YI SYLLABLE ZE;Lo;0;L;;;;;N;;;;; +A2A1;YI SYLLABLE ZEP;Lo;0;L;;;;;N;;;;; +A2A2;YI SYLLABLE ZUT;Lo;0;L;;;;;N;;;;; +A2A3;YI SYLLABLE ZUX;Lo;0;L;;;;;N;;;;; +A2A4;YI SYLLABLE ZU;Lo;0;L;;;;;N;;;;; +A2A5;YI SYLLABLE ZUP;Lo;0;L;;;;;N;;;;; +A2A6;YI SYLLABLE ZURX;Lo;0;L;;;;;N;;;;; +A2A7;YI SYLLABLE ZUR;Lo;0;L;;;;;N;;;;; +A2A8;YI SYLLABLE ZYT;Lo;0;L;;;;;N;;;;; +A2A9;YI SYLLABLE ZYX;Lo;0;L;;;;;N;;;;; +A2AA;YI SYLLABLE ZY;Lo;0;L;;;;;N;;;;; +A2AB;YI SYLLABLE ZYP;Lo;0;L;;;;;N;;;;; +A2AC;YI SYLLABLE ZYRX;Lo;0;L;;;;;N;;;;; +A2AD;YI SYLLABLE ZYR;Lo;0;L;;;;;N;;;;; +A2AE;YI SYLLABLE CIT;Lo;0;L;;;;;N;;;;; +A2AF;YI SYLLABLE CIX;Lo;0;L;;;;;N;;;;; +A2B0;YI SYLLABLE CI;Lo;0;L;;;;;N;;;;; +A2B1;YI SYLLABLE CIP;Lo;0;L;;;;;N;;;;; +A2B2;YI SYLLABLE CIET;Lo;0;L;;;;;N;;;;; +A2B3;YI SYLLABLE CIEX;Lo;0;L;;;;;N;;;;; +A2B4;YI SYLLABLE CIE;Lo;0;L;;;;;N;;;;; +A2B5;YI SYLLABLE CIEP;Lo;0;L;;;;;N;;;;; +A2B6;YI SYLLABLE CAT;Lo;0;L;;;;;N;;;;; +A2B7;YI SYLLABLE CAX;Lo;0;L;;;;;N;;;;; +A2B8;YI SYLLABLE CA;Lo;0;L;;;;;N;;;;; +A2B9;YI SYLLABLE CAP;Lo;0;L;;;;;N;;;;; +A2BA;YI SYLLABLE CUOX;Lo;0;L;;;;;N;;;;; +A2BB;YI SYLLABLE CUO;Lo;0;L;;;;;N;;;;; +A2BC;YI SYLLABLE CUOP;Lo;0;L;;;;;N;;;;; +A2BD;YI SYLLABLE COT;Lo;0;L;;;;;N;;;;; +A2BE;YI SYLLABLE COX;Lo;0;L;;;;;N;;;;; +A2BF;YI SYLLABLE CO;Lo;0;L;;;;;N;;;;; +A2C0;YI SYLLABLE COP;Lo;0;L;;;;;N;;;;; +A2C1;YI SYLLABLE CEX;Lo;0;L;;;;;N;;;;; +A2C2;YI SYLLABLE CE;Lo;0;L;;;;;N;;;;; +A2C3;YI SYLLABLE CEP;Lo;0;L;;;;;N;;;;; +A2C4;YI SYLLABLE CUT;Lo;0;L;;;;;N;;;;; +A2C5;YI SYLLABLE CUX;Lo;0;L;;;;;N;;;;; +A2C6;YI SYLLABLE CU;Lo;0;L;;;;;N;;;;; +A2C7;YI SYLLABLE CUP;Lo;0;L;;;;;N;;;;; +A2C8;YI SYLLABLE CURX;Lo;0;L;;;;;N;;;;; +A2C9;YI SYLLABLE CUR;Lo;0;L;;;;;N;;;;; +A2CA;YI SYLLABLE CYT;Lo;0;L;;;;;N;;;;; +A2CB;YI SYLLABLE CYX;Lo;0;L;;;;;N;;;;; +A2CC;YI SYLLABLE CY;Lo;0;L;;;;;N;;;;; +A2CD;YI SYLLABLE CYP;Lo;0;L;;;;;N;;;;; +A2CE;YI SYLLABLE CYRX;Lo;0;L;;;;;N;;;;; +A2CF;YI SYLLABLE CYR;Lo;0;L;;;;;N;;;;; +A2D0;YI SYLLABLE ZZIT;Lo;0;L;;;;;N;;;;; +A2D1;YI SYLLABLE ZZIX;Lo;0;L;;;;;N;;;;; +A2D2;YI SYLLABLE ZZI;Lo;0;L;;;;;N;;;;; +A2D3;YI SYLLABLE ZZIP;Lo;0;L;;;;;N;;;;; +A2D4;YI SYLLABLE ZZIET;Lo;0;L;;;;;N;;;;; +A2D5;YI SYLLABLE ZZIEX;Lo;0;L;;;;;N;;;;; +A2D6;YI SYLLABLE ZZIE;Lo;0;L;;;;;N;;;;; +A2D7;YI SYLLABLE ZZIEP;Lo;0;L;;;;;N;;;;; +A2D8;YI SYLLABLE ZZAT;Lo;0;L;;;;;N;;;;; +A2D9;YI SYLLABLE ZZAX;Lo;0;L;;;;;N;;;;; +A2DA;YI SYLLABLE ZZA;Lo;0;L;;;;;N;;;;; +A2DB;YI SYLLABLE ZZAP;Lo;0;L;;;;;N;;;;; +A2DC;YI SYLLABLE ZZOX;Lo;0;L;;;;;N;;;;; +A2DD;YI SYLLABLE ZZO;Lo;0;L;;;;;N;;;;; +A2DE;YI SYLLABLE ZZOP;Lo;0;L;;;;;N;;;;; +A2DF;YI SYLLABLE ZZEX;Lo;0;L;;;;;N;;;;; +A2E0;YI SYLLABLE ZZE;Lo;0;L;;;;;N;;;;; +A2E1;YI SYLLABLE ZZEP;Lo;0;L;;;;;N;;;;; +A2E2;YI SYLLABLE ZZUX;Lo;0;L;;;;;N;;;;; +A2E3;YI SYLLABLE ZZU;Lo;0;L;;;;;N;;;;; +A2E4;YI SYLLABLE ZZUP;Lo;0;L;;;;;N;;;;; +A2E5;YI SYLLABLE ZZURX;Lo;0;L;;;;;N;;;;; +A2E6;YI SYLLABLE ZZUR;Lo;0;L;;;;;N;;;;; +A2E7;YI SYLLABLE ZZYT;Lo;0;L;;;;;N;;;;; +A2E8;YI SYLLABLE ZZYX;Lo;0;L;;;;;N;;;;; +A2E9;YI SYLLABLE ZZY;Lo;0;L;;;;;N;;;;; +A2EA;YI SYLLABLE ZZYP;Lo;0;L;;;;;N;;;;; +A2EB;YI SYLLABLE ZZYRX;Lo;0;L;;;;;N;;;;; +A2EC;YI SYLLABLE ZZYR;Lo;0;L;;;;;N;;;;; +A2ED;YI SYLLABLE NZIT;Lo;0;L;;;;;N;;;;; +A2EE;YI SYLLABLE NZIX;Lo;0;L;;;;;N;;;;; +A2EF;YI SYLLABLE NZI;Lo;0;L;;;;;N;;;;; +A2F0;YI SYLLABLE NZIP;Lo;0;L;;;;;N;;;;; +A2F1;YI SYLLABLE NZIEX;Lo;0;L;;;;;N;;;;; +A2F2;YI SYLLABLE NZIE;Lo;0;L;;;;;N;;;;; +A2F3;YI SYLLABLE NZIEP;Lo;0;L;;;;;N;;;;; +A2F4;YI SYLLABLE NZAT;Lo;0;L;;;;;N;;;;; +A2F5;YI SYLLABLE NZAX;Lo;0;L;;;;;N;;;;; +A2F6;YI SYLLABLE NZA;Lo;0;L;;;;;N;;;;; +A2F7;YI SYLLABLE NZAP;Lo;0;L;;;;;N;;;;; +A2F8;YI SYLLABLE NZUOX;Lo;0;L;;;;;N;;;;; +A2F9;YI SYLLABLE NZUO;Lo;0;L;;;;;N;;;;; +A2FA;YI SYLLABLE NZOX;Lo;0;L;;;;;N;;;;; +A2FB;YI SYLLABLE NZOP;Lo;0;L;;;;;N;;;;; +A2FC;YI SYLLABLE NZEX;Lo;0;L;;;;;N;;;;; +A2FD;YI SYLLABLE NZE;Lo;0;L;;;;;N;;;;; +A2FE;YI SYLLABLE NZUX;Lo;0;L;;;;;N;;;;; +A2FF;YI SYLLABLE NZU;Lo;0;L;;;;;N;;;;; +A300;YI SYLLABLE NZUP;Lo;0;L;;;;;N;;;;; +A301;YI SYLLABLE NZURX;Lo;0;L;;;;;N;;;;; +A302;YI SYLLABLE NZUR;Lo;0;L;;;;;N;;;;; +A303;YI SYLLABLE NZYT;Lo;0;L;;;;;N;;;;; +A304;YI SYLLABLE NZYX;Lo;0;L;;;;;N;;;;; +A305;YI SYLLABLE NZY;Lo;0;L;;;;;N;;;;; +A306;YI SYLLABLE NZYP;Lo;0;L;;;;;N;;;;; +A307;YI SYLLABLE NZYRX;Lo;0;L;;;;;N;;;;; +A308;YI SYLLABLE NZYR;Lo;0;L;;;;;N;;;;; +A309;YI SYLLABLE SIT;Lo;0;L;;;;;N;;;;; +A30A;YI SYLLABLE SIX;Lo;0;L;;;;;N;;;;; +A30B;YI SYLLABLE SI;Lo;0;L;;;;;N;;;;; +A30C;YI SYLLABLE SIP;Lo;0;L;;;;;N;;;;; +A30D;YI SYLLABLE SIEX;Lo;0;L;;;;;N;;;;; +A30E;YI SYLLABLE SIE;Lo;0;L;;;;;N;;;;; +A30F;YI SYLLABLE SIEP;Lo;0;L;;;;;N;;;;; +A310;YI SYLLABLE SAT;Lo;0;L;;;;;N;;;;; +A311;YI SYLLABLE SAX;Lo;0;L;;;;;N;;;;; +A312;YI SYLLABLE SA;Lo;0;L;;;;;N;;;;; +A313;YI SYLLABLE SAP;Lo;0;L;;;;;N;;;;; +A314;YI SYLLABLE SUOX;Lo;0;L;;;;;N;;;;; +A315;YI SYLLABLE SUO;Lo;0;L;;;;;N;;;;; +A316;YI SYLLABLE SUOP;Lo;0;L;;;;;N;;;;; +A317;YI SYLLABLE SOT;Lo;0;L;;;;;N;;;;; +A318;YI SYLLABLE SOX;Lo;0;L;;;;;N;;;;; +A319;YI SYLLABLE SO;Lo;0;L;;;;;N;;;;; +A31A;YI SYLLABLE SOP;Lo;0;L;;;;;N;;;;; +A31B;YI SYLLABLE SEX;Lo;0;L;;;;;N;;;;; +A31C;YI SYLLABLE SE;Lo;0;L;;;;;N;;;;; +A31D;YI SYLLABLE SEP;Lo;0;L;;;;;N;;;;; +A31E;YI SYLLABLE SUT;Lo;0;L;;;;;N;;;;; +A31F;YI SYLLABLE SUX;Lo;0;L;;;;;N;;;;; +A320;YI SYLLABLE SU;Lo;0;L;;;;;N;;;;; +A321;YI SYLLABLE SUP;Lo;0;L;;;;;N;;;;; +A322;YI SYLLABLE SURX;Lo;0;L;;;;;N;;;;; +A323;YI SYLLABLE SUR;Lo;0;L;;;;;N;;;;; +A324;YI SYLLABLE SYT;Lo;0;L;;;;;N;;;;; +A325;YI SYLLABLE SYX;Lo;0;L;;;;;N;;;;; +A326;YI SYLLABLE SY;Lo;0;L;;;;;N;;;;; +A327;YI SYLLABLE SYP;Lo;0;L;;;;;N;;;;; +A328;YI SYLLABLE SYRX;Lo;0;L;;;;;N;;;;; +A329;YI SYLLABLE SYR;Lo;0;L;;;;;N;;;;; +A32A;YI SYLLABLE SSIT;Lo;0;L;;;;;N;;;;; +A32B;YI SYLLABLE SSIX;Lo;0;L;;;;;N;;;;; +A32C;YI SYLLABLE SSI;Lo;0;L;;;;;N;;;;; +A32D;YI SYLLABLE SSIP;Lo;0;L;;;;;N;;;;; +A32E;YI SYLLABLE SSIEX;Lo;0;L;;;;;N;;;;; +A32F;YI SYLLABLE SSIE;Lo;0;L;;;;;N;;;;; +A330;YI SYLLABLE SSIEP;Lo;0;L;;;;;N;;;;; +A331;YI SYLLABLE SSAT;Lo;0;L;;;;;N;;;;; +A332;YI SYLLABLE SSAX;Lo;0;L;;;;;N;;;;; +A333;YI SYLLABLE SSA;Lo;0;L;;;;;N;;;;; +A334;YI SYLLABLE SSAP;Lo;0;L;;;;;N;;;;; +A335;YI SYLLABLE SSOT;Lo;0;L;;;;;N;;;;; +A336;YI SYLLABLE SSOX;Lo;0;L;;;;;N;;;;; +A337;YI SYLLABLE SSO;Lo;0;L;;;;;N;;;;; +A338;YI SYLLABLE SSOP;Lo;0;L;;;;;N;;;;; +A339;YI SYLLABLE SSEX;Lo;0;L;;;;;N;;;;; +A33A;YI SYLLABLE SSE;Lo;0;L;;;;;N;;;;; +A33B;YI SYLLABLE SSEP;Lo;0;L;;;;;N;;;;; +A33C;YI SYLLABLE SSUT;Lo;0;L;;;;;N;;;;; +A33D;YI SYLLABLE SSUX;Lo;0;L;;;;;N;;;;; +A33E;YI SYLLABLE SSU;Lo;0;L;;;;;N;;;;; +A33F;YI SYLLABLE SSUP;Lo;0;L;;;;;N;;;;; +A340;YI SYLLABLE SSYT;Lo;0;L;;;;;N;;;;; +A341;YI SYLLABLE SSYX;Lo;0;L;;;;;N;;;;; +A342;YI SYLLABLE SSY;Lo;0;L;;;;;N;;;;; +A343;YI SYLLABLE SSYP;Lo;0;L;;;;;N;;;;; +A344;YI SYLLABLE SSYRX;Lo;0;L;;;;;N;;;;; +A345;YI SYLLABLE SSYR;Lo;0;L;;;;;N;;;;; +A346;YI SYLLABLE ZHAT;Lo;0;L;;;;;N;;;;; +A347;YI SYLLABLE ZHAX;Lo;0;L;;;;;N;;;;; +A348;YI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; +A349;YI SYLLABLE ZHAP;Lo;0;L;;;;;N;;;;; +A34A;YI SYLLABLE ZHUOX;Lo;0;L;;;;;N;;;;; +A34B;YI SYLLABLE ZHUO;Lo;0;L;;;;;N;;;;; +A34C;YI SYLLABLE ZHUOP;Lo;0;L;;;;;N;;;;; +A34D;YI SYLLABLE ZHOT;Lo;0;L;;;;;N;;;;; +A34E;YI SYLLABLE ZHOX;Lo;0;L;;;;;N;;;;; +A34F;YI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; +A350;YI SYLLABLE ZHOP;Lo;0;L;;;;;N;;;;; +A351;YI SYLLABLE ZHET;Lo;0;L;;;;;N;;;;; +A352;YI SYLLABLE ZHEX;Lo;0;L;;;;;N;;;;; +A353;YI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; +A354;YI SYLLABLE ZHEP;Lo;0;L;;;;;N;;;;; +A355;YI SYLLABLE ZHUT;Lo;0;L;;;;;N;;;;; +A356;YI SYLLABLE ZHUX;Lo;0;L;;;;;N;;;;; +A357;YI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; +A358;YI SYLLABLE ZHUP;Lo;0;L;;;;;N;;;;; +A359;YI SYLLABLE ZHURX;Lo;0;L;;;;;N;;;;; +A35A;YI SYLLABLE ZHUR;Lo;0;L;;;;;N;;;;; +A35B;YI SYLLABLE ZHYT;Lo;0;L;;;;;N;;;;; +A35C;YI SYLLABLE ZHYX;Lo;0;L;;;;;N;;;;; +A35D;YI SYLLABLE ZHY;Lo;0;L;;;;;N;;;;; +A35E;YI SYLLABLE ZHYP;Lo;0;L;;;;;N;;;;; +A35F;YI SYLLABLE ZHYRX;Lo;0;L;;;;;N;;;;; +A360;YI SYLLABLE ZHYR;Lo;0;L;;;;;N;;;;; +A361;YI SYLLABLE CHAT;Lo;0;L;;;;;N;;;;; +A362;YI SYLLABLE CHAX;Lo;0;L;;;;;N;;;;; +A363;YI SYLLABLE CHA;Lo;0;L;;;;;N;;;;; +A364;YI SYLLABLE CHAP;Lo;0;L;;;;;N;;;;; +A365;YI SYLLABLE CHUOT;Lo;0;L;;;;;N;;;;; +A366;YI SYLLABLE CHUOX;Lo;0;L;;;;;N;;;;; +A367;YI SYLLABLE CHUO;Lo;0;L;;;;;N;;;;; +A368;YI SYLLABLE CHUOP;Lo;0;L;;;;;N;;;;; +A369;YI SYLLABLE CHOT;Lo;0;L;;;;;N;;;;; +A36A;YI SYLLABLE CHOX;Lo;0;L;;;;;N;;;;; +A36B;YI SYLLABLE CHO;Lo;0;L;;;;;N;;;;; +A36C;YI SYLLABLE CHOP;Lo;0;L;;;;;N;;;;; +A36D;YI SYLLABLE CHET;Lo;0;L;;;;;N;;;;; +A36E;YI SYLLABLE CHEX;Lo;0;L;;;;;N;;;;; +A36F;YI SYLLABLE CHE;Lo;0;L;;;;;N;;;;; +A370;YI SYLLABLE CHEP;Lo;0;L;;;;;N;;;;; +A371;YI SYLLABLE CHUX;Lo;0;L;;;;;N;;;;; +A372;YI SYLLABLE CHU;Lo;0;L;;;;;N;;;;; +A373;YI SYLLABLE CHUP;Lo;0;L;;;;;N;;;;; +A374;YI SYLLABLE CHURX;Lo;0;L;;;;;N;;;;; +A375;YI SYLLABLE CHUR;Lo;0;L;;;;;N;;;;; +A376;YI SYLLABLE CHYT;Lo;0;L;;;;;N;;;;; +A377;YI SYLLABLE CHYX;Lo;0;L;;;;;N;;;;; +A378;YI SYLLABLE CHY;Lo;0;L;;;;;N;;;;; +A379;YI SYLLABLE CHYP;Lo;0;L;;;;;N;;;;; +A37A;YI SYLLABLE CHYRX;Lo;0;L;;;;;N;;;;; +A37B;YI SYLLABLE CHYR;Lo;0;L;;;;;N;;;;; +A37C;YI SYLLABLE RRAX;Lo;0;L;;;;;N;;;;; +A37D;YI SYLLABLE RRA;Lo;0;L;;;;;N;;;;; +A37E;YI SYLLABLE RRUOX;Lo;0;L;;;;;N;;;;; +A37F;YI SYLLABLE RRUO;Lo;0;L;;;;;N;;;;; +A380;YI SYLLABLE RROT;Lo;0;L;;;;;N;;;;; +A381;YI SYLLABLE RROX;Lo;0;L;;;;;N;;;;; +A382;YI SYLLABLE RRO;Lo;0;L;;;;;N;;;;; +A383;YI SYLLABLE RROP;Lo;0;L;;;;;N;;;;; +A384;YI SYLLABLE RRET;Lo;0;L;;;;;N;;;;; +A385;YI SYLLABLE RREX;Lo;0;L;;;;;N;;;;; +A386;YI SYLLABLE RRE;Lo;0;L;;;;;N;;;;; +A387;YI SYLLABLE RREP;Lo;0;L;;;;;N;;;;; +A388;YI SYLLABLE RRUT;Lo;0;L;;;;;N;;;;; +A389;YI SYLLABLE RRUX;Lo;0;L;;;;;N;;;;; +A38A;YI SYLLABLE RRU;Lo;0;L;;;;;N;;;;; +A38B;YI SYLLABLE RRUP;Lo;0;L;;;;;N;;;;; +A38C;YI SYLLABLE RRURX;Lo;0;L;;;;;N;;;;; +A38D;YI SYLLABLE RRUR;Lo;0;L;;;;;N;;;;; +A38E;YI SYLLABLE RRYT;Lo;0;L;;;;;N;;;;; +A38F;YI SYLLABLE RRYX;Lo;0;L;;;;;N;;;;; +A390;YI SYLLABLE RRY;Lo;0;L;;;;;N;;;;; +A391;YI SYLLABLE RRYP;Lo;0;L;;;;;N;;;;; +A392;YI SYLLABLE RRYRX;Lo;0;L;;;;;N;;;;; +A393;YI SYLLABLE RRYR;Lo;0;L;;;;;N;;;;; +A394;YI SYLLABLE NRAT;Lo;0;L;;;;;N;;;;; +A395;YI SYLLABLE NRAX;Lo;0;L;;;;;N;;;;; +A396;YI SYLLABLE NRA;Lo;0;L;;;;;N;;;;; +A397;YI SYLLABLE NRAP;Lo;0;L;;;;;N;;;;; +A398;YI SYLLABLE NROX;Lo;0;L;;;;;N;;;;; +A399;YI SYLLABLE NRO;Lo;0;L;;;;;N;;;;; +A39A;YI SYLLABLE NROP;Lo;0;L;;;;;N;;;;; +A39B;YI SYLLABLE NRET;Lo;0;L;;;;;N;;;;; +A39C;YI SYLLABLE NREX;Lo;0;L;;;;;N;;;;; +A39D;YI SYLLABLE NRE;Lo;0;L;;;;;N;;;;; +A39E;YI SYLLABLE NREP;Lo;0;L;;;;;N;;;;; +A39F;YI SYLLABLE NRUT;Lo;0;L;;;;;N;;;;; +A3A0;YI SYLLABLE NRUX;Lo;0;L;;;;;N;;;;; +A3A1;YI SYLLABLE NRU;Lo;0;L;;;;;N;;;;; +A3A2;YI SYLLABLE NRUP;Lo;0;L;;;;;N;;;;; +A3A3;YI SYLLABLE NRURX;Lo;0;L;;;;;N;;;;; +A3A4;YI SYLLABLE NRUR;Lo;0;L;;;;;N;;;;; +A3A5;YI SYLLABLE NRYT;Lo;0;L;;;;;N;;;;; +A3A6;YI SYLLABLE NRYX;Lo;0;L;;;;;N;;;;; +A3A7;YI SYLLABLE NRY;Lo;0;L;;;;;N;;;;; +A3A8;YI SYLLABLE NRYP;Lo;0;L;;;;;N;;;;; +A3A9;YI SYLLABLE NRYRX;Lo;0;L;;;;;N;;;;; +A3AA;YI SYLLABLE NRYR;Lo;0;L;;;;;N;;;;; +A3AB;YI SYLLABLE SHAT;Lo;0;L;;;;;N;;;;; +A3AC;YI SYLLABLE SHAX;Lo;0;L;;;;;N;;;;; +A3AD;YI SYLLABLE SHA;Lo;0;L;;;;;N;;;;; +A3AE;YI SYLLABLE SHAP;Lo;0;L;;;;;N;;;;; +A3AF;YI SYLLABLE SHUOX;Lo;0;L;;;;;N;;;;; +A3B0;YI SYLLABLE SHUO;Lo;0;L;;;;;N;;;;; +A3B1;YI SYLLABLE SHUOP;Lo;0;L;;;;;N;;;;; +A3B2;YI SYLLABLE SHOT;Lo;0;L;;;;;N;;;;; +A3B3;YI SYLLABLE SHOX;Lo;0;L;;;;;N;;;;; +A3B4;YI SYLLABLE SHO;Lo;0;L;;;;;N;;;;; +A3B5;YI SYLLABLE SHOP;Lo;0;L;;;;;N;;;;; +A3B6;YI SYLLABLE SHET;Lo;0;L;;;;;N;;;;; +A3B7;YI SYLLABLE SHEX;Lo;0;L;;;;;N;;;;; +A3B8;YI SYLLABLE SHE;Lo;0;L;;;;;N;;;;; +A3B9;YI SYLLABLE SHEP;Lo;0;L;;;;;N;;;;; +A3BA;YI SYLLABLE SHUT;Lo;0;L;;;;;N;;;;; +A3BB;YI SYLLABLE SHUX;Lo;0;L;;;;;N;;;;; +A3BC;YI SYLLABLE SHU;Lo;0;L;;;;;N;;;;; +A3BD;YI SYLLABLE SHUP;Lo;0;L;;;;;N;;;;; +A3BE;YI SYLLABLE SHURX;Lo;0;L;;;;;N;;;;; +A3BF;YI SYLLABLE SHUR;Lo;0;L;;;;;N;;;;; +A3C0;YI SYLLABLE SHYT;Lo;0;L;;;;;N;;;;; +A3C1;YI SYLLABLE SHYX;Lo;0;L;;;;;N;;;;; +A3C2;YI SYLLABLE SHY;Lo;0;L;;;;;N;;;;; +A3C3;YI SYLLABLE SHYP;Lo;0;L;;;;;N;;;;; +A3C4;YI SYLLABLE SHYRX;Lo;0;L;;;;;N;;;;; +A3C5;YI SYLLABLE SHYR;Lo;0;L;;;;;N;;;;; +A3C6;YI SYLLABLE RAT;Lo;0;L;;;;;N;;;;; +A3C7;YI SYLLABLE RAX;Lo;0;L;;;;;N;;;;; +A3C8;YI SYLLABLE RA;Lo;0;L;;;;;N;;;;; +A3C9;YI SYLLABLE RAP;Lo;0;L;;;;;N;;;;; +A3CA;YI SYLLABLE RUOX;Lo;0;L;;;;;N;;;;; +A3CB;YI SYLLABLE RUO;Lo;0;L;;;;;N;;;;; +A3CC;YI SYLLABLE RUOP;Lo;0;L;;;;;N;;;;; +A3CD;YI SYLLABLE ROT;Lo;0;L;;;;;N;;;;; +A3CE;YI SYLLABLE ROX;Lo;0;L;;;;;N;;;;; +A3CF;YI SYLLABLE RO;Lo;0;L;;;;;N;;;;; +A3D0;YI SYLLABLE ROP;Lo;0;L;;;;;N;;;;; +A3D1;YI SYLLABLE REX;Lo;0;L;;;;;N;;;;; +A3D2;YI SYLLABLE RE;Lo;0;L;;;;;N;;;;; +A3D3;YI SYLLABLE REP;Lo;0;L;;;;;N;;;;; +A3D4;YI SYLLABLE RUT;Lo;0;L;;;;;N;;;;; +A3D5;YI SYLLABLE RUX;Lo;0;L;;;;;N;;;;; +A3D6;YI SYLLABLE RU;Lo;0;L;;;;;N;;;;; +A3D7;YI SYLLABLE RUP;Lo;0;L;;;;;N;;;;; +A3D8;YI SYLLABLE RURX;Lo;0;L;;;;;N;;;;; +A3D9;YI SYLLABLE RUR;Lo;0;L;;;;;N;;;;; +A3DA;YI SYLLABLE RYT;Lo;0;L;;;;;N;;;;; +A3DB;YI SYLLABLE RYX;Lo;0;L;;;;;N;;;;; +A3DC;YI SYLLABLE RY;Lo;0;L;;;;;N;;;;; +A3DD;YI SYLLABLE RYP;Lo;0;L;;;;;N;;;;; +A3DE;YI SYLLABLE RYRX;Lo;0;L;;;;;N;;;;; +A3DF;YI SYLLABLE RYR;Lo;0;L;;;;;N;;;;; +A3E0;YI SYLLABLE JIT;Lo;0;L;;;;;N;;;;; +A3E1;YI SYLLABLE JIX;Lo;0;L;;;;;N;;;;; +A3E2;YI SYLLABLE JI;Lo;0;L;;;;;N;;;;; +A3E3;YI SYLLABLE JIP;Lo;0;L;;;;;N;;;;; +A3E4;YI SYLLABLE JIET;Lo;0;L;;;;;N;;;;; +A3E5;YI SYLLABLE JIEX;Lo;0;L;;;;;N;;;;; +A3E6;YI SYLLABLE JIE;Lo;0;L;;;;;N;;;;; +A3E7;YI SYLLABLE JIEP;Lo;0;L;;;;;N;;;;; +A3E8;YI SYLLABLE JUOT;Lo;0;L;;;;;N;;;;; +A3E9;YI SYLLABLE JUOX;Lo;0;L;;;;;N;;;;; +A3EA;YI SYLLABLE JUO;Lo;0;L;;;;;N;;;;; +A3EB;YI SYLLABLE JUOP;Lo;0;L;;;;;N;;;;; +A3EC;YI SYLLABLE JOT;Lo;0;L;;;;;N;;;;; +A3ED;YI SYLLABLE JOX;Lo;0;L;;;;;N;;;;; +A3EE;YI SYLLABLE JO;Lo;0;L;;;;;N;;;;; +A3EF;YI SYLLABLE JOP;Lo;0;L;;;;;N;;;;; +A3F0;YI SYLLABLE JUT;Lo;0;L;;;;;N;;;;; +A3F1;YI SYLLABLE JUX;Lo;0;L;;;;;N;;;;; +A3F2;YI SYLLABLE JU;Lo;0;L;;;;;N;;;;; +A3F3;YI SYLLABLE JUP;Lo;0;L;;;;;N;;;;; +A3F4;YI SYLLABLE JURX;Lo;0;L;;;;;N;;;;; +A3F5;YI SYLLABLE JUR;Lo;0;L;;;;;N;;;;; +A3F6;YI SYLLABLE JYT;Lo;0;L;;;;;N;;;;; +A3F7;YI SYLLABLE JYX;Lo;0;L;;;;;N;;;;; +A3F8;YI SYLLABLE JY;Lo;0;L;;;;;N;;;;; +A3F9;YI SYLLABLE JYP;Lo;0;L;;;;;N;;;;; +A3FA;YI SYLLABLE JYRX;Lo;0;L;;;;;N;;;;; +A3FB;YI SYLLABLE JYR;Lo;0;L;;;;;N;;;;; +A3FC;YI SYLLABLE QIT;Lo;0;L;;;;;N;;;;; +A3FD;YI SYLLABLE QIX;Lo;0;L;;;;;N;;;;; +A3FE;YI SYLLABLE QI;Lo;0;L;;;;;N;;;;; +A3FF;YI SYLLABLE QIP;Lo;0;L;;;;;N;;;;; +A400;YI SYLLABLE QIET;Lo;0;L;;;;;N;;;;; +A401;YI SYLLABLE QIEX;Lo;0;L;;;;;N;;;;; +A402;YI SYLLABLE QIE;Lo;0;L;;;;;N;;;;; +A403;YI SYLLABLE QIEP;Lo;0;L;;;;;N;;;;; +A404;YI SYLLABLE QUOT;Lo;0;L;;;;;N;;;;; +A405;YI SYLLABLE QUOX;Lo;0;L;;;;;N;;;;; +A406;YI SYLLABLE QUO;Lo;0;L;;;;;N;;;;; +A407;YI SYLLABLE QUOP;Lo;0;L;;;;;N;;;;; +A408;YI SYLLABLE QOT;Lo;0;L;;;;;N;;;;; +A409;YI SYLLABLE QOX;Lo;0;L;;;;;N;;;;; +A40A;YI SYLLABLE QO;Lo;0;L;;;;;N;;;;; +A40B;YI SYLLABLE QOP;Lo;0;L;;;;;N;;;;; +A40C;YI SYLLABLE QUT;Lo;0;L;;;;;N;;;;; +A40D;YI SYLLABLE QUX;Lo;0;L;;;;;N;;;;; +A40E;YI SYLLABLE QU;Lo;0;L;;;;;N;;;;; +A40F;YI SYLLABLE QUP;Lo;0;L;;;;;N;;;;; +A410;YI SYLLABLE QURX;Lo;0;L;;;;;N;;;;; +A411;YI SYLLABLE QUR;Lo;0;L;;;;;N;;;;; +A412;YI SYLLABLE QYT;Lo;0;L;;;;;N;;;;; +A413;YI SYLLABLE QYX;Lo;0;L;;;;;N;;;;; +A414;YI SYLLABLE QY;Lo;0;L;;;;;N;;;;; +A415;YI SYLLABLE QYP;Lo;0;L;;;;;N;;;;; +A416;YI SYLLABLE QYRX;Lo;0;L;;;;;N;;;;; +A417;YI SYLLABLE QYR;Lo;0;L;;;;;N;;;;; +A418;YI SYLLABLE JJIT;Lo;0;L;;;;;N;;;;; +A419;YI SYLLABLE JJIX;Lo;0;L;;;;;N;;;;; +A41A;YI SYLLABLE JJI;Lo;0;L;;;;;N;;;;; +A41B;YI SYLLABLE JJIP;Lo;0;L;;;;;N;;;;; +A41C;YI SYLLABLE JJIET;Lo;0;L;;;;;N;;;;; +A41D;YI SYLLABLE JJIEX;Lo;0;L;;;;;N;;;;; +A41E;YI SYLLABLE JJIE;Lo;0;L;;;;;N;;;;; +A41F;YI SYLLABLE JJIEP;Lo;0;L;;;;;N;;;;; +A420;YI SYLLABLE JJUOX;Lo;0;L;;;;;N;;;;; +A421;YI SYLLABLE JJUO;Lo;0;L;;;;;N;;;;; +A422;YI SYLLABLE JJUOP;Lo;0;L;;;;;N;;;;; +A423;YI SYLLABLE JJOT;Lo;0;L;;;;;N;;;;; +A424;YI SYLLABLE JJOX;Lo;0;L;;;;;N;;;;; +A425;YI SYLLABLE JJO;Lo;0;L;;;;;N;;;;; +A426;YI SYLLABLE JJOP;Lo;0;L;;;;;N;;;;; +A427;YI SYLLABLE JJUT;Lo;0;L;;;;;N;;;;; +A428;YI SYLLABLE JJUX;Lo;0;L;;;;;N;;;;; +A429;YI SYLLABLE JJU;Lo;0;L;;;;;N;;;;; +A42A;YI SYLLABLE JJUP;Lo;0;L;;;;;N;;;;; +A42B;YI SYLLABLE JJURX;Lo;0;L;;;;;N;;;;; +A42C;YI SYLLABLE JJUR;Lo;0;L;;;;;N;;;;; +A42D;YI SYLLABLE JJYT;Lo;0;L;;;;;N;;;;; +A42E;YI SYLLABLE JJYX;Lo;0;L;;;;;N;;;;; +A42F;YI SYLLABLE JJY;Lo;0;L;;;;;N;;;;; +A430;YI SYLLABLE JJYP;Lo;0;L;;;;;N;;;;; +A431;YI SYLLABLE NJIT;Lo;0;L;;;;;N;;;;; +A432;YI SYLLABLE NJIX;Lo;0;L;;;;;N;;;;; +A433;YI SYLLABLE NJI;Lo;0;L;;;;;N;;;;; +A434;YI SYLLABLE NJIP;Lo;0;L;;;;;N;;;;; +A435;YI SYLLABLE NJIET;Lo;0;L;;;;;N;;;;; +A436;YI SYLLABLE NJIEX;Lo;0;L;;;;;N;;;;; +A437;YI SYLLABLE NJIE;Lo;0;L;;;;;N;;;;; +A438;YI SYLLABLE NJIEP;Lo;0;L;;;;;N;;;;; +A439;YI SYLLABLE NJUOX;Lo;0;L;;;;;N;;;;; +A43A;YI SYLLABLE NJUO;Lo;0;L;;;;;N;;;;; +A43B;YI SYLLABLE NJOT;Lo;0;L;;;;;N;;;;; +A43C;YI SYLLABLE NJOX;Lo;0;L;;;;;N;;;;; +A43D;YI SYLLABLE NJO;Lo;0;L;;;;;N;;;;; +A43E;YI SYLLABLE NJOP;Lo;0;L;;;;;N;;;;; +A43F;YI SYLLABLE NJUX;Lo;0;L;;;;;N;;;;; +A440;YI SYLLABLE NJU;Lo;0;L;;;;;N;;;;; +A441;YI SYLLABLE NJUP;Lo;0;L;;;;;N;;;;; +A442;YI SYLLABLE NJURX;Lo;0;L;;;;;N;;;;; +A443;YI SYLLABLE NJUR;Lo;0;L;;;;;N;;;;; +A444;YI SYLLABLE NJYT;Lo;0;L;;;;;N;;;;; +A445;YI SYLLABLE NJYX;Lo;0;L;;;;;N;;;;; +A446;YI SYLLABLE NJY;Lo;0;L;;;;;N;;;;; +A447;YI SYLLABLE NJYP;Lo;0;L;;;;;N;;;;; +A448;YI SYLLABLE NJYRX;Lo;0;L;;;;;N;;;;; +A449;YI SYLLABLE NJYR;Lo;0;L;;;;;N;;;;; +A44A;YI SYLLABLE NYIT;Lo;0;L;;;;;N;;;;; +A44B;YI SYLLABLE NYIX;Lo;0;L;;;;;N;;;;; +A44C;YI SYLLABLE NYI;Lo;0;L;;;;;N;;;;; +A44D;YI SYLLABLE NYIP;Lo;0;L;;;;;N;;;;; +A44E;YI SYLLABLE NYIET;Lo;0;L;;;;;N;;;;; +A44F;YI SYLLABLE NYIEX;Lo;0;L;;;;;N;;;;; +A450;YI SYLLABLE NYIE;Lo;0;L;;;;;N;;;;; +A451;YI SYLLABLE NYIEP;Lo;0;L;;;;;N;;;;; +A452;YI SYLLABLE NYUOX;Lo;0;L;;;;;N;;;;; +A453;YI SYLLABLE NYUO;Lo;0;L;;;;;N;;;;; +A454;YI SYLLABLE NYUOP;Lo;0;L;;;;;N;;;;; +A455;YI SYLLABLE NYOT;Lo;0;L;;;;;N;;;;; +A456;YI SYLLABLE NYOX;Lo;0;L;;;;;N;;;;; +A457;YI SYLLABLE NYO;Lo;0;L;;;;;N;;;;; +A458;YI SYLLABLE NYOP;Lo;0;L;;;;;N;;;;; +A459;YI SYLLABLE NYUT;Lo;0;L;;;;;N;;;;; +A45A;YI SYLLABLE NYUX;Lo;0;L;;;;;N;;;;; +A45B;YI SYLLABLE NYU;Lo;0;L;;;;;N;;;;; +A45C;YI SYLLABLE NYUP;Lo;0;L;;;;;N;;;;; +A45D;YI SYLLABLE XIT;Lo;0;L;;;;;N;;;;; +A45E;YI SYLLABLE XIX;Lo;0;L;;;;;N;;;;; +A45F;YI SYLLABLE XI;Lo;0;L;;;;;N;;;;; +A460;YI SYLLABLE XIP;Lo;0;L;;;;;N;;;;; +A461;YI SYLLABLE XIET;Lo;0;L;;;;;N;;;;; +A462;YI SYLLABLE XIEX;Lo;0;L;;;;;N;;;;; +A463;YI SYLLABLE XIE;Lo;0;L;;;;;N;;;;; +A464;YI SYLLABLE XIEP;Lo;0;L;;;;;N;;;;; +A465;YI SYLLABLE XUOX;Lo;0;L;;;;;N;;;;; +A466;YI SYLLABLE XUO;Lo;0;L;;;;;N;;;;; +A467;YI SYLLABLE XOT;Lo;0;L;;;;;N;;;;; +A468;YI SYLLABLE XOX;Lo;0;L;;;;;N;;;;; +A469;YI SYLLABLE XO;Lo;0;L;;;;;N;;;;; +A46A;YI SYLLABLE XOP;Lo;0;L;;;;;N;;;;; +A46B;YI SYLLABLE XYT;Lo;0;L;;;;;N;;;;; +A46C;YI SYLLABLE XYX;Lo;0;L;;;;;N;;;;; +A46D;YI SYLLABLE XY;Lo;0;L;;;;;N;;;;; +A46E;YI SYLLABLE XYP;Lo;0;L;;;;;N;;;;; +A46F;YI SYLLABLE XYRX;Lo;0;L;;;;;N;;;;; +A470;YI SYLLABLE XYR;Lo;0;L;;;;;N;;;;; +A471;YI SYLLABLE YIT;Lo;0;L;;;;;N;;;;; +A472;YI SYLLABLE YIX;Lo;0;L;;;;;N;;;;; +A473;YI SYLLABLE YI;Lo;0;L;;;;;N;;;;; +A474;YI SYLLABLE YIP;Lo;0;L;;;;;N;;;;; +A475;YI SYLLABLE YIET;Lo;0;L;;;;;N;;;;; +A476;YI SYLLABLE YIEX;Lo;0;L;;;;;N;;;;; +A477;YI SYLLABLE YIE;Lo;0;L;;;;;N;;;;; +A478;YI SYLLABLE YIEP;Lo;0;L;;;;;N;;;;; +A479;YI SYLLABLE YUOT;Lo;0;L;;;;;N;;;;; +A47A;YI SYLLABLE YUOX;Lo;0;L;;;;;N;;;;; +A47B;YI SYLLABLE YUO;Lo;0;L;;;;;N;;;;; +A47C;YI SYLLABLE YUOP;Lo;0;L;;;;;N;;;;; +A47D;YI SYLLABLE YOT;Lo;0;L;;;;;N;;;;; +A47E;YI SYLLABLE YOX;Lo;0;L;;;;;N;;;;; +A47F;YI SYLLABLE YO;Lo;0;L;;;;;N;;;;; +A480;YI SYLLABLE YOP;Lo;0;L;;;;;N;;;;; +A481;YI SYLLABLE YUT;Lo;0;L;;;;;N;;;;; +A482;YI SYLLABLE YUX;Lo;0;L;;;;;N;;;;; +A483;YI SYLLABLE YU;Lo;0;L;;;;;N;;;;; +A484;YI SYLLABLE YUP;Lo;0;L;;;;;N;;;;; +A485;YI SYLLABLE YURX;Lo;0;L;;;;;N;;;;; +A486;YI SYLLABLE YUR;Lo;0;L;;;;;N;;;;; +A487;YI SYLLABLE YYT;Lo;0;L;;;;;N;;;;; +A488;YI SYLLABLE YYX;Lo;0;L;;;;;N;;;;; +A489;YI SYLLABLE YY;Lo;0;L;;;;;N;;;;; +A48A;YI SYLLABLE YYP;Lo;0;L;;;;;N;;;;; +A48B;YI SYLLABLE YYRX;Lo;0;L;;;;;N;;;;; +A48C;YI SYLLABLE YYR;Lo;0;L;;;;;N;;;;; +A490;YI RADICAL QOT;So;0;ON;;;;;N;;;;; +A491;YI RADICAL LI;So;0;ON;;;;;N;;;;; +A492;YI RADICAL KIT;So;0;ON;;;;;N;;;;; +A493;YI RADICAL NYIP;So;0;ON;;;;;N;;;;; +A494;YI RADICAL CYP;So;0;ON;;;;;N;;;;; +A495;YI RADICAL SSI;So;0;ON;;;;;N;;;;; +A496;YI RADICAL GGOP;So;0;ON;;;;;N;;;;; +A497;YI RADICAL GEP;So;0;ON;;;;;N;;;;; +A498;YI RADICAL MI;So;0;ON;;;;;N;;;;; +A499;YI RADICAL HXIT;So;0;ON;;;;;N;;;;; +A49A;YI RADICAL LYR;So;0;ON;;;;;N;;;;; +A49B;YI RADICAL BBUT;So;0;ON;;;;;N;;;;; +A49C;YI RADICAL MOP;So;0;ON;;;;;N;;;;; +A49D;YI RADICAL YO;So;0;ON;;;;;N;;;;; +A49E;YI RADICAL PUT;So;0;ON;;;;;N;;;;; +A49F;YI RADICAL HXUO;So;0;ON;;;;;N;;;;; +A4A0;YI RADICAL TAT;So;0;ON;;;;;N;;;;; +A4A1;YI RADICAL GA;So;0;ON;;;;;N;;;;; +A4A2;YI RADICAL ZUP;So;0;ON;;;;;N;;;;; +A4A3;YI RADICAL CYT;So;0;ON;;;;;N;;;;; +A4A4;YI RADICAL DDUR;So;0;ON;;;;;N;;;;; +A4A5;YI RADICAL BUR;So;0;ON;;;;;N;;;;; +A4A6;YI RADICAL GGUO;So;0;ON;;;;;N;;;;; +A4A7;YI RADICAL NYOP;So;0;ON;;;;;N;;;;; +A4A8;YI RADICAL TU;So;0;ON;;;;;N;;;;; +A4A9;YI RADICAL OP;So;0;ON;;;;;N;;;;; +A4AA;YI RADICAL JJUT;So;0;ON;;;;;N;;;;; +A4AB;YI RADICAL ZOT;So;0;ON;;;;;N;;;;; +A4AC;YI RADICAL PYT;So;0;ON;;;;;N;;;;; +A4AD;YI RADICAL HMO;So;0;ON;;;;;N;;;;; +A4AE;YI RADICAL YIT;So;0;ON;;;;;N;;;;; +A4AF;YI RADICAL VUR;So;0;ON;;;;;N;;;;; +A4B0;YI RADICAL SHY;So;0;ON;;;;;N;;;;; +A4B1;YI RADICAL VEP;So;0;ON;;;;;N;;;;; +A4B2;YI RADICAL ZA;So;0;ON;;;;;N;;;;; +A4B3;YI RADICAL JO;So;0;ON;;;;;N;;;;; +A4B4;YI RADICAL NZUP;So;0;ON;;;;;N;;;;; +A4B5;YI RADICAL JJY;So;0;ON;;;;;N;;;;; +A4B6;YI RADICAL GOT;So;0;ON;;;;;N;;;;; +A4B7;YI RADICAL JJIE;So;0;ON;;;;;N;;;;; +A4B8;YI RADICAL WO;So;0;ON;;;;;N;;;;; +A4B9;YI RADICAL DU;So;0;ON;;;;;N;;;;; +A4BA;YI RADICAL SHUR;So;0;ON;;;;;N;;;;; +A4BB;YI RADICAL LIE;So;0;ON;;;;;N;;;;; +A4BC;YI RADICAL CY;So;0;ON;;;;;N;;;;; +A4BD;YI RADICAL CUOP;So;0;ON;;;;;N;;;;; +A4BE;YI RADICAL CIP;So;0;ON;;;;;N;;;;; +A4BF;YI RADICAL HXOP;So;0;ON;;;;;N;;;;; +A4C0;YI RADICAL SHAT;So;0;ON;;;;;N;;;;; +A4C1;YI RADICAL ZUR;So;0;ON;;;;;N;;;;; +A4C2;YI RADICAL SHOP;So;0;ON;;;;;N;;;;; +A4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;; +A4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;; +A4C5;YI RADICAL NBIE;So;0;ON;;;;;N;;;;; +A4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;; +AC00;<Hangul Syllable, First>;Lo;0;L;;;;;N;;;;; +D7A3;<Hangul Syllable, Last>;Lo;0;L;;;;;N;;;;; +D800;<Non Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;; +DB7F;<Non Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;; +DB80;<Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;; +DBFF;<Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;; +DC00;<Low Surrogate, First>;Cs;0;L;;;;;N;;;;; +DFFF;<Low Surrogate, Last>;Cs;0;L;;;;;N;;;;; +E000;<Private Use, First>;Co;0;L;;;;;N;;;;; +F8FF;<Private Use, Last>;Co;0;L;;;;;N;;;;; +F900;CJK COMPATIBILITY IDEOGRAPH-F900;Lo;0;L;8C48;;;;N;;;;; +F901;CJK COMPATIBILITY IDEOGRAPH-F901;Lo;0;L;66F4;;;;N;;;;; +F902;CJK COMPATIBILITY IDEOGRAPH-F902;Lo;0;L;8ECA;;;;N;;;;; +F903;CJK COMPATIBILITY IDEOGRAPH-F903;Lo;0;L;8CC8;;;;N;;;;; +F904;CJK COMPATIBILITY IDEOGRAPH-F904;Lo;0;L;6ED1;;;;N;;;;; +F905;CJK COMPATIBILITY IDEOGRAPH-F905;Lo;0;L;4E32;;;;N;;;;; +F906;CJK COMPATIBILITY IDEOGRAPH-F906;Lo;0;L;53E5;;;;N;;;;; +F907;CJK COMPATIBILITY IDEOGRAPH-F907;Lo;0;L;9F9C;;;;N;;;;; +F908;CJK COMPATIBILITY IDEOGRAPH-F908;Lo;0;L;9F9C;;;;N;;;;; +F909;CJK COMPATIBILITY IDEOGRAPH-F909;Lo;0;L;5951;;;;N;;;;; +F90A;CJK COMPATIBILITY IDEOGRAPH-F90A;Lo;0;L;91D1;;;;N;;;;; +F90B;CJK COMPATIBILITY IDEOGRAPH-F90B;Lo;0;L;5587;;;;N;;;;; +F90C;CJK COMPATIBILITY IDEOGRAPH-F90C;Lo;0;L;5948;;;;N;;;;; +F90D;CJK COMPATIBILITY IDEOGRAPH-F90D;Lo;0;L;61F6;;;;N;;;;; +F90E;CJK COMPATIBILITY IDEOGRAPH-F90E;Lo;0;L;7669;;;;N;;;;; +F90F;CJK COMPATIBILITY IDEOGRAPH-F90F;Lo;0;L;7F85;;;;N;;;;; +F910;CJK COMPATIBILITY IDEOGRAPH-F910;Lo;0;L;863F;;;;N;;;;; +F911;CJK COMPATIBILITY IDEOGRAPH-F911;Lo;0;L;87BA;;;;N;;;;; +F912;CJK COMPATIBILITY IDEOGRAPH-F912;Lo;0;L;88F8;;;;N;;;;; +F913;CJK COMPATIBILITY IDEOGRAPH-F913;Lo;0;L;908F;;;;N;;;;; +F914;CJK COMPATIBILITY IDEOGRAPH-F914;Lo;0;L;6A02;;;;N;;;;; +F915;CJK COMPATIBILITY IDEOGRAPH-F915;Lo;0;L;6D1B;;;;N;;;;; +F916;CJK COMPATIBILITY IDEOGRAPH-F916;Lo;0;L;70D9;;;;N;;;;; +F917;CJK COMPATIBILITY IDEOGRAPH-F917;Lo;0;L;73DE;;;;N;;;;; +F918;CJK COMPATIBILITY IDEOGRAPH-F918;Lo;0;L;843D;;;;N;;;;; +F919;CJK COMPATIBILITY IDEOGRAPH-F919;Lo;0;L;916A;;;;N;;;;; +F91A;CJK COMPATIBILITY IDEOGRAPH-F91A;Lo;0;L;99F1;;;;N;;;;; +F91B;CJK COMPATIBILITY IDEOGRAPH-F91B;Lo;0;L;4E82;;;;N;;;;; +F91C;CJK COMPATIBILITY IDEOGRAPH-F91C;Lo;0;L;5375;;;;N;;;;; +F91D;CJK COMPATIBILITY IDEOGRAPH-F91D;Lo;0;L;6B04;;;;N;;;;; +F91E;CJK COMPATIBILITY IDEOGRAPH-F91E;Lo;0;L;721B;;;;N;;;;; +F91F;CJK COMPATIBILITY IDEOGRAPH-F91F;Lo;0;L;862D;;;;N;;;;; +F920;CJK COMPATIBILITY IDEOGRAPH-F920;Lo;0;L;9E1E;;;;N;;;;; +F921;CJK COMPATIBILITY IDEOGRAPH-F921;Lo;0;L;5D50;;;;N;;;;; +F922;CJK COMPATIBILITY IDEOGRAPH-F922;Lo;0;L;6FEB;;;;N;;;;; +F923;CJK COMPATIBILITY IDEOGRAPH-F923;Lo;0;L;85CD;;;;N;;;;; +F924;CJK COMPATIBILITY IDEOGRAPH-F924;Lo;0;L;8964;;;;N;;;;; +F925;CJK COMPATIBILITY IDEOGRAPH-F925;Lo;0;L;62C9;;;;N;;;;; +F926;CJK COMPATIBILITY IDEOGRAPH-F926;Lo;0;L;81D8;;;;N;;;;; +F927;CJK COMPATIBILITY IDEOGRAPH-F927;Lo;0;L;881F;;;;N;;;;; +F928;CJK COMPATIBILITY IDEOGRAPH-F928;Lo;0;L;5ECA;;;;N;;;;; +F929;CJK COMPATIBILITY IDEOGRAPH-F929;Lo;0;L;6717;;;;N;;;;; +F92A;CJK COMPATIBILITY IDEOGRAPH-F92A;Lo;0;L;6D6A;;;;N;;;;; +F92B;CJK COMPATIBILITY IDEOGRAPH-F92B;Lo;0;L;72FC;;;;N;;;;; +F92C;CJK COMPATIBILITY IDEOGRAPH-F92C;Lo;0;L;90CE;;;;N;;;;; +F92D;CJK COMPATIBILITY IDEOGRAPH-F92D;Lo;0;L;4F86;;;;N;;;;; +F92E;CJK COMPATIBILITY IDEOGRAPH-F92E;Lo;0;L;51B7;;;;N;;;;; +F92F;CJK COMPATIBILITY IDEOGRAPH-F92F;Lo;0;L;52DE;;;;N;;;;; +F930;CJK COMPATIBILITY IDEOGRAPH-F930;Lo;0;L;64C4;;;;N;;;;; +F931;CJK COMPATIBILITY IDEOGRAPH-F931;Lo;0;L;6AD3;;;;N;;;;; +F932;CJK COMPATIBILITY IDEOGRAPH-F932;Lo;0;L;7210;;;;N;;;;; +F933;CJK COMPATIBILITY IDEOGRAPH-F933;Lo;0;L;76E7;;;;N;;;;; +F934;CJK COMPATIBILITY IDEOGRAPH-F934;Lo;0;L;8001;;;;N;;;;; +F935;CJK COMPATIBILITY IDEOGRAPH-F935;Lo;0;L;8606;;;;N;;;;; +F936;CJK COMPATIBILITY IDEOGRAPH-F936;Lo;0;L;865C;;;;N;;;;; +F937;CJK COMPATIBILITY IDEOGRAPH-F937;Lo;0;L;8DEF;;;;N;;;;; +F938;CJK COMPATIBILITY IDEOGRAPH-F938;Lo;0;L;9732;;;;N;;;;; +F939;CJK COMPATIBILITY IDEOGRAPH-F939;Lo;0;L;9B6F;;;;N;;;;; +F93A;CJK COMPATIBILITY IDEOGRAPH-F93A;Lo;0;L;9DFA;;;;N;;;;; +F93B;CJK COMPATIBILITY IDEOGRAPH-F93B;Lo;0;L;788C;;;;N;;;;; +F93C;CJK COMPATIBILITY IDEOGRAPH-F93C;Lo;0;L;797F;;;;N;;;;; +F93D;CJK COMPATIBILITY IDEOGRAPH-F93D;Lo;0;L;7DA0;;;;N;;;;; +F93E;CJK COMPATIBILITY IDEOGRAPH-F93E;Lo;0;L;83C9;;;;N;;;;; +F93F;CJK COMPATIBILITY IDEOGRAPH-F93F;Lo;0;L;9304;;;;N;;;;; +F940;CJK COMPATIBILITY IDEOGRAPH-F940;Lo;0;L;9E7F;;;;N;;;;; +F941;CJK COMPATIBILITY IDEOGRAPH-F941;Lo;0;L;8AD6;;;;N;;;;; +F942;CJK COMPATIBILITY IDEOGRAPH-F942;Lo;0;L;58DF;;;;N;;;;; +F943;CJK COMPATIBILITY IDEOGRAPH-F943;Lo;0;L;5F04;;;;N;;;;; +F944;CJK COMPATIBILITY IDEOGRAPH-F944;Lo;0;L;7C60;;;;N;;;;; +F945;CJK COMPATIBILITY IDEOGRAPH-F945;Lo;0;L;807E;;;;N;;;;; +F946;CJK COMPATIBILITY IDEOGRAPH-F946;Lo;0;L;7262;;;;N;;;;; +F947;CJK COMPATIBILITY IDEOGRAPH-F947;Lo;0;L;78CA;;;;N;;;;; +F948;CJK COMPATIBILITY IDEOGRAPH-F948;Lo;0;L;8CC2;;;;N;;;;; +F949;CJK COMPATIBILITY IDEOGRAPH-F949;Lo;0;L;96F7;;;;N;;;;; +F94A;CJK COMPATIBILITY IDEOGRAPH-F94A;Lo;0;L;58D8;;;;N;;;;; +F94B;CJK COMPATIBILITY IDEOGRAPH-F94B;Lo;0;L;5C62;;;;N;;;;; +F94C;CJK COMPATIBILITY IDEOGRAPH-F94C;Lo;0;L;6A13;;;;N;;;;; +F94D;CJK COMPATIBILITY IDEOGRAPH-F94D;Lo;0;L;6DDA;;;;N;;;;; +F94E;CJK COMPATIBILITY IDEOGRAPH-F94E;Lo;0;L;6F0F;;;;N;;;;; +F94F;CJK COMPATIBILITY IDEOGRAPH-F94F;Lo;0;L;7D2F;;;;N;;;;; +F950;CJK COMPATIBILITY IDEOGRAPH-F950;Lo;0;L;7E37;;;;N;;;;; +F951;CJK COMPATIBILITY IDEOGRAPH-F951;Lo;0;L;964B;;;;N;;;;; +F952;CJK COMPATIBILITY IDEOGRAPH-F952;Lo;0;L;52D2;;;;N;;;;; +F953;CJK COMPATIBILITY IDEOGRAPH-F953;Lo;0;L;808B;;;;N;;;;; +F954;CJK COMPATIBILITY IDEOGRAPH-F954;Lo;0;L;51DC;;;;N;;;;; +F955;CJK COMPATIBILITY IDEOGRAPH-F955;Lo;0;L;51CC;;;;N;;;;; +F956;CJK COMPATIBILITY IDEOGRAPH-F956;Lo;0;L;7A1C;;;;N;;;;; +F957;CJK COMPATIBILITY IDEOGRAPH-F957;Lo;0;L;7DBE;;;;N;;;;; +F958;CJK COMPATIBILITY IDEOGRAPH-F958;Lo;0;L;83F1;;;;N;;;;; +F959;CJK COMPATIBILITY IDEOGRAPH-F959;Lo;0;L;9675;;;;N;;;;; +F95A;CJK COMPATIBILITY IDEOGRAPH-F95A;Lo;0;L;8B80;;;;N;;;;; +F95B;CJK COMPATIBILITY IDEOGRAPH-F95B;Lo;0;L;62CF;;;;N;;;;; +F95C;CJK COMPATIBILITY IDEOGRAPH-F95C;Lo;0;L;6A02;;;;N;;;;; +F95D;CJK COMPATIBILITY IDEOGRAPH-F95D;Lo;0;L;8AFE;;;;N;;;;; +F95E;CJK COMPATIBILITY IDEOGRAPH-F95E;Lo;0;L;4E39;;;;N;;;;; +F95F;CJK COMPATIBILITY IDEOGRAPH-F95F;Lo;0;L;5BE7;;;;N;;;;; +F960;CJK COMPATIBILITY IDEOGRAPH-F960;Lo;0;L;6012;;;;N;;;;; +F961;CJK COMPATIBILITY IDEOGRAPH-F961;Lo;0;L;7387;;;;N;;;;; +F962;CJK COMPATIBILITY IDEOGRAPH-F962;Lo;0;L;7570;;;;N;;;;; +F963;CJK COMPATIBILITY IDEOGRAPH-F963;Lo;0;L;5317;;;;N;;;;; +F964;CJK COMPATIBILITY IDEOGRAPH-F964;Lo;0;L;78FB;;;;N;;;;; +F965;CJK COMPATIBILITY IDEOGRAPH-F965;Lo;0;L;4FBF;;;;N;;;;; +F966;CJK COMPATIBILITY IDEOGRAPH-F966;Lo;0;L;5FA9;;;;N;;;;; +F967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;; +F968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;; +F969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;; +F96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;; +F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;;N;;;;; +F96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;; +F96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;; +F96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;; +F96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;; +F970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;; +F971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;; +F972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;; +F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;;N;;;;; +F974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;; +F975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;; +F976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;; +F977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;; +F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;;N;;;;; +F979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;; +F97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;; +F97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;; +F97C;CJK COMPATIBILITY IDEOGRAPH-F97C;Lo;0;L;826F;;;;N;;;;; +F97D;CJK COMPATIBILITY IDEOGRAPH-F97D;Lo;0;L;8AD2;;;;N;;;;; +F97E;CJK COMPATIBILITY IDEOGRAPH-F97E;Lo;0;L;91CF;;;;N;;;;; +F97F;CJK COMPATIBILITY IDEOGRAPH-F97F;Lo;0;L;52F5;;;;N;;;;; +F980;CJK COMPATIBILITY IDEOGRAPH-F980;Lo;0;L;5442;;;;N;;;;; +F981;CJK COMPATIBILITY IDEOGRAPH-F981;Lo;0;L;5973;;;;N;;;;; +F982;CJK COMPATIBILITY IDEOGRAPH-F982;Lo;0;L;5EEC;;;;N;;;;; +F983;CJK COMPATIBILITY IDEOGRAPH-F983;Lo;0;L;65C5;;;;N;;;;; +F984;CJK COMPATIBILITY IDEOGRAPH-F984;Lo;0;L;6FFE;;;;N;;;;; +F985;CJK COMPATIBILITY IDEOGRAPH-F985;Lo;0;L;792A;;;;N;;;;; +F986;CJK COMPATIBILITY IDEOGRAPH-F986;Lo;0;L;95AD;;;;N;;;;; +F987;CJK COMPATIBILITY IDEOGRAPH-F987;Lo;0;L;9A6A;;;;N;;;;; +F988;CJK COMPATIBILITY IDEOGRAPH-F988;Lo;0;L;9E97;;;;N;;;;; +F989;CJK COMPATIBILITY IDEOGRAPH-F989;Lo;0;L;9ECE;;;;N;;;;; +F98A;CJK COMPATIBILITY IDEOGRAPH-F98A;Lo;0;L;529B;;;;N;;;;; +F98B;CJK COMPATIBILITY IDEOGRAPH-F98B;Lo;0;L;66C6;;;;N;;;;; +F98C;CJK COMPATIBILITY IDEOGRAPH-F98C;Lo;0;L;6B77;;;;N;;;;; +F98D;CJK COMPATIBILITY IDEOGRAPH-F98D;Lo;0;L;8F62;;;;N;;;;; +F98E;CJK COMPATIBILITY IDEOGRAPH-F98E;Lo;0;L;5E74;;;;N;;;;; +F98F;CJK COMPATIBILITY IDEOGRAPH-F98F;Lo;0;L;6190;;;;N;;;;; +F990;CJK COMPATIBILITY IDEOGRAPH-F990;Lo;0;L;6200;;;;N;;;;; +F991;CJK COMPATIBILITY IDEOGRAPH-F991;Lo;0;L;649A;;;;N;;;;; +F992;CJK COMPATIBILITY IDEOGRAPH-F992;Lo;0;L;6F23;;;;N;;;;; +F993;CJK COMPATIBILITY IDEOGRAPH-F993;Lo;0;L;7149;;;;N;;;;; +F994;CJK COMPATIBILITY IDEOGRAPH-F994;Lo;0;L;7489;;;;N;;;;; +F995;CJK COMPATIBILITY IDEOGRAPH-F995;Lo;0;L;79CA;;;;N;;;;; +F996;CJK COMPATIBILITY IDEOGRAPH-F996;Lo;0;L;7DF4;;;;N;;;;; +F997;CJK COMPATIBILITY IDEOGRAPH-F997;Lo;0;L;806F;;;;N;;;;; +F998;CJK COMPATIBILITY IDEOGRAPH-F998;Lo;0;L;8F26;;;;N;;;;; +F999;CJK COMPATIBILITY IDEOGRAPH-F999;Lo;0;L;84EE;;;;N;;;;; +F99A;CJK COMPATIBILITY IDEOGRAPH-F99A;Lo;0;L;9023;;;;N;;;;; +F99B;CJK COMPATIBILITY IDEOGRAPH-F99B;Lo;0;L;934A;;;;N;;;;; +F99C;CJK COMPATIBILITY IDEOGRAPH-F99C;Lo;0;L;5217;;;;N;;;;; +F99D;CJK COMPATIBILITY IDEOGRAPH-F99D;Lo;0;L;52A3;;;;N;;;;; +F99E;CJK COMPATIBILITY IDEOGRAPH-F99E;Lo;0;L;54BD;;;;N;;;;; +F99F;CJK COMPATIBILITY IDEOGRAPH-F99F;Lo;0;L;70C8;;;;N;;;;; +F9A0;CJK COMPATIBILITY IDEOGRAPH-F9A0;Lo;0;L;88C2;;;;N;;;;; +F9A1;CJK COMPATIBILITY IDEOGRAPH-F9A1;Lo;0;L;8AAA;;;;N;;;;; +F9A2;CJK COMPATIBILITY IDEOGRAPH-F9A2;Lo;0;L;5EC9;;;;N;;;;; +F9A3;CJK COMPATIBILITY IDEOGRAPH-F9A3;Lo;0;L;5FF5;;;;N;;;;; +F9A4;CJK COMPATIBILITY IDEOGRAPH-F9A4;Lo;0;L;637B;;;;N;;;;; +F9A5;CJK COMPATIBILITY IDEOGRAPH-F9A5;Lo;0;L;6BAE;;;;N;;;;; +F9A6;CJK COMPATIBILITY IDEOGRAPH-F9A6;Lo;0;L;7C3E;;;;N;;;;; +F9A7;CJK COMPATIBILITY IDEOGRAPH-F9A7;Lo;0;L;7375;;;;N;;;;; +F9A8;CJK COMPATIBILITY IDEOGRAPH-F9A8;Lo;0;L;4EE4;;;;N;;;;; +F9A9;CJK COMPATIBILITY IDEOGRAPH-F9A9;Lo;0;L;56F9;;;;N;;;;; +F9AA;CJK COMPATIBILITY IDEOGRAPH-F9AA;Lo;0;L;5BE7;;;;N;;;;; +F9AB;CJK COMPATIBILITY IDEOGRAPH-F9AB;Lo;0;L;5DBA;;;;N;;;;; +F9AC;CJK COMPATIBILITY IDEOGRAPH-F9AC;Lo;0;L;601C;;;;N;;;;; +F9AD;CJK COMPATIBILITY IDEOGRAPH-F9AD;Lo;0;L;73B2;;;;N;;;;; +F9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;; +F9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;; +F9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;; +F9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;; +F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;;N;;;;; +F9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;; +F9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;; +F9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;; +F9B6;CJK COMPATIBILITY IDEOGRAPH-F9B6;Lo;0;L;79AE;;;;N;;;;; +F9B7;CJK COMPATIBILITY IDEOGRAPH-F9B7;Lo;0;L;91B4;;;;N;;;;; +F9B8;CJK COMPATIBILITY IDEOGRAPH-F9B8;Lo;0;L;96B8;;;;N;;;;; +F9B9;CJK COMPATIBILITY IDEOGRAPH-F9B9;Lo;0;L;60E1;;;;N;;;;; +F9BA;CJK COMPATIBILITY IDEOGRAPH-F9BA;Lo;0;L;4E86;;;;N;;;;; +F9BB;CJK COMPATIBILITY IDEOGRAPH-F9BB;Lo;0;L;50DA;;;;N;;;;; +F9BC;CJK COMPATIBILITY IDEOGRAPH-F9BC;Lo;0;L;5BEE;;;;N;;;;; +F9BD;CJK COMPATIBILITY IDEOGRAPH-F9BD;Lo;0;L;5C3F;;;;N;;;;; +F9BE;CJK COMPATIBILITY IDEOGRAPH-F9BE;Lo;0;L;6599;;;;N;;;;; +F9BF;CJK COMPATIBILITY IDEOGRAPH-F9BF;Lo;0;L;6A02;;;;N;;;;; +F9C0;CJK COMPATIBILITY IDEOGRAPH-F9C0;Lo;0;L;71CE;;;;N;;;;; +F9C1;CJK COMPATIBILITY IDEOGRAPH-F9C1;Lo;0;L;7642;;;;N;;;;; +F9C2;CJK COMPATIBILITY IDEOGRAPH-F9C2;Lo;0;L;84FC;;;;N;;;;; +F9C3;CJK COMPATIBILITY IDEOGRAPH-F9C3;Lo;0;L;907C;;;;N;;;;; +F9C4;CJK COMPATIBILITY IDEOGRAPH-F9C4;Lo;0;L;9F8D;;;;N;;;;; +F9C5;CJK COMPATIBILITY IDEOGRAPH-F9C5;Lo;0;L;6688;;;;N;;;;; +F9C6;CJK COMPATIBILITY IDEOGRAPH-F9C6;Lo;0;L;962E;;;;N;;;;; +F9C7;CJK COMPATIBILITY IDEOGRAPH-F9C7;Lo;0;L;5289;;;;N;;;;; +F9C8;CJK COMPATIBILITY IDEOGRAPH-F9C8;Lo;0;L;677B;;;;N;;;;; +F9C9;CJK COMPATIBILITY IDEOGRAPH-F9C9;Lo;0;L;67F3;;;;N;;;;; +F9CA;CJK COMPATIBILITY IDEOGRAPH-F9CA;Lo;0;L;6D41;;;;N;;;;; +F9CB;CJK COMPATIBILITY IDEOGRAPH-F9CB;Lo;0;L;6E9C;;;;N;;;;; +F9CC;CJK COMPATIBILITY IDEOGRAPH-F9CC;Lo;0;L;7409;;;;N;;;;; +F9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;; +F9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;; +F9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;; +F9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;; +F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;;N;;;;; +F9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;; +F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;;N;;;;; +F9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;; +F9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;; +F9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;; +F9D7;CJK COMPATIBILITY IDEOGRAPH-F9D7;Lo;0;L;8F2A;;;;N;;;;; +F9D8;CJK COMPATIBILITY IDEOGRAPH-F9D8;Lo;0;L;5F8B;;;;N;;;;; +F9D9;CJK COMPATIBILITY IDEOGRAPH-F9D9;Lo;0;L;6144;;;;N;;;;; +F9DA;CJK COMPATIBILITY IDEOGRAPH-F9DA;Lo;0;L;6817;;;;N;;;;; +F9DB;CJK COMPATIBILITY IDEOGRAPH-F9DB;Lo;0;L;7387;;;;N;;;;; +F9DC;CJK COMPATIBILITY IDEOGRAPH-F9DC;Lo;0;L;9686;;;;N;;;;; +F9DD;CJK COMPATIBILITY IDEOGRAPH-F9DD;Lo;0;L;5229;;;;N;;;;; +F9DE;CJK COMPATIBILITY IDEOGRAPH-F9DE;Lo;0;L;540F;;;;N;;;;; +F9DF;CJK COMPATIBILITY IDEOGRAPH-F9DF;Lo;0;L;5C65;;;;N;;;;; +F9E0;CJK COMPATIBILITY IDEOGRAPH-F9E0;Lo;0;L;6613;;;;N;;;;; +F9E1;CJK COMPATIBILITY IDEOGRAPH-F9E1;Lo;0;L;674E;;;;N;;;;; +F9E2;CJK COMPATIBILITY IDEOGRAPH-F9E2;Lo;0;L;68A8;;;;N;;;;; +F9E3;CJK COMPATIBILITY IDEOGRAPH-F9E3;Lo;0;L;6CE5;;;;N;;;;; +F9E4;CJK COMPATIBILITY IDEOGRAPH-F9E4;Lo;0;L;7406;;;;N;;;;; +F9E5;CJK COMPATIBILITY IDEOGRAPH-F9E5;Lo;0;L;75E2;;;;N;;;;; +F9E6;CJK COMPATIBILITY IDEOGRAPH-F9E6;Lo;0;L;7F79;;;;N;;;;; +F9E7;CJK COMPATIBILITY IDEOGRAPH-F9E7;Lo;0;L;88CF;;;;N;;;;; +F9E8;CJK COMPATIBILITY IDEOGRAPH-F9E8;Lo;0;L;88E1;;;;N;;;;; +F9E9;CJK COMPATIBILITY IDEOGRAPH-F9E9;Lo;0;L;91CC;;;;N;;;;; +F9EA;CJK COMPATIBILITY IDEOGRAPH-F9EA;Lo;0;L;96E2;;;;N;;;;; +F9EB;CJK COMPATIBILITY IDEOGRAPH-F9EB;Lo;0;L;533F;;;;N;;;;; +F9EC;CJK COMPATIBILITY IDEOGRAPH-F9EC;Lo;0;L;6EBA;;;;N;;;;; +F9ED;CJK COMPATIBILITY IDEOGRAPH-F9ED;Lo;0;L;541D;;;;N;;;;; +F9EE;CJK COMPATIBILITY IDEOGRAPH-F9EE;Lo;0;L;71D0;;;;N;;;;; +F9EF;CJK COMPATIBILITY IDEOGRAPH-F9EF;Lo;0;L;7498;;;;N;;;;; +F9F0;CJK COMPATIBILITY IDEOGRAPH-F9F0;Lo;0;L;85FA;;;;N;;;;; +F9F1;CJK COMPATIBILITY IDEOGRAPH-F9F1;Lo;0;L;96A3;;;;N;;;;; +F9F2;CJK COMPATIBILITY IDEOGRAPH-F9F2;Lo;0;L;9C57;;;;N;;;;; +F9F3;CJK COMPATIBILITY IDEOGRAPH-F9F3;Lo;0;L;9E9F;;;;N;;;;; +F9F4;CJK COMPATIBILITY IDEOGRAPH-F9F4;Lo;0;L;6797;;;;N;;;;; +F9F5;CJK COMPATIBILITY IDEOGRAPH-F9F5;Lo;0;L;6DCB;;;;N;;;;; +F9F6;CJK COMPATIBILITY IDEOGRAPH-F9F6;Lo;0;L;81E8;;;;N;;;;; +F9F7;CJK COMPATIBILITY IDEOGRAPH-F9F7;Lo;0;L;7ACB;;;;N;;;;; +F9F8;CJK COMPATIBILITY IDEOGRAPH-F9F8;Lo;0;L;7B20;;;;N;;;;; +F9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;; +F9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;; +F9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;; +F9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;; +F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;;N;;;;; +F9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;; +F9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;; +FA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;; +FA01;CJK COMPATIBILITY IDEOGRAPH-FA01;Lo;0;L;5EA6;;;;N;;;;; +FA02;CJK COMPATIBILITY IDEOGRAPH-FA02;Lo;0;L;62D3;;;;N;;;;; +FA03;CJK COMPATIBILITY IDEOGRAPH-FA03;Lo;0;L;7CD6;;;;N;;;;; +FA04;CJK COMPATIBILITY IDEOGRAPH-FA04;Lo;0;L;5B85;;;;N;;;;; +FA05;CJK COMPATIBILITY IDEOGRAPH-FA05;Lo;0;L;6D1E;;;;N;;;;; +FA06;CJK COMPATIBILITY IDEOGRAPH-FA06;Lo;0;L;66B4;;;;N;;;;; +FA07;CJK COMPATIBILITY IDEOGRAPH-FA07;Lo;0;L;8F3B;;;;N;;;;; +FA08;CJK COMPATIBILITY IDEOGRAPH-FA08;Lo;0;L;884C;;;;N;;;;; +FA09;CJK COMPATIBILITY IDEOGRAPH-FA09;Lo;0;L;964D;;;;N;;;;; +FA0A;CJK COMPATIBILITY IDEOGRAPH-FA0A;Lo;0;L;898B;;;;N;;;;; +FA0B;CJK COMPATIBILITY IDEOGRAPH-FA0B;Lo;0;L;5ED3;;;;N;;;;; +FA0C;CJK COMPATIBILITY IDEOGRAPH-FA0C;Lo;0;L;5140;;;;N;;;;; +FA0D;CJK COMPATIBILITY IDEOGRAPH-FA0D;Lo;0;L;55C0;;;;N;;;;; +FA0E;CJK COMPATIBILITY IDEOGRAPH-FA0E;Lo;0;L;;;;;N;;;;; +FA0F;CJK COMPATIBILITY IDEOGRAPH-FA0F;Lo;0;L;;;;;N;;;;; +FA10;CJK COMPATIBILITY IDEOGRAPH-FA10;Lo;0;L;585A;;;;N;;;;; +FA11;CJK COMPATIBILITY IDEOGRAPH-FA11;Lo;0;L;;;;;N;;;;; +FA12;CJK COMPATIBILITY IDEOGRAPH-FA12;Lo;0;L;6674;;;;N;;;;; +FA13;CJK COMPATIBILITY IDEOGRAPH-FA13;Lo;0;L;;;;;N;;;;; +FA14;CJK COMPATIBILITY IDEOGRAPH-FA14;Lo;0;L;;;;;N;;;;; +FA15;CJK COMPATIBILITY IDEOGRAPH-FA15;Lo;0;L;51DE;;;;N;;;;; +FA16;CJK COMPATIBILITY IDEOGRAPH-FA16;Lo;0;L;732A;;;;N;;;;; +FA17;CJK COMPATIBILITY IDEOGRAPH-FA17;Lo;0;L;76CA;;;;N;;;;; +FA18;CJK COMPATIBILITY IDEOGRAPH-FA18;Lo;0;L;793C;;;;N;;;;; +FA19;CJK COMPATIBILITY IDEOGRAPH-FA19;Lo;0;L;795E;;;;N;;;;; +FA1A;CJK COMPATIBILITY IDEOGRAPH-FA1A;Lo;0;L;7965;;;;N;;;;; +FA1B;CJK COMPATIBILITY IDEOGRAPH-FA1B;Lo;0;L;798F;;;;N;;;;; +FA1C;CJK COMPATIBILITY IDEOGRAPH-FA1C;Lo;0;L;9756;;;;N;;;;; +FA1D;CJK COMPATIBILITY IDEOGRAPH-FA1D;Lo;0;L;7CBE;;;;N;;;;; +FA1E;CJK COMPATIBILITY IDEOGRAPH-FA1E;Lo;0;L;7FBD;;;;N;;;;; +FA1F;CJK COMPATIBILITY IDEOGRAPH-FA1F;Lo;0;L;;;;;N;;*;;; +FA20;CJK COMPATIBILITY IDEOGRAPH-FA20;Lo;0;L;8612;;;;N;;;;; +FA21;CJK COMPATIBILITY IDEOGRAPH-FA21;Lo;0;L;;;;;N;;;;; +FA22;CJK COMPATIBILITY IDEOGRAPH-FA22;Lo;0;L;8AF8;;;;N;;;;; +FA23;CJK COMPATIBILITY IDEOGRAPH-FA23;Lo;0;L;;;;;N;;*;;; +FA24;CJK COMPATIBILITY IDEOGRAPH-FA24;Lo;0;L;;;;;N;;;;; +FA25;CJK COMPATIBILITY IDEOGRAPH-FA25;Lo;0;L;9038;;;;N;;;;; +FA26;CJK COMPATIBILITY IDEOGRAPH-FA26;Lo;0;L;90FD;;;;N;;;;; +FA27;CJK COMPATIBILITY IDEOGRAPH-FA27;Lo;0;L;;;;;N;;;;; +FA28;CJK COMPATIBILITY IDEOGRAPH-FA28;Lo;0;L;;;;;N;;;;; +FA29;CJK COMPATIBILITY IDEOGRAPH-FA29;Lo;0;L;;;;;N;;;;; +FA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;; +FA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;; +FA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;; +FA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;; +FA30;CJK COMPATIBILITY IDEOGRAPH-FA30;Lo;0;L;4FAE;;;;N;;;;; +FA31;CJK COMPATIBILITY IDEOGRAPH-FA31;Lo;0;L;50E7;;;;N;;;;; +FA32;CJK COMPATIBILITY IDEOGRAPH-FA32;Lo;0;L;514D;;;;N;;;;; +FA33;CJK COMPATIBILITY IDEOGRAPH-FA33;Lo;0;L;52C9;;;;N;;;;; +FA34;CJK COMPATIBILITY IDEOGRAPH-FA34;Lo;0;L;52E4;;;;N;;;;; +FA35;CJK COMPATIBILITY IDEOGRAPH-FA35;Lo;0;L;5351;;;;N;;;;; +FA36;CJK COMPATIBILITY IDEOGRAPH-FA36;Lo;0;L;559D;;;;N;;;;; +FA37;CJK COMPATIBILITY IDEOGRAPH-FA37;Lo;0;L;5606;;;;N;;;;; +FA38;CJK COMPATIBILITY IDEOGRAPH-FA38;Lo;0;L;5668;;;;N;;;;; +FA39;CJK COMPATIBILITY IDEOGRAPH-FA39;Lo;0;L;5840;;;;N;;;;; +FA3A;CJK COMPATIBILITY IDEOGRAPH-FA3A;Lo;0;L;58A8;;;;N;;;;; +FA3B;CJK COMPATIBILITY IDEOGRAPH-FA3B;Lo;0;L;5C64;;;;N;;;;; +FA3C;CJK COMPATIBILITY IDEOGRAPH-FA3C;Lo;0;L;5C6E;;;;N;;;;; +FA3D;CJK COMPATIBILITY IDEOGRAPH-FA3D;Lo;0;L;6094;;;;N;;;;; +FA3E;CJK COMPATIBILITY IDEOGRAPH-FA3E;Lo;0;L;6168;;;;N;;;;; +FA3F;CJK COMPATIBILITY IDEOGRAPH-FA3F;Lo;0;L;618E;;;;N;;;;; +FA40;CJK COMPATIBILITY IDEOGRAPH-FA40;Lo;0;L;61F2;;;;N;;;;; +FA41;CJK COMPATIBILITY IDEOGRAPH-FA41;Lo;0;L;654F;;;;N;;;;; +FA42;CJK COMPATIBILITY IDEOGRAPH-FA42;Lo;0;L;65E2;;;;N;;;;; +FA43;CJK COMPATIBILITY IDEOGRAPH-FA43;Lo;0;L;6691;;;;N;;;;; +FA44;CJK COMPATIBILITY IDEOGRAPH-FA44;Lo;0;L;6885;;;;N;;;;; +FA45;CJK COMPATIBILITY IDEOGRAPH-FA45;Lo;0;L;6D77;;;;N;;;;; +FA46;CJK COMPATIBILITY IDEOGRAPH-FA46;Lo;0;L;6E1A;;;;N;;;;; +FA47;CJK COMPATIBILITY IDEOGRAPH-FA47;Lo;0;L;6F22;;;;N;;;;; +FA48;CJK COMPATIBILITY IDEOGRAPH-FA48;Lo;0;L;716E;;;;N;;;;; +FA49;CJK COMPATIBILITY IDEOGRAPH-FA49;Lo;0;L;722B;;;;N;;;;; +FA4A;CJK COMPATIBILITY IDEOGRAPH-FA4A;Lo;0;L;7422;;;;N;;;;; +FA4B;CJK COMPATIBILITY IDEOGRAPH-FA4B;Lo;0;L;7891;;;;N;;;;; +FA4C;CJK COMPATIBILITY IDEOGRAPH-FA4C;Lo;0;L;793E;;;;N;;;;; +FA4D;CJK COMPATIBILITY IDEOGRAPH-FA4D;Lo;0;L;7949;;;;N;;;;; +FA4E;CJK COMPATIBILITY IDEOGRAPH-FA4E;Lo;0;L;7948;;;;N;;;;; +FA4F;CJK COMPATIBILITY IDEOGRAPH-FA4F;Lo;0;L;7950;;;;N;;;;; +FA50;CJK COMPATIBILITY IDEOGRAPH-FA50;Lo;0;L;7956;;;;N;;;;; +FA51;CJK COMPATIBILITY IDEOGRAPH-FA51;Lo;0;L;795D;;;;N;;;;; +FA52;CJK COMPATIBILITY IDEOGRAPH-FA52;Lo;0;L;798D;;;;N;;;;; +FA53;CJK COMPATIBILITY IDEOGRAPH-FA53;Lo;0;L;798E;;;;N;;;;; +FA54;CJK COMPATIBILITY IDEOGRAPH-FA54;Lo;0;L;7A40;;;;N;;;;; +FA55;CJK COMPATIBILITY IDEOGRAPH-FA55;Lo;0;L;7A81;;;;N;;;;; +FA56;CJK COMPATIBILITY IDEOGRAPH-FA56;Lo;0;L;7BC0;;;;N;;;;; +FA57;CJK COMPATIBILITY IDEOGRAPH-FA57;Lo;0;L;7DF4;;;;N;;;;; +FA58;CJK COMPATIBILITY IDEOGRAPH-FA58;Lo;0;L;7E09;;;;N;;;;; +FA59;CJK COMPATIBILITY IDEOGRAPH-FA59;Lo;0;L;7E41;;;;N;;;;; +FA5A;CJK COMPATIBILITY IDEOGRAPH-FA5A;Lo;0;L;7F72;;;;N;;;;; +FA5B;CJK COMPATIBILITY IDEOGRAPH-FA5B;Lo;0;L;8005;;;;N;;;;; +FA5C;CJK COMPATIBILITY IDEOGRAPH-FA5C;Lo;0;L;81ED;;;;N;;;;; +FA5D;CJK COMPATIBILITY IDEOGRAPH-FA5D;Lo;0;L;8279;;;;N;;;;; +FA5E;CJK COMPATIBILITY IDEOGRAPH-FA5E;Lo;0;L;8279;;;;N;;;;; +FA5F;CJK COMPATIBILITY IDEOGRAPH-FA5F;Lo;0;L;8457;;;;N;;;;; +FA60;CJK COMPATIBILITY IDEOGRAPH-FA60;Lo;0;L;8910;;;;N;;;;; +FA61;CJK COMPATIBILITY IDEOGRAPH-FA61;Lo;0;L;8996;;;;N;;;;; +FA62;CJK COMPATIBILITY IDEOGRAPH-FA62;Lo;0;L;8B01;;;;N;;;;; +FA63;CJK COMPATIBILITY IDEOGRAPH-FA63;Lo;0;L;8B39;;;;N;;;;; +FA64;CJK COMPATIBILITY IDEOGRAPH-FA64;Lo;0;L;8CD3;;;;N;;;;; +FA65;CJK COMPATIBILITY IDEOGRAPH-FA65;Lo;0;L;8D08;;;;N;;;;; +FA66;CJK COMPATIBILITY IDEOGRAPH-FA66;Lo;0;L;8FB6;;;;N;;;;; +FA67;CJK COMPATIBILITY IDEOGRAPH-FA67;Lo;0;L;9038;;;;N;;;;; +FA68;CJK COMPATIBILITY IDEOGRAPH-FA68;Lo;0;L;96E3;;;;N;;;;; +FA69;CJK COMPATIBILITY IDEOGRAPH-FA69;Lo;0;L;97FF;;;;N;;;;; +FA6A;CJK COMPATIBILITY IDEOGRAPH-FA6A;Lo;0;L;983B;;;;N;;;;; +FB00;LATIN SMALL LIGATURE FF;Ll;0;L;<compat> 0066 0066;;;;N;;;;; +FB01;LATIN SMALL LIGATURE FI;Ll;0;L;<compat> 0066 0069;;;;N;;;;; +FB02;LATIN SMALL LIGATURE FL;Ll;0;L;<compat> 0066 006C;;;;N;;;;; +FB03;LATIN SMALL LIGATURE FFI;Ll;0;L;<compat> 0066 0066 0069;;;;N;;;;; +FB04;LATIN SMALL LIGATURE FFL;Ll;0;L;<compat> 0066 0066 006C;;;;N;;;;; +FB05;LATIN SMALL LIGATURE LONG S T;Ll;0;L;<compat> 017F 0074;;;;N;;;;; +FB06;LATIN SMALL LIGATURE ST;Ll;0;L;<compat> 0073 0074;;;;N;;;;; +FB13;ARMENIAN SMALL LIGATURE MEN NOW;Ll;0;L;<compat> 0574 0576;;;;N;;;;; +FB14;ARMENIAN SMALL LIGATURE MEN ECH;Ll;0;L;<compat> 0574 0565;;;;N;;;;; +FB15;ARMENIAN SMALL LIGATURE MEN INI;Ll;0;L;<compat> 0574 056B;;;;N;;;;; +FB16;ARMENIAN SMALL LIGATURE VEW NOW;Ll;0;L;<compat> 057E 0576;;;;N;;;;; +FB17;ARMENIAN SMALL LIGATURE MEN XEH;Ll;0;L;<compat> 0574 056D;;;;N;;;;; +FB1D;HEBREW LETTER YOD WITH HIRIQ;Lo;0;R;05D9 05B4;;;;N;;;;; +FB1E;HEBREW POINT JUDEO-SPANISH VARIKA;Mn;26;NSM;;;;;N;HEBREW POINT VARIKA;;;; +FB1F;HEBREW LIGATURE YIDDISH YOD YOD PATAH;Lo;0;R;05F2 05B7;;;;N;;;;; +FB20;HEBREW LETTER ALTERNATIVE AYIN;Lo;0;R;<font> 05E2;;;;N;;;;; +FB21;HEBREW LETTER WIDE ALEF;Lo;0;R;<font> 05D0;;;;N;;;;; +FB22;HEBREW LETTER WIDE DALET;Lo;0;R;<font> 05D3;;;;N;;;;; +FB23;HEBREW LETTER WIDE HE;Lo;0;R;<font> 05D4;;;;N;;;;; +FB24;HEBREW LETTER WIDE KAF;Lo;0;R;<font> 05DB;;;;N;;;;; +FB25;HEBREW LETTER WIDE LAMED;Lo;0;R;<font> 05DC;;;;N;;;;; +FB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R;<font> 05DD;;;;N;;;;; +FB27;HEBREW LETTER WIDE RESH;Lo;0;R;<font> 05E8;;;;N;;;;; +FB28;HEBREW LETTER WIDE TAV;Lo;0;R;<font> 05EA;;;;N;;;;; +FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ET;<font> 002B;;;;N;;;;; +FB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;; +FB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;; +FB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;; +FB2D;HEBREW LETTER SHIN WITH DAGESH AND SIN DOT;Lo;0;R;FB49 05C2;;;;N;;;;; +FB2E;HEBREW LETTER ALEF WITH PATAH;Lo;0;R;05D0 05B7;;;;N;;;;; +FB2F;HEBREW LETTER ALEF WITH QAMATS;Lo;0;R;05D0 05B8;;;;N;;;;; +FB30;HEBREW LETTER ALEF WITH MAPIQ;Lo;0;R;05D0 05BC;;;;N;;;;; +FB31;HEBREW LETTER BET WITH DAGESH;Lo;0;R;05D1 05BC;;;;N;;;;; +FB32;HEBREW LETTER GIMEL WITH DAGESH;Lo;0;R;05D2 05BC;;;;N;;;;; +FB33;HEBREW LETTER DALET WITH DAGESH;Lo;0;R;05D3 05BC;;;;N;;;;; +FB34;HEBREW LETTER HE WITH MAPIQ;Lo;0;R;05D4 05BC;;;;N;;;;; +FB35;HEBREW LETTER VAV WITH DAGESH;Lo;0;R;05D5 05BC;;;;N;;;;; +FB36;HEBREW LETTER ZAYIN WITH DAGESH;Lo;0;R;05D6 05BC;;;;N;;;;; +FB38;HEBREW LETTER TET WITH DAGESH;Lo;0;R;05D8 05BC;;;;N;;;;; +FB39;HEBREW LETTER YOD WITH DAGESH;Lo;0;R;05D9 05BC;;;;N;;;;; +FB3A;HEBREW LETTER FINAL KAF WITH DAGESH;Lo;0;R;05DA 05BC;;;;N;;;;; +FB3B;HEBREW LETTER KAF WITH DAGESH;Lo;0;R;05DB 05BC;;;;N;;;;; +FB3C;HEBREW LETTER LAMED WITH DAGESH;Lo;0;R;05DC 05BC;;;;N;;;;; +FB3E;HEBREW LETTER MEM WITH DAGESH;Lo;0;R;05DE 05BC;;;;N;;;;; +FB40;HEBREW LETTER NUN WITH DAGESH;Lo;0;R;05E0 05BC;;;;N;;;;; +FB41;HEBREW LETTER SAMEKH WITH DAGESH;Lo;0;R;05E1 05BC;;;;N;;;;; +FB43;HEBREW LETTER FINAL PE WITH DAGESH;Lo;0;R;05E3 05BC;;;;N;;;;; +FB44;HEBREW LETTER PE WITH DAGESH;Lo;0;R;05E4 05BC;;;;N;;;;; +FB46;HEBREW LETTER TSADI WITH DAGESH;Lo;0;R;05E6 05BC;;;;N;;;;; +FB47;HEBREW LETTER QOF WITH DAGESH;Lo;0;R;05E7 05BC;;;;N;;;;; +FB48;HEBREW LETTER RESH WITH DAGESH;Lo;0;R;05E8 05BC;;;;N;;;;; +FB49;HEBREW LETTER SHIN WITH DAGESH;Lo;0;R;05E9 05BC;;;;N;;;;; +FB4A;HEBREW LETTER TAV WITH DAGESH;Lo;0;R;05EA 05BC;;;;N;;;;; +FB4B;HEBREW LETTER VAV WITH HOLAM;Lo;0;R;05D5 05B9;;;;N;;;;; +FB4C;HEBREW LETTER BET WITH RAFE;Lo;0;R;05D1 05BF;;;;N;;;;; +FB4D;HEBREW LETTER KAF WITH RAFE;Lo;0;R;05DB 05BF;;;;N;;;;; +FB4E;HEBREW LETTER PE WITH RAFE;Lo;0;R;05E4 05BF;;;;N;;;;; +FB4F;HEBREW LIGATURE ALEF LAMED;Lo;0;R;<compat> 05D0 05DC;;;;N;;;;; +FB50;ARABIC LETTER ALEF WASLA ISOLATED FORM;Lo;0;AL;<isolated> 0671;;;;N;;;;; +FB51;ARABIC LETTER ALEF WASLA FINAL FORM;Lo;0;AL;<final> 0671;;;;N;;;;; +FB52;ARABIC LETTER BEEH ISOLATED FORM;Lo;0;AL;<isolated> 067B;;;;N;;;;; +FB53;ARABIC LETTER BEEH FINAL FORM;Lo;0;AL;<final> 067B;;;;N;;;;; +FB54;ARABIC LETTER BEEH INITIAL FORM;Lo;0;AL;<initial> 067B;;;;N;;;;; +FB55;ARABIC LETTER BEEH MEDIAL FORM;Lo;0;AL;<medial> 067B;;;;N;;;;; +FB56;ARABIC LETTER PEH ISOLATED FORM;Lo;0;AL;<isolated> 067E;;;;N;;;;; +FB57;ARABIC LETTER PEH FINAL FORM;Lo;0;AL;<final> 067E;;;;N;;;;; +FB58;ARABIC LETTER PEH INITIAL FORM;Lo;0;AL;<initial> 067E;;;;N;;;;; +FB59;ARABIC LETTER PEH MEDIAL FORM;Lo;0;AL;<medial> 067E;;;;N;;;;; +FB5A;ARABIC LETTER BEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0680;;;;N;;;;; +FB5B;ARABIC LETTER BEHEH FINAL FORM;Lo;0;AL;<final> 0680;;;;N;;;;; +FB5C;ARABIC LETTER BEHEH INITIAL FORM;Lo;0;AL;<initial> 0680;;;;N;;;;; +FB5D;ARABIC LETTER BEHEH MEDIAL FORM;Lo;0;AL;<medial> 0680;;;;N;;;;; +FB5E;ARABIC LETTER TTEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067A;;;;N;;;;; +FB5F;ARABIC LETTER TTEHEH FINAL FORM;Lo;0;AL;<final> 067A;;;;N;;;;; +FB60;ARABIC LETTER TTEHEH INITIAL FORM;Lo;0;AL;<initial> 067A;;;;N;;;;; +FB61;ARABIC LETTER TTEHEH MEDIAL FORM;Lo;0;AL;<medial> 067A;;;;N;;;;; +FB62;ARABIC LETTER TEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067F;;;;N;;;;; +FB63;ARABIC LETTER TEHEH FINAL FORM;Lo;0;AL;<final> 067F;;;;N;;;;; +FB64;ARABIC LETTER TEHEH INITIAL FORM;Lo;0;AL;<initial> 067F;;;;N;;;;; +FB65;ARABIC LETTER TEHEH MEDIAL FORM;Lo;0;AL;<medial> 067F;;;;N;;;;; +FB66;ARABIC LETTER TTEH ISOLATED FORM;Lo;0;AL;<isolated> 0679;;;;N;;;;; +FB67;ARABIC LETTER TTEH FINAL FORM;Lo;0;AL;<final> 0679;;;;N;;;;; +FB68;ARABIC LETTER TTEH INITIAL FORM;Lo;0;AL;<initial> 0679;;;;N;;;;; +FB69;ARABIC LETTER TTEH MEDIAL FORM;Lo;0;AL;<medial> 0679;;;;N;;;;; +FB6A;ARABIC LETTER VEH ISOLATED FORM;Lo;0;AL;<isolated> 06A4;;;;N;;;;; +FB6B;ARABIC LETTER VEH FINAL FORM;Lo;0;AL;<final> 06A4;;;;N;;;;; +FB6C;ARABIC LETTER VEH INITIAL FORM;Lo;0;AL;<initial> 06A4;;;;N;;;;; +FB6D;ARABIC LETTER VEH MEDIAL FORM;Lo;0;AL;<medial> 06A4;;;;N;;;;; +FB6E;ARABIC LETTER PEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A6;;;;N;;;;; +FB6F;ARABIC LETTER PEHEH FINAL FORM;Lo;0;AL;<final> 06A6;;;;N;;;;; +FB70;ARABIC LETTER PEHEH INITIAL FORM;Lo;0;AL;<initial> 06A6;;;;N;;;;; +FB71;ARABIC LETTER PEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A6;;;;N;;;;; +FB72;ARABIC LETTER DYEH ISOLATED FORM;Lo;0;AL;<isolated> 0684;;;;N;;;;; +FB73;ARABIC LETTER DYEH FINAL FORM;Lo;0;AL;<final> 0684;;;;N;;;;; +FB74;ARABIC LETTER DYEH INITIAL FORM;Lo;0;AL;<initial> 0684;;;;N;;;;; +FB75;ARABIC LETTER DYEH MEDIAL FORM;Lo;0;AL;<medial> 0684;;;;N;;;;; +FB76;ARABIC LETTER NYEH ISOLATED FORM;Lo;0;AL;<isolated> 0683;;;;N;;;;; +FB77;ARABIC LETTER NYEH FINAL FORM;Lo;0;AL;<final> 0683;;;;N;;;;; +FB78;ARABIC LETTER NYEH INITIAL FORM;Lo;0;AL;<initial> 0683;;;;N;;;;; +FB79;ARABIC LETTER NYEH MEDIAL FORM;Lo;0;AL;<medial> 0683;;;;N;;;;; +FB7A;ARABIC LETTER TCHEH ISOLATED FORM;Lo;0;AL;<isolated> 0686;;;;N;;;;; +FB7B;ARABIC LETTER TCHEH FINAL FORM;Lo;0;AL;<final> 0686;;;;N;;;;; +FB7C;ARABIC LETTER TCHEH INITIAL FORM;Lo;0;AL;<initial> 0686;;;;N;;;;; +FB7D;ARABIC LETTER TCHEH MEDIAL FORM;Lo;0;AL;<medial> 0686;;;;N;;;;; +FB7E;ARABIC LETTER TCHEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0687;;;;N;;;;; +FB7F;ARABIC LETTER TCHEHEH FINAL FORM;Lo;0;AL;<final> 0687;;;;N;;;;; +FB80;ARABIC LETTER TCHEHEH INITIAL FORM;Lo;0;AL;<initial> 0687;;;;N;;;;; +FB81;ARABIC LETTER TCHEHEH MEDIAL FORM;Lo;0;AL;<medial> 0687;;;;N;;;;; +FB82;ARABIC LETTER DDAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068D;;;;N;;;;; +FB83;ARABIC LETTER DDAHAL FINAL FORM;Lo;0;AL;<final> 068D;;;;N;;;;; +FB84;ARABIC LETTER DAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068C;;;;N;;;;; +FB85;ARABIC LETTER DAHAL FINAL FORM;Lo;0;AL;<final> 068C;;;;N;;;;; +FB86;ARABIC LETTER DUL ISOLATED FORM;Lo;0;AL;<isolated> 068E;;;;N;;;;; +FB87;ARABIC LETTER DUL FINAL FORM;Lo;0;AL;<final> 068E;;;;N;;;;; +FB88;ARABIC LETTER DDAL ISOLATED FORM;Lo;0;AL;<isolated> 0688;;;;N;;;;; +FB89;ARABIC LETTER DDAL FINAL FORM;Lo;0;AL;<final> 0688;;;;N;;;;; +FB8A;ARABIC LETTER JEH ISOLATED FORM;Lo;0;AL;<isolated> 0698;;;;N;;;;; +FB8B;ARABIC LETTER JEH FINAL FORM;Lo;0;AL;<final> 0698;;;;N;;;;; +FB8C;ARABIC LETTER RREH ISOLATED FORM;Lo;0;AL;<isolated> 0691;;;;N;;;;; +FB8D;ARABIC LETTER RREH FINAL FORM;Lo;0;AL;<final> 0691;;;;N;;;;; +FB8E;ARABIC LETTER KEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A9;;;;N;;;;; +FB8F;ARABIC LETTER KEHEH FINAL FORM;Lo;0;AL;<final> 06A9;;;;N;;;;; +FB90;ARABIC LETTER KEHEH INITIAL FORM;Lo;0;AL;<initial> 06A9;;;;N;;;;; +FB91;ARABIC LETTER KEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A9;;;;N;;;;; +FB92;ARABIC LETTER GAF ISOLATED FORM;Lo;0;AL;<isolated> 06AF;;;;N;;;;; +FB93;ARABIC LETTER GAF FINAL FORM;Lo;0;AL;<final> 06AF;;;;N;;;;; +FB94;ARABIC LETTER GAF INITIAL FORM;Lo;0;AL;<initial> 06AF;;;;N;;;;; +FB95;ARABIC LETTER GAF MEDIAL FORM;Lo;0;AL;<medial> 06AF;;;;N;;;;; +FB96;ARABIC LETTER GUEH ISOLATED FORM;Lo;0;AL;<isolated> 06B3;;;;N;;;;; +FB97;ARABIC LETTER GUEH FINAL FORM;Lo;0;AL;<final> 06B3;;;;N;;;;; +FB98;ARABIC LETTER GUEH INITIAL FORM;Lo;0;AL;<initial> 06B3;;;;N;;;;; +FB99;ARABIC LETTER GUEH MEDIAL FORM;Lo;0;AL;<medial> 06B3;;;;N;;;;; +FB9A;ARABIC LETTER NGOEH ISOLATED FORM;Lo;0;AL;<isolated> 06B1;;;;N;;;;; +FB9B;ARABIC LETTER NGOEH FINAL FORM;Lo;0;AL;<final> 06B1;;;;N;;;;; +FB9C;ARABIC LETTER NGOEH INITIAL FORM;Lo;0;AL;<initial> 06B1;;;;N;;;;; +FB9D;ARABIC LETTER NGOEH MEDIAL FORM;Lo;0;AL;<medial> 06B1;;;;N;;;;; +FB9E;ARABIC LETTER NOON GHUNNA ISOLATED FORM;Lo;0;AL;<isolated> 06BA;;;;N;;;;; +FB9F;ARABIC LETTER NOON GHUNNA FINAL FORM;Lo;0;AL;<final> 06BA;;;;N;;;;; +FBA0;ARABIC LETTER RNOON ISOLATED FORM;Lo;0;AL;<isolated> 06BB;;;;N;;;;; +FBA1;ARABIC LETTER RNOON FINAL FORM;Lo;0;AL;<final> 06BB;;;;N;;;;; +FBA2;ARABIC LETTER RNOON INITIAL FORM;Lo;0;AL;<initial> 06BB;;;;N;;;;; +FBA3;ARABIC LETTER RNOON MEDIAL FORM;Lo;0;AL;<medial> 06BB;;;;N;;;;; +FBA4;ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06C0;;;;N;;;;; +FBA5;ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM;Lo;0;AL;<final> 06C0;;;;N;;;;; +FBA6;ARABIC LETTER HEH GOAL ISOLATED FORM;Lo;0;AL;<isolated> 06C1;;;;N;;;;; +FBA7;ARABIC LETTER HEH GOAL FINAL FORM;Lo;0;AL;<final> 06C1;;;;N;;;;; +FBA8;ARABIC LETTER HEH GOAL INITIAL FORM;Lo;0;AL;<initial> 06C1;;;;N;;;;; +FBA9;ARABIC LETTER HEH GOAL MEDIAL FORM;Lo;0;AL;<medial> 06C1;;;;N;;;;; +FBAA;ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM;Lo;0;AL;<isolated> 06BE;;;;N;;;;; +FBAB;ARABIC LETTER HEH DOACHASHMEE FINAL FORM;Lo;0;AL;<final> 06BE;;;;N;;;;; +FBAC;ARABIC LETTER HEH DOACHASHMEE INITIAL FORM;Lo;0;AL;<initial> 06BE;;;;N;;;;; +FBAD;ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM;Lo;0;AL;<medial> 06BE;;;;N;;;;; +FBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL;<isolated> 06D2;;;;N;;;;; +FBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL;<final> 06D2;;;;N;;;;; +FBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06D3;;;;N;;;;; +FBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 06D3;;;;N;;;;; +FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL;<isolated> 06AD;;;;N;;;;; +FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL;<final> 06AD;;;;N;;;;; +FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL;<initial> 06AD;;;;N;;;;; +FBD6;ARABIC LETTER NG MEDIAL FORM;Lo;0;AL;<medial> 06AD;;;;N;;;;; +FBD7;ARABIC LETTER U ISOLATED FORM;Lo;0;AL;<isolated> 06C7;;;;N;;;;; +FBD8;ARABIC LETTER U FINAL FORM;Lo;0;AL;<final> 06C7;;;;N;;;;; +FBD9;ARABIC LETTER OE ISOLATED FORM;Lo;0;AL;<isolated> 06C6;;;;N;;;;; +FBDA;ARABIC LETTER OE FINAL FORM;Lo;0;AL;<final> 06C6;;;;N;;;;; +FBDB;ARABIC LETTER YU ISOLATED FORM;Lo;0;AL;<isolated> 06C8;;;;N;;;;; +FBDC;ARABIC LETTER YU FINAL FORM;Lo;0;AL;<final> 06C8;;;;N;;;;; +FBDD;ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0677;;;;N;;;;; +FBDE;ARABIC LETTER VE ISOLATED FORM;Lo;0;AL;<isolated> 06CB;;;;N;;;;; +FBDF;ARABIC LETTER VE FINAL FORM;Lo;0;AL;<final> 06CB;;;;N;;;;; +FBE0;ARABIC LETTER KIRGHIZ OE ISOLATED FORM;Lo;0;AL;<isolated> 06C5;;;;N;;;;; +FBE1;ARABIC LETTER KIRGHIZ OE FINAL FORM;Lo;0;AL;<final> 06C5;;;;N;;;;; +FBE2;ARABIC LETTER KIRGHIZ YU ISOLATED FORM;Lo;0;AL;<isolated> 06C9;;;;N;;;;; +FBE3;ARABIC LETTER KIRGHIZ YU FINAL FORM;Lo;0;AL;<final> 06C9;;;;N;;;;; +FBE4;ARABIC LETTER E ISOLATED FORM;Lo;0;AL;<isolated> 06D0;;;;N;;;;; +FBE5;ARABIC LETTER E FINAL FORM;Lo;0;AL;<final> 06D0;;;;N;;;;; +FBE6;ARABIC LETTER E INITIAL FORM;Lo;0;AL;<initial> 06D0;;;;N;;;;; +FBE7;ARABIC LETTER E MEDIAL FORM;Lo;0;AL;<medial> 06D0;;;;N;;;;; +FBE8;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0649;;;;N;;;;; +FBE9;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM;Lo;0;AL;<medial> 0649;;;;N;;;;; +FBEA;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0626 0627;;;;N;;;;; +FBEB;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM;Lo;0;AL;<final> 0626 0627;;;;N;;;;; +FBEC;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D5;;;;N;;;;; +FBED;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM;Lo;0;AL;<final> 0626 06D5;;;;N;;;;; +FBEE;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM;Lo;0;AL;<isolated> 0626 0648;;;;N;;;;; +FBEF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM;Lo;0;AL;<final> 0626 0648;;;;N;;;;; +FBF0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C7;;;;N;;;;; +FBF1;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM;Lo;0;AL;<final> 0626 06C7;;;;N;;;;; +FBF2;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C6;;;;N;;;;; +FBF3;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM;Lo;0;AL;<final> 0626 06C6;;;;N;;;;; +FBF4;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C8;;;;N;;;;; +FBF5;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM;Lo;0;AL;<final> 0626 06C8;;;;N;;;;; +FBF6;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D0;;;;N;;;;; +FBF7;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM;Lo;0;AL;<final> 0626 06D0;;;;N;;;;; +FBF8;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM;Lo;0;AL;<initial> 0626 06D0;;;;N;;;;; +FBF9;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;; +FBFA;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;; +FBFB;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0626 0649;;;;N;;;;; +FBFC;ARABIC LETTER FARSI YEH ISOLATED FORM;Lo;0;AL;<isolated> 06CC;;;;N;;;;; +FBFD;ARABIC LETTER FARSI YEH FINAL FORM;Lo;0;AL;<final> 06CC;;;;N;;;;; +FBFE;ARABIC LETTER FARSI YEH INITIAL FORM;Lo;0;AL;<initial> 06CC;;;;N;;;;; +FBFF;ARABIC LETTER FARSI YEH MEDIAL FORM;Lo;0;AL;<medial> 06CC;;;;N;;;;; +FC00;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 062C;;;;N;;;;; +FC01;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0626 062D;;;;N;;;;; +FC02;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 0645;;;;N;;;;; +FC03;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;; +FC04;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0626 064A;;;;N;;;;; +FC05;ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 062C;;;;N;;;;; +FC06;ARABIC LIGATURE BEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062D;;;;N;;;;; +FC07;ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062E;;;;N;;;;; +FC08;ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 0645;;;;N;;;;; +FC09;ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0628 0649;;;;N;;;;; +FC0A;ARABIC LIGATURE BEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0628 064A;;;;N;;;;; +FC0B;ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 062C;;;;N;;;;; +FC0C;ARABIC LIGATURE TEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062D;;;;N;;;;; +FC0D;ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062E;;;;N;;;;; +FC0E;ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 0645;;;;N;;;;; +FC0F;ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062A 0649;;;;N;;;;; +FC10;ARABIC LIGATURE TEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062A 064A;;;;N;;;;; +FC11;ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 062C;;;;N;;;;; +FC12;ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 0645;;;;N;;;;; +FC13;ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062B 0649;;;;N;;;;; +FC14;ARABIC LIGATURE THEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062B 064A;;;;N;;;;; +FC15;ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062C 062D;;;;N;;;;; +FC16;ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C 0645;;;;N;;;;; +FC17;ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 062C;;;;N;;;;; +FC18;ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 0645;;;;N;;;;; +FC19;ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 062C;;;;N;;;;; +FC1A;ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062E 062D;;;;N;;;;; +FC1B;ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 0645;;;;N;;;;; +FC1C;ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 062C;;;;N;;;;; +FC1D;ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062D;;;;N;;;;; +FC1E;ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062E;;;;N;;;;; +FC1F;ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 0645;;;;N;;;;; +FC20;ARABIC LIGATURE SAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0635 062D;;;;N;;;;; +FC21;ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0645;;;;N;;;;; +FC22;ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 062C;;;;N;;;;; +FC23;ARABIC LIGATURE DAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062D;;;;N;;;;; +FC24;ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062E;;;;N;;;;; +FC25;ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 0645;;;;N;;;;; +FC26;ARABIC LIGATURE TAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0637 062D;;;;N;;;;; +FC27;ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0637 0645;;;;N;;;;; +FC28;ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0638 0645;;;;N;;;;; +FC29;ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 062C;;;;N;;;;; +FC2A;ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 0645;;;;N;;;;; +FC2B;ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 062C;;;;N;;;;; +FC2C;ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 0645;;;;N;;;;; +FC2D;ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 062C;;;;N;;;;; +FC2E;ARABIC LIGATURE FEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062D;;;;N;;;;; +FC2F;ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062E;;;;N;;;;; +FC30;ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 0645;;;;N;;;;; +FC31;ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0641 0649;;;;N;;;;; +FC32;ARABIC LIGATURE FEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0641 064A;;;;N;;;;; +FC33;ARABIC LIGATURE QAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0642 062D;;;;N;;;;; +FC34;ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0642 0645;;;;N;;;;; +FC35;ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0642 0649;;;;N;;;;; +FC36;ARABIC LIGATURE QAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0642 064A;;;;N;;;;; +FC37;ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0643 0627;;;;N;;;;; +FC38;ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 062C;;;;N;;;;; +FC39;ARABIC LIGATURE KAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062D;;;;N;;;;; +FC3A;ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062E;;;;N;;;;; +FC3B;ARABIC LIGATURE KAF WITH LAM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0644;;;;N;;;;; +FC3C;ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0645;;;;N;;;;; +FC3D;ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0643 0649;;;;N;;;;; +FC3E;ARABIC LIGATURE KAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0643 064A;;;;N;;;;; +FC3F;ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 062C;;;;N;;;;; +FC40;ARABIC LIGATURE LAM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062D;;;;N;;;;; +FC41;ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062E;;;;N;;;;; +FC42;ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 0645;;;;N;;;;; +FC43;ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0644 0649;;;;N;;;;; +FC44;ARABIC LIGATURE LAM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0644 064A;;;;N;;;;; +FC45;ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 062C;;;;N;;;;; +FC46;ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D;;;;N;;;;; +FC47;ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062E;;;;N;;;;; +FC48;ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 0645;;;;N;;;;; +FC49;ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0645 0649;;;;N;;;;; +FC4A;ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0645 064A;;;;N;;;;; +FC4B;ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 062C;;;;N;;;;; +FC4C;ARABIC LIGATURE NOON WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062D;;;;N;;;;; +FC4D;ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062E;;;;N;;;;; +FC4E;ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 0645;;;;N;;;;; +FC4F;ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0646 0649;;;;N;;;;; +FC50;ARABIC LIGATURE NOON WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0646 064A;;;;N;;;;; +FC51;ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 062C;;;;N;;;;; +FC52;ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 0645;;;;N;;;;; +FC53;ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0647 0649;;;;N;;;;; +FC54;ARABIC LIGATURE HEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0647 064A;;;;N;;;;; +FC55;ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 062C;;;;N;;;;; +FC56;ARABIC LIGATURE YEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062D;;;;N;;;;; +FC57;ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062E;;;;N;;;;; +FC58;ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 0645;;;;N;;;;; +FC59;ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 064A 0649;;;;N;;;;; +FC5A;ARABIC LIGATURE YEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A 064A;;;;N;;;;; +FC5B;ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0630 0670;;;;N;;;;; +FC5C;ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0631 0670;;;;N;;;;; +FC5D;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0649 0670;;;;N;;;;; +FC5E;ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C 0651;;;;N;;;;; +FC5F;ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D 0651;;;;N;;;;; +FC60;ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E 0651;;;;N;;;;; +FC61;ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F 0651;;;;N;;;;; +FC62;ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650 0651;;;;N;;;;; +FC63;ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651 0670;;;;N;;;;; +FC64;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM;Lo;0;AL;<final> 0626 0631;;;;N;;;;; +FC65;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0626 0632;;;;N;;;;; +FC66;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM;Lo;0;AL;<final> 0626 0645;;;;N;;;;; +FC67;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM;Lo;0;AL;<final> 0626 0646;;;;N;;;;; +FC68;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;; +FC69;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM;Lo;0;AL;<final> 0626 064A;;;;N;;;;; +FC6A;ARABIC LIGATURE BEH WITH REH FINAL FORM;Lo;0;AL;<final> 0628 0631;;;;N;;;;; +FC6B;ARABIC LIGATURE BEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0628 0632;;;;N;;;;; +FC6C;ARABIC LIGATURE BEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0628 0645;;;;N;;;;; +FC6D;ARABIC LIGATURE BEH WITH NOON FINAL FORM;Lo;0;AL;<final> 0628 0646;;;;N;;;;; +FC6E;ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0628 0649;;;;N;;;;; +FC6F;ARABIC LIGATURE BEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 064A;;;;N;;;;; +FC70;ARABIC LIGATURE TEH WITH REH FINAL FORM;Lo;0;AL;<final> 062A 0631;;;;N;;;;; +FC71;ARABIC LIGATURE TEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062A 0632;;;;N;;;;; +FC72;ARABIC LIGATURE TEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062A 0645;;;;N;;;;; +FC73;ARABIC LIGATURE TEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062A 0646;;;;N;;;;; +FC74;ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0649;;;;N;;;;; +FC75;ARABIC LIGATURE TEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 064A;;;;N;;;;; +FC76;ARABIC LIGATURE THEH WITH REH FINAL FORM;Lo;0;AL;<final> 062B 0631;;;;N;;;;; +FC77;ARABIC LIGATURE THEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062B 0632;;;;N;;;;; +FC78;ARABIC LIGATURE THEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062B 0645;;;;N;;;;; +FC79;ARABIC LIGATURE THEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062B 0646;;;;N;;;;; +FC7A;ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062B 0649;;;;N;;;;; +FC7B;ARABIC LIGATURE THEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062B 064A;;;;N;;;;; +FC7C;ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0641 0649;;;;N;;;;; +FC7D;ARABIC LIGATURE FEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 064A;;;;N;;;;; +FC7E;ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0642 0649;;;;N;;;;; +FC7F;ARABIC LIGATURE QAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 064A;;;;N;;;;; +FC80;ARABIC LIGATURE KAF WITH ALEF FINAL FORM;Lo;0;AL;<final> 0643 0627;;;;N;;;;; +FC81;ARABIC LIGATURE KAF WITH LAM FINAL FORM;Lo;0;AL;<final> 0643 0644;;;;N;;;;; +FC82;ARABIC LIGATURE KAF WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645;;;;N;;;;; +FC83;ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0643 0649;;;;N;;;;; +FC84;ARABIC LIGATURE KAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 064A;;;;N;;;;; +FC85;ARABIC LIGATURE LAM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 0645;;;;N;;;;; +FC86;ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 0649;;;;N;;;;; +FC87;ARABIC LIGATURE LAM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 064A;;;;N;;;;; +FC88;ARABIC LIGATURE MEEM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0645 0627;;;;N;;;;; +FC89;ARABIC LIGATURE MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0645 0645;;;;N;;;;; +FC8A;ARABIC LIGATURE NOON WITH REH FINAL FORM;Lo;0;AL;<final> 0646 0631;;;;N;;;;; +FC8B;ARABIC LIGATURE NOON WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0646 0632;;;;N;;;;; +FC8C;ARABIC LIGATURE NOON WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 0645;;;;N;;;;; +FC8D;ARABIC LIGATURE NOON WITH NOON FINAL FORM;Lo;0;AL;<final> 0646 0646;;;;N;;;;; +FC8E;ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0649;;;;N;;;;; +FC8F;ARABIC LIGATURE NOON WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 064A;;;;N;;;;; +FC90;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM;Lo;0;AL;<final> 0649 0670;;;;N;;;;; +FC91;ARABIC LIGATURE YEH WITH REH FINAL FORM;Lo;0;AL;<final> 064A 0631;;;;N;;;;; +FC92;ARABIC LIGATURE YEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 064A 0632;;;;N;;;;; +FC93;ARABIC LIGATURE YEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645;;;;N;;;;; +FC94;ARABIC LIGATURE YEH WITH NOON FINAL FORM;Lo;0;AL;<final> 064A 0646;;;;N;;;;; +FC95;ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 064A 0649;;;;N;;;;; +FC96;ARABIC LIGATURE YEH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 064A;;;;N;;;;; +FC97;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0626 062C;;;;N;;;;; +FC98;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0626 062D;;;;N;;;;; +FC99;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0626 062E;;;;N;;;;; +FC9A;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0626 0645;;;;N;;;;; +FC9B;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0626 0647;;;;N;;;;; +FC9C;ARABIC LIGATURE BEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0628 062C;;;;N;;;;; +FC9D;ARABIC LIGATURE BEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0628 062D;;;;N;;;;; +FC9E;ARABIC LIGATURE BEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0628 062E;;;;N;;;;; +FC9F;ARABIC LIGATURE BEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0628 0645;;;;N;;;;; +FCA0;ARABIC LIGATURE BEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0628 0647;;;;N;;;;; +FCA1;ARABIC LIGATURE TEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C;;;;N;;;;; +FCA2;ARABIC LIGATURE TEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 062D;;;;N;;;;; +FCA3;ARABIC LIGATURE TEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 062E;;;;N;;;;; +FCA4;ARABIC LIGATURE TEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645;;;;N;;;;; +FCA5;ARABIC LIGATURE TEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 062A 0647;;;;N;;;;; +FCA6;ARABIC LIGATURE THEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062B 0645;;;;N;;;;; +FCA7;ARABIC LIGATURE JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 062D;;;;N;;;;; +FCA8;ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062C 0645;;;;N;;;;; +FCA9;ARABIC LIGATURE HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062D 062C;;;;N;;;;; +FCAA;ARABIC LIGATURE HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062D 0645;;;;N;;;;; +FCAB;ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062E 062C;;;;N;;;;; +FCAC;ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062E 0645;;;;N;;;;; +FCAD;ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062C;;;;N;;;;; +FCAE;ARABIC LIGATURE SEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062D;;;;N;;;;; +FCAF;ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0633 062E;;;;N;;;;; +FCB0;ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645;;;;N;;;;; +FCB1;ARABIC LIGATURE SAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D;;;;N;;;;; +FCB2;ARABIC LIGATURE SAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0635 062E;;;;N;;;;; +FCB3;ARABIC LIGATURE SAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645;;;;N;;;;; +FCB4;ARABIC LIGATURE DAD WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062C;;;;N;;;;; +FCB5;ARABIC LIGATURE DAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0636 062D;;;;N;;;;; +FCB6;ARABIC LIGATURE DAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0636 062E;;;;N;;;;; +FCB7;ARABIC LIGATURE DAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 0645;;;;N;;;;; +FCB8;ARABIC LIGATURE TAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 062D;;;;N;;;;; +FCB9;ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0638 0645;;;;N;;;;; +FCBA;ARABIC LIGATURE AIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C;;;;N;;;;; +FCBB;ARABIC LIGATURE AIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645;;;;N;;;;; +FCBC;ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 063A 062C;;;;N;;;;; +FCBD;ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 063A 0645;;;;N;;;;; +FCBE;ARABIC LIGATURE FEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062C;;;;N;;;;; +FCBF;ARABIC LIGATURE FEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0641 062D;;;;N;;;;; +FCC0;ARABIC LIGATURE FEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0641 062E;;;;N;;;;; +FCC1;ARABIC LIGATURE FEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 0645;;;;N;;;;; +FCC2;ARABIC LIGATURE QAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 062D;;;;N;;;;; +FCC3;ARABIC LIGATURE QAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0642 0645;;;;N;;;;; +FCC4;ARABIC LIGATURE KAF WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0643 062C;;;;N;;;;; +FCC5;ARABIC LIGATURE KAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0643 062D;;;;N;;;;; +FCC6;ARABIC LIGATURE KAF WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0643 062E;;;;N;;;;; +FCC7;ARABIC LIGATURE KAF WITH LAM INITIAL FORM;Lo;0;AL;<initial> 0643 0644;;;;N;;;;; +FCC8;ARABIC LIGATURE KAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645;;;;N;;;;; +FCC9;ARABIC LIGATURE LAM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C;;;;N;;;;; +FCCA;ARABIC LIGATURE LAM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 062D;;;;N;;;;; +FCCB;ARABIC LIGATURE LAM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0644 062E;;;;N;;;;; +FCCC;ARABIC LIGATURE LAM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 0645;;;;N;;;;; +FCCD;ARABIC LIGATURE LAM WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0644 0647;;;;N;;;;; +FCCE;ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C;;;;N;;;;; +FCCF;ARABIC LIGATURE MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062D;;;;N;;;;; +FCD0;ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062E;;;;N;;;;; +FCD1;ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 0645;;;;N;;;;; +FCD2;ARABIC LIGATURE NOON WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C;;;;N;;;;; +FCD3;ARABIC LIGATURE NOON WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062D;;;;N;;;;; +FCD4;ARABIC LIGATURE NOON WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0646 062E;;;;N;;;;; +FCD5;ARABIC LIGATURE NOON WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 0645;;;;N;;;;; +FCD6;ARABIC LIGATURE NOON WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0646 0647;;;;N;;;;; +FCD7;ARABIC LIGATURE HEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 062C;;;;N;;;;; +FCD8;ARABIC LIGATURE HEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645;;;;N;;;;; +FCD9;ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM;Lo;0;AL;<initial> 0647 0670;;;;N;;;;; +FCDA;ARABIC LIGATURE YEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 064A 062C;;;;N;;;;; +FCDB;ARABIC LIGATURE YEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 064A 062D;;;;N;;;;; +FCDC;ARABIC LIGATURE YEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 064A 062E;;;;N;;;;; +FCDD;ARABIC LIGATURE YEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645;;;;N;;;;; +FCDE;ARABIC LIGATURE YEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 064A 0647;;;;N;;;;; +FCDF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0626 0645;;;;N;;;;; +FCE0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0626 0647;;;;N;;;;; +FCE1;ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0628 0645;;;;N;;;;; +FCE2;ARABIC LIGATURE BEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0628 0647;;;;N;;;;; +FCE3;ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062A 0645;;;;N;;;;; +FCE4;ARABIC LIGATURE TEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062A 0647;;;;N;;;;; +FCE5;ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062B 0645;;;;N;;;;; +FCE6;ARABIC LIGATURE THEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062B 0647;;;;N;;;;; +FCE7;ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 0645;;;;N;;;;; +FCE8;ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0633 0647;;;;N;;;;; +FCE9;ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 0645;;;;N;;;;; +FCEA;ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0634 0647;;;;N;;;;; +FCEB;ARABIC LIGATURE KAF WITH LAM MEDIAL FORM;Lo;0;AL;<medial> 0643 0644;;;;N;;;;; +FCEC;ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0643 0645;;;;N;;;;; +FCED;ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0644 0645;;;;N;;;;; +FCEE;ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0646 0645;;;;N;;;;; +FCEF;ARABIC LIGATURE NOON WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0646 0647;;;;N;;;;; +FCF0;ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 064A 0645;;;;N;;;;; +FCF1;ARABIC LIGATURE YEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 064A 0647;;;;N;;;;; +FCF2;ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E 0651;;;;N;;;;; +FCF3;ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F 0651;;;;N;;;;; +FCF4;ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650 0651;;;;N;;;;; +FCF5;ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0637 0649;;;;N;;;;; +FCF6;ARABIC LIGATURE TAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0637 064A;;;;N;;;;; +FCF7;ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0639 0649;;;;N;;;;; +FCF8;ARABIC LIGATURE AIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0639 064A;;;;N;;;;; +FCF9;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 063A 0649;;;;N;;;;; +FCFA;ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 063A 064A;;;;N;;;;; +FCFB;ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0633 0649;;;;N;;;;; +FCFC;ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0633 064A;;;;N;;;;; +FCFD;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0634 0649;;;;N;;;;; +FCFE;ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0634 064A;;;;N;;;;; +FCFF;ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062D 0649;;;;N;;;;; +FD00;ARABIC LIGATURE HAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062D 064A;;;;N;;;;; +FD01;ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062C 0649;;;;N;;;;; +FD02;ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062C 064A;;;;N;;;;; +FD03;ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062E 0649;;;;N;;;;; +FD04;ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062E 064A;;;;N;;;;; +FD05;ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0649;;;;N;;;;; +FD06;ARABIC LIGATURE SAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0635 064A;;;;N;;;;; +FD07;ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0636 0649;;;;N;;;;; +FD08;ARABIC LIGATURE DAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0636 064A;;;;N;;;;; +FD09;ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 062C;;;;N;;;;; +FD0A;ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062D;;;;N;;;;; +FD0B;ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062E;;;;N;;;;; +FD0C;ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 0645;;;;N;;;;; +FD0D;ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0634 0631;;;;N;;;;; +FD0E;ARABIC LIGATURE SEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0633 0631;;;;N;;;;; +FD0F;ARABIC LIGATURE SAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0635 0631;;;;N;;;;; +FD10;ARABIC LIGATURE DAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0636 0631;;;;N;;;;; +FD11;ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0637 0649;;;;N;;;;; +FD12;ARABIC LIGATURE TAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 064A;;;;N;;;;; +FD13;ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0649;;;;N;;;;; +FD14;ARABIC LIGATURE AIN WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 064A;;;;N;;;;; +FD15;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0649;;;;N;;;;; +FD16;ARABIC LIGATURE GHAIN WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 064A;;;;N;;;;; +FD17;ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 0649;;;;N;;;;; +FD18;ARABIC LIGATURE SEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 064A;;;;N;;;;; +FD19;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0634 0649;;;;N;;;;; +FD1A;ARABIC LIGATURE SHEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 064A;;;;N;;;;; +FD1B;ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0649;;;;N;;;;; +FD1C;ARABIC LIGATURE HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 064A;;;;N;;;;; +FD1D;ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0649;;;;N;;;;; +FD1E;ARABIC LIGATURE JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 064A;;;;N;;;;; +FD1F;ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062E 0649;;;;N;;;;; +FD20;ARABIC LIGATURE KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062E 064A;;;;N;;;;; +FD21;ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0635 0649;;;;N;;;;; +FD22;ARABIC LIGATURE SAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 064A;;;;N;;;;; +FD23;ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 0649;;;;N;;;;; +FD24;ARABIC LIGATURE DAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 064A;;;;N;;;;; +FD25;ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM;Lo;0;AL;<final> 0634 062C;;;;N;;;;; +FD26;ARABIC LIGATURE SHEEN WITH HAH FINAL FORM;Lo;0;AL;<final> 0634 062D;;;;N;;;;; +FD27;ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 062E;;;;N;;;;; +FD28;ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645;;;;N;;;;; +FD29;ARABIC LIGATURE SHEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0634 0631;;;;N;;;;; +FD2A;ARABIC LIGATURE SEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0633 0631;;;;N;;;;; +FD2B;ARABIC LIGATURE SAD WITH REH FINAL FORM;Lo;0;AL;<final> 0635 0631;;;;N;;;;; +FD2C;ARABIC LIGATURE DAD WITH REH FINAL FORM;Lo;0;AL;<final> 0636 0631;;;;N;;;;; +FD2D;ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062C;;;;N;;;;; +FD2E;ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0634 062D;;;;N;;;;; +FD2F;ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 062E;;;;N;;;;; +FD30;ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645;;;;N;;;;; +FD31;ARABIC LIGATURE SEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0633 0647;;;;N;;;;; +FD32;ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0634 0647;;;;N;;;;; +FD33;ARABIC LIGATURE TAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645;;;;N;;;;; +FD34;ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 062C;;;;N;;;;; +FD35;ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062D;;;;N;;;;; +FD36;ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062E;;;;N;;;;; +FD37;ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 062C;;;;N;;;;; +FD38;ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062D;;;;N;;;;; +FD39;ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062E;;;;N;;;;; +FD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0637 0645;;;;N;;;;; +FD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0638 0645;;;;N;;;;; +FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL;<final> 0627 064B;;;;N;;;;; +FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0627 064B;;;;N;;;;; +FD3E;ORNATE LEFT PARENTHESIS;Ps;0;ON;;;;;N;;;;; +FD3F;ORNATE RIGHT PARENTHESIS;Pe;0;ON;;;;;N;;;;; +FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C 0645;;;;N;;;;; +FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL;<final> 062A 062D 062C;;;;N;;;;; +FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 062C;;;;N;;;;; +FD53;ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 0645;;;;N;;;;; +FD54;ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062E 0645;;;;N;;;;; +FD55;ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062C;;;;N;;;;; +FD56;ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062D;;;;N;;;;; +FD57;ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062E;;;;N;;;;; +FD58;ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 062C 0645 062D;;;;N;;;;; +FD59;ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 0645 062D;;;;N;;;;; +FD5A;ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 0645 064A;;;;N;;;;; +FD5B;ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0645 0649;;;;N;;;;; +FD5C;ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062D 062C;;;;N;;;;; +FD5D;ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062C 062D;;;;N;;;;; +FD5E;ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062C 0649;;;;N;;;;; +FD5F;ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0633 0645 062D;;;;N;;;;; +FD60;ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062D;;;;N;;;;; +FD61;ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062C;;;;N;;;;; +FD62;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0633 0645 0645;;;;N;;;;; +FD63;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 0645;;;;N;;;;; +FD64;ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM;Lo;0;AL;<final> 0635 062D 062D;;;;N;;;;; +FD65;ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D 062D;;;;N;;;;; +FD66;ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0635 0645 0645;;;;N;;;;; +FD67;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 062D 0645;;;;N;;;;; +FD68;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062D 0645;;;;N;;;;; +FD69;ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062C 064A;;;;N;;;;; +FD6A;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 0645 062E;;;;N;;;;; +FD6B;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 0645 062E;;;;N;;;;; +FD6C;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645 0645;;;;N;;;;; +FD6D;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645 0645;;;;N;;;;; +FD6E;ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 062D 0649;;;;N;;;;; +FD6F;ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0636 062E 0645;;;;N;;;;; +FD70;ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062E 0645;;;;N;;;;; +FD71;ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0637 0645 062D;;;;N;;;;; +FD72;ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 0645 062D;;;;N;;;;; +FD73;ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645 0645;;;;N;;;;; +FD74;ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 0645 064A;;;;N;;;;; +FD75;ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 062C 0645;;;;N;;;;; +FD76;ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 0645 0645;;;;N;;;;; +FD77;ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645 0645;;;;N;;;;; +FD78;ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0645 0649;;;;N;;;;; +FD79;ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 063A 0645 0645;;;;N;;;;; +FD7A;ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 0645 064A;;;;N;;;;; +FD7B;ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0645 0649;;;;N;;;;; +FD7C;ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0641 062E 0645;;;;N;;;;; +FD7D;ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062E 0645;;;;N;;;;; +FD7E;ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0642 0645 062D;;;;N;;;;; +FD7F;ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0642 0645 0645;;;;N;;;;; +FD80;ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062D 0645;;;;N;;;;; +FD81;ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062D 064A;;;;N;;;;; +FD82;ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 062D 0649;;;;N;;;;; +FD83;ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 062C;;;;N;;;;; +FD84;ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 062C;;;;N;;;;; +FD85;ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062E 0645;;;;N;;;;; +FD86;ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062E 0645;;;;N;;;;; +FD87;ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0644 0645 062D;;;;N;;;;; +FD88;ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 0645 062D;;;;N;;;;; +FD89;ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 062C;;;;N;;;;; +FD8A;ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 0645;;;;N;;;;; +FD8B;ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062D 064A;;;;N;;;;; +FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062D;;;;N;;;;; +FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C 0645;;;;N;;;;; +FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 062C;;;;N;;;;; +FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 0645;;;;N;;;;; +FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062E;;;;N;;;;; +FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 062C;;;;N;;;;; +FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 0645;;;;N;;;;; +FD95;ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062D 0645;;;;N;;;;; +FD96;ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062D 0649;;;;N;;;;; +FD97;ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 062C 0645;;;;N;;;;; +FD98;ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C 0645;;;;N;;;;; +FD99;ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062C 0649;;;;N;;;;; +FD9A;ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 0645 064A;;;;N;;;;; +FD9B;ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0645 0649;;;;N;;;;; +FD9C;ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645 0645;;;;N;;;;; +FD9D;ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645 0645;;;;N;;;;; +FD9E;ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062E 064A;;;;N;;;;; +FD9F;ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062C 064A;;;;N;;;;; +FDA0;ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062C 0649;;;;N;;;;; +FDA1;ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062E 064A;;;;N;;;;; +FDA2;ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062E 0649;;;;N;;;;; +FDA3;ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 0645 064A;;;;N;;;;; +FDA4;ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0645 0649;;;;N;;;;; +FDA5;ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 0645 064A;;;;N;;;;; +FDA6;ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 062D 0649;;;;N;;;;; +FDA7;ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0645 0649;;;;N;;;;; +FDA8;ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062E 0649;;;;N;;;;; +FDA9;ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 062D 064A;;;;N;;;;; +FDAA;ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062D 064A;;;;N;;;;; +FDAB;ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 062D 064A;;;;N;;;;; +FDAC;ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062C 064A;;;;N;;;;; +FDAD;ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 0645 064A;;;;N;;;;; +FDAE;ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062D 064A;;;;N;;;;; +FDAF;ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062C 064A;;;;N;;;;; +FDB0;ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 0645 064A;;;;N;;;;; +FDB1;ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 0645 064A;;;;N;;;;; +FDB2;ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 0645 064A;;;;N;;;;; +FDB3;ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062D 064A;;;;N;;;;; +FDB4;ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 0645 062D;;;;N;;;;; +FDB5;ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062D 0645;;;;N;;;;; +FDB6;ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 0645 064A;;;;N;;;;; +FDB7;ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 0645 064A;;;;N;;;;; +FDB8;ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062C 062D;;;;N;;;;; +FDB9;ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062E 064A;;;;N;;;;; +FDBA;ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 0645;;;;N;;;;; +FDBB;ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645 0645;;;;N;;;;; +FDBC;ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 0645;;;;N;;;;; +FDBD;ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0646 062C 062D;;;;N;;;;; +FDBE;ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 062D 064A;;;;N;;;;; +FDBF;ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 062C 064A;;;;N;;;;; +FDC0;ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062C 064A;;;;N;;;;; +FDC1;ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 0645 064A;;;;N;;;;; +FDC2;ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062D 064A;;;;N;;;;; +FDC3;ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645 0645;;;;N;;;;; +FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C 0645;;;;N;;;;; +FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645 0645;;;;N;;;;; +FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 062E 064A;;;;N;;;;; +FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062C 064A;;;;N;;;;; +FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 06D2;;;;N;;;;; +FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0642 0644 06D2;;;;N;;;;; +FDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL;<isolated> 0627 0644 0644 0647;;;;N;;;;; +FDF3;ARABIC LIGATURE AKBAR ISOLATED FORM;Lo;0;AL;<isolated> 0627 0643 0628 0631;;;;N;;;;; +FDF4;ARABIC LIGATURE MOHAMMAD ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D 0645 062F;;;;N;;;;; +FDF5;ARABIC LIGATURE SALAM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0639 0645;;;;N;;;;; +FDF6;ARABIC LIGATURE RASOUL ISOLATED FORM;Lo;0;AL;<isolated> 0631 0633 0648 0644;;;;N;;;;; +FDF7;ARABIC LIGATURE ALAYHE ISOLATED FORM;Lo;0;AL;<isolated> 0639 0644 064A 0647;;;;N;;;;; +FDF8;ARABIC LIGATURE WASALLAM ISOLATED FORM;Lo;0;AL;<isolated> 0648 0633 0644 0645;;;;N;;;;; +FDF9;ARABIC LIGATURE SALLA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0649;;;;N;;;;; +FDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL;<isolated> 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;;;;N;ARABIC LETTER SALLALLAHOU ALAYHE WASALLAM;;;; +FDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL;<isolated> 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;; +FDFC;RIAL SIGN;Sc;0;AL;<isolated> 0631 06CC 0627 0644;;;;N;;;;; +FDFD;ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM;So;0;ON;;;;;N;;;;; +FE00;VARIATION SELECTOR-1;Mn;0;NSM;;;;;N;;;;; +FE01;VARIATION SELECTOR-2;Mn;0;NSM;;;;;N;;;;; +FE02;VARIATION SELECTOR-3;Mn;0;NSM;;;;;N;;;;; +FE03;VARIATION SELECTOR-4;Mn;0;NSM;;;;;N;;;;; +FE04;VARIATION SELECTOR-5;Mn;0;NSM;;;;;N;;;;; +FE05;VARIATION SELECTOR-6;Mn;0;NSM;;;;;N;;;;; +FE06;VARIATION SELECTOR-7;Mn;0;NSM;;;;;N;;;;; +FE07;VARIATION SELECTOR-8;Mn;0;NSM;;;;;N;;;;; +FE08;VARIATION SELECTOR-9;Mn;0;NSM;;;;;N;;;;; +FE09;VARIATION SELECTOR-10;Mn;0;NSM;;;;;N;;;;; +FE0A;VARIATION SELECTOR-11;Mn;0;NSM;;;;;N;;;;; +FE0B;VARIATION SELECTOR-12;Mn;0;NSM;;;;;N;;;;; +FE0C;VARIATION SELECTOR-13;Mn;0;NSM;;;;;N;;;;; +FE0D;VARIATION SELECTOR-14;Mn;0;NSM;;;;;N;;;;; +FE0E;VARIATION SELECTOR-15;Mn;0;NSM;;;;;N;;;;; +FE0F;VARIATION SELECTOR-16;Mn;0;NSM;;;;;N;;;;; +FE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;; +FE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; +FE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;; +FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; +FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON;<vertical> 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;; +FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON;<vertical> 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;; +FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON;<vertical> 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;; +FE33;PRESENTATION FORM FOR VERTICAL LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING UNDERSCORE;;;; +FE34;PRESENTATION FORM FOR VERTICAL WAVY LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING WAVY UNDERSCORE;;;; +FE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps;0;ON;<vertical> 0028;;;;N;GLYPH FOR VERTICAL OPENING PARENTHESIS;;;; +FE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe;0;ON;<vertical> 0029;;;;N;GLYPH FOR VERTICAL CLOSING PARENTHESIS;;;; +FE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps;0;ON;<vertical> 007B;;;;N;GLYPH FOR VERTICAL OPENING CURLY BRACKET;;;; +FE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe;0;ON;<vertical> 007D;;;;N;GLYPH FOR VERTICAL CLOSING CURLY BRACKET;;;; +FE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<vertical> 3014;;;;N;GLYPH FOR VERTICAL OPENING TORTOISE SHELL BRACKET;;;; +FE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<vertical> 3015;;;;N;GLYPH FOR VERTICAL CLOSING TORTOISE SHELL BRACKET;;;; +FE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;<vertical> 3010;;;;N;GLYPH FOR VERTICAL OPENING BLACK LENTICULAR BRACKET;;;; +FE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;<vertical> 3011;;;;N;GLYPH FOR VERTICAL CLOSING BLACK LENTICULAR BRACKET;;;; +FE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;<vertical> 300A;;;;N;GLYPH FOR VERTICAL OPENING DOUBLE ANGLE BRACKET;;;; +FE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;<vertical> 300B;;;;N;GLYPH FOR VERTICAL CLOSING DOUBLE ANGLE BRACKET;;;; +FE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps;0;ON;<vertical> 3008;;;;N;GLYPH FOR VERTICAL OPENING ANGLE BRACKET;;;; +FE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe;0;ON;<vertical> 3009;;;;N;GLYPH FOR VERTICAL CLOSING ANGLE BRACKET;;;; +FE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps;0;ON;<vertical> 300C;;;;N;GLYPH FOR VERTICAL OPENING CORNER BRACKET;;;; +FE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe;0;ON;<vertical> 300D;;;;N;GLYPH FOR VERTICAL CLOSING CORNER BRACKET;;;; +FE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps;0;ON;<vertical> 300E;;;;N;GLYPH FOR VERTICAL OPENING WHITE CORNER BRACKET;;;; +FE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe;0;ON;<vertical> 300F;;;;N;GLYPH FOR VERTICAL CLOSING WHITE CORNER BRACKET;;;; +FE45;SESAME DOT;Po;0;ON;;;;;N;;;;; +FE46;WHITE SESAME DOT;Po;0;ON;;;;;N;;;;; +FE47;PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET;Ps;0;ON;<vertical> 005B;;;;N;;;;; +FE48;PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET;Pe;0;ON;<vertical> 005D;;;;N;;;;; +FE49;DASHED OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DASHED OVERSCORE;;;; +FE4A;CENTRELINE OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING CENTERLINE OVERSCORE;;;; +FE4B;WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING WAVY OVERSCORE;;;; +FE4C;DOUBLE WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DOUBLE WAVY OVERSCORE;;;; +FE4D;DASHED LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING DASHED UNDERSCORE;;;; +FE4E;CENTRELINE LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING CENTERLINE UNDERSCORE;;;; +FE4F;WAVY LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING WAVY UNDERSCORE;;;; +FE50;SMALL COMMA;Po;0;CS;<small> 002C;;;;N;;;;; +FE51;SMALL IDEOGRAPHIC COMMA;Po;0;ON;<small> 3001;;;;N;;;;; +FE52;SMALL FULL STOP;Po;0;CS;<small> 002E;;;;N;SMALL PERIOD;;;; +FE54;SMALL SEMICOLON;Po;0;ON;<small> 003B;;;;N;;;;; +FE55;SMALL COLON;Po;0;CS;<small> 003A;;;;N;;;;; +FE56;SMALL QUESTION MARK;Po;0;ON;<small> 003F;;;;N;;;;; +FE57;SMALL EXCLAMATION MARK;Po;0;ON;<small> 0021;;;;N;;;;; +FE58;SMALL EM DASH;Pd;0;ON;<small> 2014;;;;N;;;;; +FE59;SMALL LEFT PARENTHESIS;Ps;0;ON;<small> 0028;;;;N;SMALL OPENING PARENTHESIS;;;; +FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON;<small> 0029;;;;N;SMALL CLOSING PARENTHESIS;;;; +FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON;<small> 007B;;;;N;SMALL OPENING CURLY BRACKET;;;; +FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON;<small> 007D;;;;N;SMALL CLOSING CURLY BRACKET;;;; +FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<small> 3014;;;;N;SMALL OPENING TORTOISE SHELL BRACKET;;;; +FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<small> 3015;;;;N;SMALL CLOSING TORTOISE SHELL BRACKET;;;; +FE5F;SMALL NUMBER SIGN;Po;0;ET;<small> 0023;;;;N;;;;; +FE60;SMALL AMPERSAND;Po;0;ON;<small> 0026;;;;N;;;;; +FE61;SMALL ASTERISK;Po;0;ON;<small> 002A;;;;N;;;;; +FE62;SMALL PLUS SIGN;Sm;0;ET;<small> 002B;;;;N;;;;; +FE63;SMALL HYPHEN-MINUS;Pd;0;ET;<small> 002D;;;;N;;;;; +FE64;SMALL LESS-THAN SIGN;Sm;0;ON;<small> 003C;;;;N;;;;; +FE65;SMALL GREATER-THAN SIGN;Sm;0;ON;<small> 003E;;;;N;;;;; +FE66;SMALL EQUALS SIGN;Sm;0;ON;<small> 003D;;;;N;;;;; +FE68;SMALL REVERSE SOLIDUS;Po;0;ON;<small> 005C;;;;N;SMALL BACKSLASH;;;; +FE69;SMALL DOLLAR SIGN;Sc;0;ET;<small> 0024;;;;N;;;;; +FE6A;SMALL PERCENT SIGN;Po;0;ET;<small> 0025;;;;N;;;;; +FE6B;SMALL COMMERCIAL AT;Po;0;ON;<small> 0040;;;;N;;;;; +FE70;ARABIC FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064B;;;;N;ARABIC SPACING FATHATAN;;;; +FE71;ARABIC TATWEEL WITH FATHATAN ABOVE;Lo;0;AL;<medial> 0640 064B;;;;N;ARABIC FATHATAN ON TATWEEL;;;; +FE72;ARABIC DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C;;;;N;ARABIC SPACING DAMMATAN;;;; +FE73;ARABIC TAIL FRAGMENT;Lo;0;AL;;;;;N;;;;; +FE74;ARABIC KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D;;;;N;ARABIC SPACING KASRATAN;;;; +FE76;ARABIC FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E;;;;N;ARABIC SPACING FATHAH;;;; +FE77;ARABIC FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E;;;;N;ARABIC FATHAH ON TATWEEL;;;; +FE78;ARABIC DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F;;;;N;ARABIC SPACING DAMMAH;;;; +FE79;ARABIC DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F;;;;N;ARABIC DAMMAH ON TATWEEL;;;; +FE7A;ARABIC KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650;;;;N;ARABIC SPACING KASRAH;;;; +FE7B;ARABIC KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650;;;;N;ARABIC KASRAH ON TATWEEL;;;; +FE7C;ARABIC SHADDA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651;;;;N;ARABIC SPACING SHADDAH;;;; +FE7D;ARABIC SHADDA MEDIAL FORM;Lo;0;AL;<medial> 0640 0651;;;;N;ARABIC SHADDAH ON TATWEEL;;;; +FE7E;ARABIC SUKUN ISOLATED FORM;Lo;0;AL;<isolated> 0020 0652;;;;N;ARABIC SPACING SUKUN;;;; +FE7F;ARABIC SUKUN MEDIAL FORM;Lo;0;AL;<medial> 0640 0652;;;;N;ARABIC SUKUN ON TATWEEL;;;; +FE80;ARABIC LETTER HAMZA ISOLATED FORM;Lo;0;AL;<isolated> 0621;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH;;;; +FE81;ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON ALEF;;;; +FE82;ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON ALEF;;;; +FE83;ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON ALEF;;;; +FE84;ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON ALEF;;;; +FE85;ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0624;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON WAW;;;; +FE86;ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0624;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON WAW;;;; +FE87;ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER ALEF;;;; +FE88;ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER ALEF;;;; +FE89;ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0626;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON YA;;;; +FE8A;ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0626;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON YA;;;; +FE8B;ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM;Lo;0;AL;<initial> 0626;;;;N;GLYPH FOR INITIAL ARABIC HAMZAH ON YA;;;; +FE8C;ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM;Lo;0;AL;<medial> 0626;;;;N;GLYPH FOR MEDIAL ARABIC HAMZAH ON YA;;;; +FE8D;ARABIC LETTER ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0627;;;;N;GLYPH FOR ISOLATE ARABIC ALEF;;;; +FE8E;ARABIC LETTER ALEF FINAL FORM;Lo;0;AL;<final> 0627;;;;N;GLYPH FOR FINAL ARABIC ALEF;;;; +FE8F;ARABIC LETTER BEH ISOLATED FORM;Lo;0;AL;<isolated> 0628;;;;N;GLYPH FOR ISOLATE ARABIC BAA;;;; +FE90;ARABIC LETTER BEH FINAL FORM;Lo;0;AL;<final> 0628;;;;N;GLYPH FOR FINAL ARABIC BAA;;;; +FE91;ARABIC LETTER BEH INITIAL FORM;Lo;0;AL;<initial> 0628;;;;N;GLYPH FOR INITIAL ARABIC BAA;;;; +FE92;ARABIC LETTER BEH MEDIAL FORM;Lo;0;AL;<medial> 0628;;;;N;GLYPH FOR MEDIAL ARABIC BAA;;;; +FE93;ARABIC LETTER TEH MARBUTA ISOLATED FORM;Lo;0;AL;<isolated> 0629;;;;N;GLYPH FOR ISOLATE ARABIC TAA MARBUTAH;;;; +FE94;ARABIC LETTER TEH MARBUTA FINAL FORM;Lo;0;AL;<final> 0629;;;;N;GLYPH FOR FINAL ARABIC TAA MARBUTAH;;;; +FE95;ARABIC LETTER TEH ISOLATED FORM;Lo;0;AL;<isolated> 062A;;;;N;GLYPH FOR ISOLATE ARABIC TAA;;;; +FE96;ARABIC LETTER TEH FINAL FORM;Lo;0;AL;<final> 062A;;;;N;GLYPH FOR FINAL ARABIC TAA;;;; +FE97;ARABIC LETTER TEH INITIAL FORM;Lo;0;AL;<initial> 062A;;;;N;GLYPH FOR INITIAL ARABIC TAA;;;; +FE98;ARABIC LETTER TEH MEDIAL FORM;Lo;0;AL;<medial> 062A;;;;N;GLYPH FOR MEDIAL ARABIC TAA;;;; +FE99;ARABIC LETTER THEH ISOLATED FORM;Lo;0;AL;<isolated> 062B;;;;N;GLYPH FOR ISOLATE ARABIC THAA;;;; +FE9A;ARABIC LETTER THEH FINAL FORM;Lo;0;AL;<final> 062B;;;;N;GLYPH FOR FINAL ARABIC THAA;;;; +FE9B;ARABIC LETTER THEH INITIAL FORM;Lo;0;AL;<initial> 062B;;;;N;GLYPH FOR INITIAL ARABIC THAA;;;; +FE9C;ARABIC LETTER THEH MEDIAL FORM;Lo;0;AL;<medial> 062B;;;;N;GLYPH FOR MEDIAL ARABIC THAA;;;; +FE9D;ARABIC LETTER JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C;;;;N;GLYPH FOR ISOLATE ARABIC JEEM;;;; +FE9E;ARABIC LETTER JEEM FINAL FORM;Lo;0;AL;<final> 062C;;;;N;GLYPH FOR FINAL ARABIC JEEM;;;; +FE9F;ARABIC LETTER JEEM INITIAL FORM;Lo;0;AL;<initial> 062C;;;;N;GLYPH FOR INITIAL ARABIC JEEM;;;; +FEA0;ARABIC LETTER JEEM MEDIAL FORM;Lo;0;AL;<medial> 062C;;;;N;GLYPH FOR MEDIAL ARABIC JEEM;;;; +FEA1;ARABIC LETTER HAH ISOLATED FORM;Lo;0;AL;<isolated> 062D;;;;N;GLYPH FOR ISOLATE ARABIC HAA;;;; +FEA2;ARABIC LETTER HAH FINAL FORM;Lo;0;AL;<final> 062D;;;;N;GLYPH FOR FINAL ARABIC HAA;;;; +FEA3;ARABIC LETTER HAH INITIAL FORM;Lo;0;AL;<initial> 062D;;;;N;GLYPH FOR INITIAL ARABIC HAA;;;; +FEA4;ARABIC LETTER HAH MEDIAL FORM;Lo;0;AL;<medial> 062D;;;;N;GLYPH FOR MEDIAL ARABIC HAA;;;; +FEA5;ARABIC LETTER KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062E;;;;N;GLYPH FOR ISOLATE ARABIC KHAA;;;; +FEA6;ARABIC LETTER KHAH FINAL FORM;Lo;0;AL;<final> 062E;;;;N;GLYPH FOR FINAL ARABIC KHAA;;;; +FEA7;ARABIC LETTER KHAH INITIAL FORM;Lo;0;AL;<initial> 062E;;;;N;GLYPH FOR INITIAL ARABIC KHAA;;;; +FEA8;ARABIC LETTER KHAH MEDIAL FORM;Lo;0;AL;<medial> 062E;;;;N;GLYPH FOR MEDIAL ARABIC KHAA;;;; +FEA9;ARABIC LETTER DAL ISOLATED FORM;Lo;0;AL;<isolated> 062F;;;;N;GLYPH FOR ISOLATE ARABIC DAL;;;; +FEAA;ARABIC LETTER DAL FINAL FORM;Lo;0;AL;<final> 062F;;;;N;GLYPH FOR FINAL ARABIC DAL;;;; +FEAB;ARABIC LETTER THAL ISOLATED FORM;Lo;0;AL;<isolated> 0630;;;;N;GLYPH FOR ISOLATE ARABIC THAL;;;; +FEAC;ARABIC LETTER THAL FINAL FORM;Lo;0;AL;<final> 0630;;;;N;GLYPH FOR FINAL ARABIC THAL;;;; +FEAD;ARABIC LETTER REH ISOLATED FORM;Lo;0;AL;<isolated> 0631;;;;N;GLYPH FOR ISOLATE ARABIC RA;;;; +FEAE;ARABIC LETTER REH FINAL FORM;Lo;0;AL;<final> 0631;;;;N;GLYPH FOR FINAL ARABIC RA;;;; +FEAF;ARABIC LETTER ZAIN ISOLATED FORM;Lo;0;AL;<isolated> 0632;;;;N;GLYPH FOR ISOLATE ARABIC ZAIN;;;; +FEB0;ARABIC LETTER ZAIN FINAL FORM;Lo;0;AL;<final> 0632;;;;N;GLYPH FOR FINAL ARABIC ZAIN;;;; +FEB1;ARABIC LETTER SEEN ISOLATED FORM;Lo;0;AL;<isolated> 0633;;;;N;GLYPH FOR ISOLATE ARABIC SEEN;;;; +FEB2;ARABIC LETTER SEEN FINAL FORM;Lo;0;AL;<final> 0633;;;;N;GLYPH FOR FINAL ARABIC SEEN;;;; +FEB3;ARABIC LETTER SEEN INITIAL FORM;Lo;0;AL;<initial> 0633;;;;N;GLYPH FOR INITIAL ARABIC SEEN;;;; +FEB4;ARABIC LETTER SEEN MEDIAL FORM;Lo;0;AL;<medial> 0633;;;;N;GLYPH FOR MEDIAL ARABIC SEEN;;;; +FEB5;ARABIC LETTER SHEEN ISOLATED FORM;Lo;0;AL;<isolated> 0634;;;;N;GLYPH FOR ISOLATE ARABIC SHEEN;;;; +FEB6;ARABIC LETTER SHEEN FINAL FORM;Lo;0;AL;<final> 0634;;;;N;GLYPH FOR FINAL ARABIC SHEEN;;;; +FEB7;ARABIC LETTER SHEEN INITIAL FORM;Lo;0;AL;<initial> 0634;;;;N;GLYPH FOR INITIAL ARABIC SHEEN;;;; +FEB8;ARABIC LETTER SHEEN MEDIAL FORM;Lo;0;AL;<medial> 0634;;;;N;GLYPH FOR MEDIAL ARABIC SHEEN;;;; +FEB9;ARABIC LETTER SAD ISOLATED FORM;Lo;0;AL;<isolated> 0635;;;;N;GLYPH FOR ISOLATE ARABIC SAD;;;; +FEBA;ARABIC LETTER SAD FINAL FORM;Lo;0;AL;<final> 0635;;;;N;GLYPH FOR FINAL ARABIC SAD;;;; +FEBB;ARABIC LETTER SAD INITIAL FORM;Lo;0;AL;<initial> 0635;;;;N;GLYPH FOR INITIAL ARABIC SAD;;;; +FEBC;ARABIC LETTER SAD MEDIAL FORM;Lo;0;AL;<medial> 0635;;;;N;GLYPH FOR MEDIAL ARABIC SAD;;;; +FEBD;ARABIC LETTER DAD ISOLATED FORM;Lo;0;AL;<isolated> 0636;;;;N;GLYPH FOR ISOLATE ARABIC DAD;;;; +FEBE;ARABIC LETTER DAD FINAL FORM;Lo;0;AL;<final> 0636;;;;N;GLYPH FOR FINAL ARABIC DAD;;;; +FEBF;ARABIC LETTER DAD INITIAL FORM;Lo;0;AL;<initial> 0636;;;;N;GLYPH FOR INITIAL ARABIC DAD;;;; +FEC0;ARABIC LETTER DAD MEDIAL FORM;Lo;0;AL;<medial> 0636;;;;N;GLYPH FOR MEDIAL ARABIC DAD;;;; +FEC1;ARABIC LETTER TAH ISOLATED FORM;Lo;0;AL;<isolated> 0637;;;;N;GLYPH FOR ISOLATE ARABIC TAH;;;; +FEC2;ARABIC LETTER TAH FINAL FORM;Lo;0;AL;<final> 0637;;;;N;GLYPH FOR FINAL ARABIC TAH;;;; +FEC3;ARABIC LETTER TAH INITIAL FORM;Lo;0;AL;<initial> 0637;;;;N;GLYPH FOR INITIAL ARABIC TAH;;;; +FEC4;ARABIC LETTER TAH MEDIAL FORM;Lo;0;AL;<medial> 0637;;;;N;GLYPH FOR MEDIAL ARABIC TAH;;;; +FEC5;ARABIC LETTER ZAH ISOLATED FORM;Lo;0;AL;<isolated> 0638;;;;N;GLYPH FOR ISOLATE ARABIC DHAH;;;; +FEC6;ARABIC LETTER ZAH FINAL FORM;Lo;0;AL;<final> 0638;;;;N;GLYPH FOR FINAL ARABIC DHAH;;;; +FEC7;ARABIC LETTER ZAH INITIAL FORM;Lo;0;AL;<initial> 0638;;;;N;GLYPH FOR INITIAL ARABIC DHAH;;;; +FEC8;ARABIC LETTER ZAH MEDIAL FORM;Lo;0;AL;<medial> 0638;;;;N;GLYPH FOR MEDIAL ARABIC DHAH;;;; +FEC9;ARABIC LETTER AIN ISOLATED FORM;Lo;0;AL;<isolated> 0639;;;;N;GLYPH FOR ISOLATE ARABIC AIN;;;; +FECA;ARABIC LETTER AIN FINAL FORM;Lo;0;AL;<final> 0639;;;;N;GLYPH FOR FINAL ARABIC AIN;;;; +FECB;ARABIC LETTER AIN INITIAL FORM;Lo;0;AL;<initial> 0639;;;;N;GLYPH FOR INITIAL ARABIC AIN;;;; +FECC;ARABIC LETTER AIN MEDIAL FORM;Lo;0;AL;<medial> 0639;;;;N;GLYPH FOR MEDIAL ARABIC AIN;;;; +FECD;ARABIC LETTER GHAIN ISOLATED FORM;Lo;0;AL;<isolated> 063A;;;;N;GLYPH FOR ISOLATE ARABIC GHAIN;;;; +FECE;ARABIC LETTER GHAIN FINAL FORM;Lo;0;AL;<final> 063A;;;;N;GLYPH FOR FINAL ARABIC GHAIN;;;; +FECF;ARABIC LETTER GHAIN INITIAL FORM;Lo;0;AL;<initial> 063A;;;;N;GLYPH FOR INITIAL ARABIC GHAIN;;;; +FED0;ARABIC LETTER GHAIN MEDIAL FORM;Lo;0;AL;<medial> 063A;;;;N;GLYPH FOR MEDIAL ARABIC GHAIN;;;; +FED1;ARABIC LETTER FEH ISOLATED FORM;Lo;0;AL;<isolated> 0641;;;;N;GLYPH FOR ISOLATE ARABIC FA;;;; +FED2;ARABIC LETTER FEH FINAL FORM;Lo;0;AL;<final> 0641;;;;N;GLYPH FOR FINAL ARABIC FA;;;; +FED3;ARABIC LETTER FEH INITIAL FORM;Lo;0;AL;<initial> 0641;;;;N;GLYPH FOR INITIAL ARABIC FA;;;; +FED4;ARABIC LETTER FEH MEDIAL FORM;Lo;0;AL;<medial> 0641;;;;N;GLYPH FOR MEDIAL ARABIC FA;;;; +FED5;ARABIC LETTER QAF ISOLATED FORM;Lo;0;AL;<isolated> 0642;;;;N;GLYPH FOR ISOLATE ARABIC QAF;;;; +FED6;ARABIC LETTER QAF FINAL FORM;Lo;0;AL;<final> 0642;;;;N;GLYPH FOR FINAL ARABIC QAF;;;; +FED7;ARABIC LETTER QAF INITIAL FORM;Lo;0;AL;<initial> 0642;;;;N;GLYPH FOR INITIAL ARABIC QAF;;;; +FED8;ARABIC LETTER QAF MEDIAL FORM;Lo;0;AL;<medial> 0642;;;;N;GLYPH FOR MEDIAL ARABIC QAF;;;; +FED9;ARABIC LETTER KAF ISOLATED FORM;Lo;0;AL;<isolated> 0643;;;;N;GLYPH FOR ISOLATE ARABIC CAF;;;; +FEDA;ARABIC LETTER KAF FINAL FORM;Lo;0;AL;<final> 0643;;;;N;GLYPH FOR FINAL ARABIC CAF;;;; +FEDB;ARABIC LETTER KAF INITIAL FORM;Lo;0;AL;<initial> 0643;;;;N;GLYPH FOR INITIAL ARABIC CAF;;;; +FEDC;ARABIC LETTER KAF MEDIAL FORM;Lo;0;AL;<medial> 0643;;;;N;GLYPH FOR MEDIAL ARABIC CAF;;;; +FEDD;ARABIC LETTER LAM ISOLATED FORM;Lo;0;AL;<isolated> 0644;;;;N;GLYPH FOR ISOLATE ARABIC LAM;;;; +FEDE;ARABIC LETTER LAM FINAL FORM;Lo;0;AL;<final> 0644;;;;N;GLYPH FOR FINAL ARABIC LAM;;;; +FEDF;ARABIC LETTER LAM INITIAL FORM;Lo;0;AL;<initial> 0644;;;;N;GLYPH FOR INITIAL ARABIC LAM;;;; +FEE0;ARABIC LETTER LAM MEDIAL FORM;Lo;0;AL;<medial> 0644;;;;N;GLYPH FOR MEDIAL ARABIC LAM;;;; +FEE1;ARABIC LETTER MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645;;;;N;GLYPH FOR ISOLATE ARABIC MEEM;;;; +FEE2;ARABIC LETTER MEEM FINAL FORM;Lo;0;AL;<final> 0645;;;;N;GLYPH FOR FINAL ARABIC MEEM;;;; +FEE3;ARABIC LETTER MEEM INITIAL FORM;Lo;0;AL;<initial> 0645;;;;N;GLYPH FOR INITIAL ARABIC MEEM;;;; +FEE4;ARABIC LETTER MEEM MEDIAL FORM;Lo;0;AL;<medial> 0645;;;;N;GLYPH FOR MEDIAL ARABIC MEEM;;;; +FEE5;ARABIC LETTER NOON ISOLATED FORM;Lo;0;AL;<isolated> 0646;;;;N;GLYPH FOR ISOLATE ARABIC NOON;;;; +FEE6;ARABIC LETTER NOON FINAL FORM;Lo;0;AL;<final> 0646;;;;N;GLYPH FOR FINAL ARABIC NOON;;;; +FEE7;ARABIC LETTER NOON INITIAL FORM;Lo;0;AL;<initial> 0646;;;;N;GLYPH FOR INITIAL ARABIC NOON;;;; +FEE8;ARABIC LETTER NOON MEDIAL FORM;Lo;0;AL;<medial> 0646;;;;N;GLYPH FOR MEDIAL ARABIC NOON;;;; +FEE9;ARABIC LETTER HEH ISOLATED FORM;Lo;0;AL;<isolated> 0647;;;;N;GLYPH FOR ISOLATE ARABIC HA;;;; +FEEA;ARABIC LETTER HEH FINAL FORM;Lo;0;AL;<final> 0647;;;;N;GLYPH FOR FINAL ARABIC HA;;;; +FEEB;ARABIC LETTER HEH INITIAL FORM;Lo;0;AL;<initial> 0647;;;;N;GLYPH FOR INITIAL ARABIC HA;;;; +FEEC;ARABIC LETTER HEH MEDIAL FORM;Lo;0;AL;<medial> 0647;;;;N;GLYPH FOR MEDIAL ARABIC HA;;;; +FEED;ARABIC LETTER WAW ISOLATED FORM;Lo;0;AL;<isolated> 0648;;;;N;GLYPH FOR ISOLATE ARABIC WAW;;;; +FEEE;ARABIC LETTER WAW FINAL FORM;Lo;0;AL;<final> 0648;;;;N;GLYPH FOR FINAL ARABIC WAW;;;; +FEEF;ARABIC LETTER ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0649;;;;N;GLYPH FOR ISOLATE ARABIC ALEF MAQSURAH;;;; +FEF0;ARABIC LETTER ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0649;;;;N;GLYPH FOR FINAL ARABIC ALEF MAQSURAH;;;; +FEF1;ARABIC LETTER YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A;;;;N;GLYPH FOR ISOLATE ARABIC YA;;;; +FEF2;ARABIC LETTER YEH FINAL FORM;Lo;0;AL;<final> 064A;;;;N;GLYPH FOR FINAL ARABIC YA;;;; +FEF3;ARABIC LETTER YEH INITIAL FORM;Lo;0;AL;<initial> 064A;;;;N;GLYPH FOR INITIAL ARABIC YA;;;; +FEF4;ARABIC LETTER YEH MEDIAL FORM;Lo;0;AL;<medial> 064A;;;;N;GLYPH FOR MEDIAL ARABIC YA;;;; +FEF5;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON LIGATURE LAM ALEF;;;; +FEF6;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON LIGATURE LAM ALEF;;;; +FEF7;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON LIGATURE LAM ALEF;;;; +FEF8;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON LIGATURE LAM ALEF;;;; +FEF9;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0644 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;; +FEFA;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0644 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;; +FEFB;ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0644 0627;;;;N;GLYPH FOR ISOLATE ARABIC LIGATURE LAM ALEF;;;; +FEFC;ARABIC LIGATURE LAM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0644 0627;;;;N;GLYPH FOR FINAL ARABIC LIGATURE LAM ALEF;;;; +FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; +FF01;FULLWIDTH EXCLAMATION MARK;Po;0;ON;<wide> 0021;;;;N;;;;; +FF02;FULLWIDTH QUOTATION MARK;Po;0;ON;<wide> 0022;;;;N;;;;; +FF03;FULLWIDTH NUMBER SIGN;Po;0;ET;<wide> 0023;;;;N;;;;; +FF04;FULLWIDTH DOLLAR SIGN;Sc;0;ET;<wide> 0024;;;;N;;;;; +FF05;FULLWIDTH PERCENT SIGN;Po;0;ET;<wide> 0025;;;;N;;;;; +FF06;FULLWIDTH AMPERSAND;Po;0;ON;<wide> 0026;;;;N;;;;; +FF07;FULLWIDTH APOSTROPHE;Po;0;ON;<wide> 0027;;;;N;;;;; +FF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON;<wide> 0028;;;;Y;FULLWIDTH OPENING PARENTHESIS;;;; +FF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON;<wide> 0029;;;;Y;FULLWIDTH CLOSING PARENTHESIS;;;; +FF0A;FULLWIDTH ASTERISK;Po;0;ON;<wide> 002A;;;;N;;;;; +FF0B;FULLWIDTH PLUS SIGN;Sm;0;ET;<wide> 002B;;;;N;;;;; +FF0C;FULLWIDTH COMMA;Po;0;CS;<wide> 002C;;;;N;;;;; +FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ET;<wide> 002D;;;;N;;;;; +FF0E;FULLWIDTH FULL STOP;Po;0;CS;<wide> 002E;;;;N;FULLWIDTH PERIOD;;;; +FF0F;FULLWIDTH SOLIDUS;Po;0;ES;<wide> 002F;;;;N;FULLWIDTH SLASH;;;; +FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN;<wide> 0030;0;0;0;N;;;;; +FF11;FULLWIDTH DIGIT ONE;Nd;0;EN;<wide> 0031;1;1;1;N;;;;; +FF12;FULLWIDTH DIGIT TWO;Nd;0;EN;<wide> 0032;2;2;2;N;;;;; +FF13;FULLWIDTH DIGIT THREE;Nd;0;EN;<wide> 0033;3;3;3;N;;;;; +FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN;<wide> 0034;4;4;4;N;;;;; +FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN;<wide> 0035;5;5;5;N;;;;; +FF16;FULLWIDTH DIGIT SIX;Nd;0;EN;<wide> 0036;6;6;6;N;;;;; +FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN;<wide> 0037;7;7;7;N;;;;; +FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN;<wide> 0038;8;8;8;N;;;;; +FF19;FULLWIDTH DIGIT NINE;Nd;0;EN;<wide> 0039;9;9;9;N;;;;; +FF1A;FULLWIDTH COLON;Po;0;CS;<wide> 003A;;;;N;;;;; +FF1B;FULLWIDTH SEMICOLON;Po;0;ON;<wide> 003B;;;;N;;;;; +FF1C;FULLWIDTH LESS-THAN SIGN;Sm;0;ON;<wide> 003C;;;;Y;;;;; +FF1D;FULLWIDTH EQUALS SIGN;Sm;0;ON;<wide> 003D;;;;N;;;;; +FF1E;FULLWIDTH GREATER-THAN SIGN;Sm;0;ON;<wide> 003E;;;;Y;;;;; +FF1F;FULLWIDTH QUESTION MARK;Po;0;ON;<wide> 003F;;;;N;;;;; +FF20;FULLWIDTH COMMERCIAL AT;Po;0;ON;<wide> 0040;;;;N;;;;; +FF21;FULLWIDTH LATIN CAPITAL LETTER A;Lu;0;L;<wide> 0041;;;;N;;;;FF41; +FF22;FULLWIDTH LATIN CAPITAL LETTER B;Lu;0;L;<wide> 0042;;;;N;;;;FF42; +FF23;FULLWIDTH LATIN CAPITAL LETTER C;Lu;0;L;<wide> 0043;;;;N;;;;FF43; +FF24;FULLWIDTH LATIN CAPITAL LETTER D;Lu;0;L;<wide> 0044;;;;N;;;;FF44; +FF25;FULLWIDTH LATIN CAPITAL LETTER E;Lu;0;L;<wide> 0045;;;;N;;;;FF45; +FF26;FULLWIDTH LATIN CAPITAL LETTER F;Lu;0;L;<wide> 0046;;;;N;;;;FF46; +FF27;FULLWIDTH LATIN CAPITAL LETTER G;Lu;0;L;<wide> 0047;;;;N;;;;FF47; +FF28;FULLWIDTH LATIN CAPITAL LETTER H;Lu;0;L;<wide> 0048;;;;N;;;;FF48; +FF29;FULLWIDTH LATIN CAPITAL LETTER I;Lu;0;L;<wide> 0049;;;;N;;;;FF49; +FF2A;FULLWIDTH LATIN CAPITAL LETTER J;Lu;0;L;<wide> 004A;;;;N;;;;FF4A; +FF2B;FULLWIDTH LATIN CAPITAL LETTER K;Lu;0;L;<wide> 004B;;;;N;;;;FF4B; +FF2C;FULLWIDTH LATIN CAPITAL LETTER L;Lu;0;L;<wide> 004C;;;;N;;;;FF4C; +FF2D;FULLWIDTH LATIN CAPITAL LETTER M;Lu;0;L;<wide> 004D;;;;N;;;;FF4D; +FF2E;FULLWIDTH LATIN CAPITAL LETTER N;Lu;0;L;<wide> 004E;;;;N;;;;FF4E; +FF2F;FULLWIDTH LATIN CAPITAL LETTER O;Lu;0;L;<wide> 004F;;;;N;;;;FF4F; +FF30;FULLWIDTH LATIN CAPITAL LETTER P;Lu;0;L;<wide> 0050;;;;N;;;;FF50; +FF31;FULLWIDTH LATIN CAPITAL LETTER Q;Lu;0;L;<wide> 0051;;;;N;;;;FF51; +FF32;FULLWIDTH LATIN CAPITAL LETTER R;Lu;0;L;<wide> 0052;;;;N;;;;FF52; +FF33;FULLWIDTH LATIN CAPITAL LETTER S;Lu;0;L;<wide> 0053;;;;N;;;;FF53; +FF34;FULLWIDTH LATIN CAPITAL LETTER T;Lu;0;L;<wide> 0054;;;;N;;;;FF54; +FF35;FULLWIDTH LATIN CAPITAL LETTER U;Lu;0;L;<wide> 0055;;;;N;;;;FF55; +FF36;FULLWIDTH LATIN CAPITAL LETTER V;Lu;0;L;<wide> 0056;;;;N;;;;FF56; +FF37;FULLWIDTH LATIN CAPITAL LETTER W;Lu;0;L;<wide> 0057;;;;N;;;;FF57; +FF38;FULLWIDTH LATIN CAPITAL LETTER X;Lu;0;L;<wide> 0058;;;;N;;;;FF58; +FF39;FULLWIDTH LATIN CAPITAL LETTER Y;Lu;0;L;<wide> 0059;;;;N;;;;FF59; +FF3A;FULLWIDTH LATIN CAPITAL LETTER Z;Lu;0;L;<wide> 005A;;;;N;;;;FF5A; +FF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps;0;ON;<wide> 005B;;;;Y;FULLWIDTH OPENING SQUARE BRACKET;;;; +FF3C;FULLWIDTH REVERSE SOLIDUS;Po;0;ON;<wide> 005C;;;;N;FULLWIDTH BACKSLASH;;;; +FF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe;0;ON;<wide> 005D;;;;Y;FULLWIDTH CLOSING SQUARE BRACKET;;;; +FF3E;FULLWIDTH CIRCUMFLEX ACCENT;Sk;0;ON;<wide> 005E;;;;N;FULLWIDTH SPACING CIRCUMFLEX;;;; +FF3F;FULLWIDTH LOW LINE;Pc;0;ON;<wide> 005F;;;;N;FULLWIDTH SPACING UNDERSCORE;;;; +FF40;FULLWIDTH GRAVE ACCENT;Sk;0;ON;<wide> 0060;;;;N;FULLWIDTH SPACING GRAVE;;;; +FF41;FULLWIDTH LATIN SMALL LETTER A;Ll;0;L;<wide> 0061;;;;N;;;FF21;;FF21 +FF42;FULLWIDTH LATIN SMALL LETTER B;Ll;0;L;<wide> 0062;;;;N;;;FF22;;FF22 +FF43;FULLWIDTH LATIN SMALL LETTER C;Ll;0;L;<wide> 0063;;;;N;;;FF23;;FF23 +FF44;FULLWIDTH LATIN SMALL LETTER D;Ll;0;L;<wide> 0064;;;;N;;;FF24;;FF24 +FF45;FULLWIDTH LATIN SMALL LETTER E;Ll;0;L;<wide> 0065;;;;N;;;FF25;;FF25 +FF46;FULLWIDTH LATIN SMALL LETTER F;Ll;0;L;<wide> 0066;;;;N;;;FF26;;FF26 +FF47;FULLWIDTH LATIN SMALL LETTER G;Ll;0;L;<wide> 0067;;;;N;;;FF27;;FF27 +FF48;FULLWIDTH LATIN SMALL LETTER H;Ll;0;L;<wide> 0068;;;;N;;;FF28;;FF28 +FF49;FULLWIDTH LATIN SMALL LETTER I;Ll;0;L;<wide> 0069;;;;N;;;FF29;;FF29 +FF4A;FULLWIDTH LATIN SMALL LETTER J;Ll;0;L;<wide> 006A;;;;N;;;FF2A;;FF2A +FF4B;FULLWIDTH LATIN SMALL LETTER K;Ll;0;L;<wide> 006B;;;;N;;;FF2B;;FF2B +FF4C;FULLWIDTH LATIN SMALL LETTER L;Ll;0;L;<wide> 006C;;;;N;;;FF2C;;FF2C +FF4D;FULLWIDTH LATIN SMALL LETTER M;Ll;0;L;<wide> 006D;;;;N;;;FF2D;;FF2D +FF4E;FULLWIDTH LATIN SMALL LETTER N;Ll;0;L;<wide> 006E;;;;N;;;FF2E;;FF2E +FF4F;FULLWIDTH LATIN SMALL LETTER O;Ll;0;L;<wide> 006F;;;;N;;;FF2F;;FF2F +FF50;FULLWIDTH LATIN SMALL LETTER P;Ll;0;L;<wide> 0070;;;;N;;;FF30;;FF30 +FF51;FULLWIDTH LATIN SMALL LETTER Q;Ll;0;L;<wide> 0071;;;;N;;;FF31;;FF31 +FF52;FULLWIDTH LATIN SMALL LETTER R;Ll;0;L;<wide> 0072;;;;N;;;FF32;;FF32 +FF53;FULLWIDTH LATIN SMALL LETTER S;Ll;0;L;<wide> 0073;;;;N;;;FF33;;FF33 +FF54;FULLWIDTH LATIN SMALL LETTER T;Ll;0;L;<wide> 0074;;;;N;;;FF34;;FF34 +FF55;FULLWIDTH LATIN SMALL LETTER U;Ll;0;L;<wide> 0075;;;;N;;;FF35;;FF35 +FF56;FULLWIDTH LATIN SMALL LETTER V;Ll;0;L;<wide> 0076;;;;N;;;FF36;;FF36 +FF57;FULLWIDTH LATIN SMALL LETTER W;Ll;0;L;<wide> 0077;;;;N;;;FF37;;FF37 +FF58;FULLWIDTH LATIN SMALL LETTER X;Ll;0;L;<wide> 0078;;;;N;;;FF38;;FF38 +FF59;FULLWIDTH LATIN SMALL LETTER Y;Ll;0;L;<wide> 0079;;;;N;;;FF39;;FF39 +FF5A;FULLWIDTH LATIN SMALL LETTER Z;Ll;0;L;<wide> 007A;;;;N;;;FF3A;;FF3A +FF5B;FULLWIDTH LEFT CURLY BRACKET;Ps;0;ON;<wide> 007B;;;;Y;FULLWIDTH OPENING CURLY BRACKET;;;; +FF5C;FULLWIDTH VERTICAL LINE;Sm;0;ON;<wide> 007C;;;;N;FULLWIDTH VERTICAL BAR;;;; +FF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe;0;ON;<wide> 007D;;;;Y;FULLWIDTH CLOSING CURLY BRACKET;;;; +FF5E;FULLWIDTH TILDE;Sm;0;ON;<wide> 007E;;;;N;FULLWIDTH SPACING TILDE;;;; +FF5F;FULLWIDTH LEFT WHITE PARENTHESIS;Ps;0;ON;<wide> 2985;;;;Y;;*;;; +FF60;FULLWIDTH RIGHT WHITE PARENTHESIS;Pe;0;ON;<wide> 2986;;;;Y;;*;;; +FF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON;<narrow> 3002;;;;N;HALFWIDTH IDEOGRAPHIC PERIOD;;;; +FF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON;<narrow> 300C;;;;Y;HALFWIDTH OPENING CORNER BRACKET;;;; +FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON;<narrow> 300D;;;;Y;HALFWIDTH CLOSING CORNER BRACKET;;;; +FF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON;<narrow> 3001;;;;N;;;;; +FF65;HALFWIDTH KATAKANA MIDDLE DOT;Pc;0;ON;<narrow> 30FB;;;;N;;;;; +FF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L;<narrow> 30F2;;;;N;;;;; +FF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L;<narrow> 30A1;;;;N;;;;; +FF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L;<narrow> 30A3;;;;N;;;;; +FF69;HALFWIDTH KATAKANA LETTER SMALL U;Lo;0;L;<narrow> 30A5;;;;N;;;;; +FF6A;HALFWIDTH KATAKANA LETTER SMALL E;Lo;0;L;<narrow> 30A7;;;;N;;;;; +FF6B;HALFWIDTH KATAKANA LETTER SMALL O;Lo;0;L;<narrow> 30A9;;;;N;;;;; +FF6C;HALFWIDTH KATAKANA LETTER SMALL YA;Lo;0;L;<narrow> 30E3;;;;N;;;;; +FF6D;HALFWIDTH KATAKANA LETTER SMALL YU;Lo;0;L;<narrow> 30E5;;;;N;;;;; +FF6E;HALFWIDTH KATAKANA LETTER SMALL YO;Lo;0;L;<narrow> 30E7;;;;N;;;;; +FF6F;HALFWIDTH KATAKANA LETTER SMALL TU;Lo;0;L;<narrow> 30C3;;;;N;;;;; +FF70;HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;<narrow> 30FC;;;;N;;;;; +FF71;HALFWIDTH KATAKANA LETTER A;Lo;0;L;<narrow> 30A2;;;;N;;;;; +FF72;HALFWIDTH KATAKANA LETTER I;Lo;0;L;<narrow> 30A4;;;;N;;;;; +FF73;HALFWIDTH KATAKANA LETTER U;Lo;0;L;<narrow> 30A6;;;;N;;;;; +FF74;HALFWIDTH KATAKANA LETTER E;Lo;0;L;<narrow> 30A8;;;;N;;;;; +FF75;HALFWIDTH KATAKANA LETTER O;Lo;0;L;<narrow> 30AA;;;;N;;;;; +FF76;HALFWIDTH KATAKANA LETTER KA;Lo;0;L;<narrow> 30AB;;;;N;;;;; +FF77;HALFWIDTH KATAKANA LETTER KI;Lo;0;L;<narrow> 30AD;;;;N;;;;; +FF78;HALFWIDTH KATAKANA LETTER KU;Lo;0;L;<narrow> 30AF;;;;N;;;;; +FF79;HALFWIDTH KATAKANA LETTER KE;Lo;0;L;<narrow> 30B1;;;;N;;;;; +FF7A;HALFWIDTH KATAKANA LETTER KO;Lo;0;L;<narrow> 30B3;;;;N;;;;; +FF7B;HALFWIDTH KATAKANA LETTER SA;Lo;0;L;<narrow> 30B5;;;;N;;;;; +FF7C;HALFWIDTH KATAKANA LETTER SI;Lo;0;L;<narrow> 30B7;;;;N;;;;; +FF7D;HALFWIDTH KATAKANA LETTER SU;Lo;0;L;<narrow> 30B9;;;;N;;;;; +FF7E;HALFWIDTH KATAKANA LETTER SE;Lo;0;L;<narrow> 30BB;;;;N;;;;; +FF7F;HALFWIDTH KATAKANA LETTER SO;Lo;0;L;<narrow> 30BD;;;;N;;;;; +FF80;HALFWIDTH KATAKANA LETTER TA;Lo;0;L;<narrow> 30BF;;;;N;;;;; +FF81;HALFWIDTH KATAKANA LETTER TI;Lo;0;L;<narrow> 30C1;;;;N;;;;; +FF82;HALFWIDTH KATAKANA LETTER TU;Lo;0;L;<narrow> 30C4;;;;N;;;;; +FF83;HALFWIDTH KATAKANA LETTER TE;Lo;0;L;<narrow> 30C6;;;;N;;;;; +FF84;HALFWIDTH KATAKANA LETTER TO;Lo;0;L;<narrow> 30C8;;;;N;;;;; +FF85;HALFWIDTH KATAKANA LETTER NA;Lo;0;L;<narrow> 30CA;;;;N;;;;; +FF86;HALFWIDTH KATAKANA LETTER NI;Lo;0;L;<narrow> 30CB;;;;N;;;;; +FF87;HALFWIDTH KATAKANA LETTER NU;Lo;0;L;<narrow> 30CC;;;;N;;;;; +FF88;HALFWIDTH KATAKANA LETTER NE;Lo;0;L;<narrow> 30CD;;;;N;;;;; +FF89;HALFWIDTH KATAKANA LETTER NO;Lo;0;L;<narrow> 30CE;;;;N;;;;; +FF8A;HALFWIDTH KATAKANA LETTER HA;Lo;0;L;<narrow> 30CF;;;;N;;;;; +FF8B;HALFWIDTH KATAKANA LETTER HI;Lo;0;L;<narrow> 30D2;;;;N;;;;; +FF8C;HALFWIDTH KATAKANA LETTER HU;Lo;0;L;<narrow> 30D5;;;;N;;;;; +FF8D;HALFWIDTH KATAKANA LETTER HE;Lo;0;L;<narrow> 30D8;;;;N;;;;; +FF8E;HALFWIDTH KATAKANA LETTER HO;Lo;0;L;<narrow> 30DB;;;;N;;;;; +FF8F;HALFWIDTH KATAKANA LETTER MA;Lo;0;L;<narrow> 30DE;;;;N;;;;; +FF90;HALFWIDTH KATAKANA LETTER MI;Lo;0;L;<narrow> 30DF;;;;N;;;;; +FF91;HALFWIDTH KATAKANA LETTER MU;Lo;0;L;<narrow> 30E0;;;;N;;;;; +FF92;HALFWIDTH KATAKANA LETTER ME;Lo;0;L;<narrow> 30E1;;;;N;;;;; +FF93;HALFWIDTH KATAKANA LETTER MO;Lo;0;L;<narrow> 30E2;;;;N;;;;; +FF94;HALFWIDTH KATAKANA LETTER YA;Lo;0;L;<narrow> 30E4;;;;N;;;;; +FF95;HALFWIDTH KATAKANA LETTER YU;Lo;0;L;<narrow> 30E6;;;;N;;;;; +FF96;HALFWIDTH KATAKANA LETTER YO;Lo;0;L;<narrow> 30E8;;;;N;;;;; +FF97;HALFWIDTH KATAKANA LETTER RA;Lo;0;L;<narrow> 30E9;;;;N;;;;; +FF98;HALFWIDTH KATAKANA LETTER RI;Lo;0;L;<narrow> 30EA;;;;N;;;;; +FF99;HALFWIDTH KATAKANA LETTER RU;Lo;0;L;<narrow> 30EB;;;;N;;;;; +FF9A;HALFWIDTH KATAKANA LETTER RE;Lo;0;L;<narrow> 30EC;;;;N;;;;; +FF9B;HALFWIDTH KATAKANA LETTER RO;Lo;0;L;<narrow> 30ED;;;;N;;;;; +FF9C;HALFWIDTH KATAKANA LETTER WA;Lo;0;L;<narrow> 30EF;;;;N;;;;; +FF9D;HALFWIDTH KATAKANA LETTER N;Lo;0;L;<narrow> 30F3;;;;N;;;;; +FF9E;HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L;<narrow> 3099;;;;N;;halfwidth katakana-hiragana voiced sound mark;;; +FF9F;HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L;<narrow> 309A;;;;N;;halfwidth katakana-hiragana semi-voiced sound mark;;; +FFA0;HALFWIDTH HANGUL FILLER;Lo;0;L;<narrow> 3164;;;;N;HALFWIDTH HANGUL CAE OM;;;; +FFA1;HALFWIDTH HANGUL LETTER KIYEOK;Lo;0;L;<narrow> 3131;;;;N;HALFWIDTH HANGUL LETTER GIYEOG;;;; +FFA2;HALFWIDTH HANGUL LETTER SSANGKIYEOK;Lo;0;L;<narrow> 3132;;;;N;HALFWIDTH HANGUL LETTER SSANG GIYEOG;;;; +FFA3;HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<narrow> 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;; +FFA4;HALFWIDTH HANGUL LETTER NIEUN;Lo;0;L;<narrow> 3134;;;;N;;;;; +FFA5;HALFWIDTH HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<narrow> 3135;;;;N;HALFWIDTH HANGUL LETTER NIEUN JIEUJ;;;; +FFA6;HALFWIDTH HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<narrow> 3136;;;;N;HALFWIDTH HANGUL LETTER NIEUN HIEUH;;;; +FFA7;HALFWIDTH HANGUL LETTER TIKEUT;Lo;0;L;<narrow> 3137;;;;N;HALFWIDTH HANGUL LETTER DIGEUD;;;; +FFA8;HALFWIDTH HANGUL LETTER SSANGTIKEUT;Lo;0;L;<narrow> 3138;;;;N;HALFWIDTH HANGUL LETTER SSANG DIGEUD;;;; +FFA9;HALFWIDTH HANGUL LETTER RIEUL;Lo;0;L;<narrow> 3139;;;;N;HALFWIDTH HANGUL LETTER LIEUL;;;; +FFAA;HALFWIDTH HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<narrow> 313A;;;;N;HALFWIDTH HANGUL LETTER LIEUL GIYEOG;;;; +FFAB;HALFWIDTH HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<narrow> 313B;;;;N;HALFWIDTH HANGUL LETTER LIEUL MIEUM;;;; +FFAC;HALFWIDTH HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<narrow> 313C;;;;N;HALFWIDTH HANGUL LETTER LIEUL BIEUB;;;; +FFAD;HALFWIDTH HANGUL LETTER RIEUL-SIOS;Lo;0;L;<narrow> 313D;;;;N;HALFWIDTH HANGUL LETTER LIEUL SIOS;;;; +FFAE;HALFWIDTH HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<narrow> 313E;;;;N;HALFWIDTH HANGUL LETTER LIEUL TIEUT;;;; +FFAF;HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<narrow> 313F;;;;N;HALFWIDTH HANGUL LETTER LIEUL PIEUP;;;; +FFB0;HALFWIDTH HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<narrow> 3140;;;;N;HALFWIDTH HANGUL LETTER LIEUL HIEUH;;;; +FFB1;HALFWIDTH HANGUL LETTER MIEUM;Lo;0;L;<narrow> 3141;;;;N;;;;; +FFB2;HALFWIDTH HANGUL LETTER PIEUP;Lo;0;L;<narrow> 3142;;;;N;HALFWIDTH HANGUL LETTER BIEUB;;;; +FFB3;HALFWIDTH HANGUL LETTER SSANGPIEUP;Lo;0;L;<narrow> 3143;;;;N;HALFWIDTH HANGUL LETTER SSANG BIEUB;;;; +FFB4;HALFWIDTH HANGUL LETTER PIEUP-SIOS;Lo;0;L;<narrow> 3144;;;;N;HALFWIDTH HANGUL LETTER BIEUB SIOS;;;; +FFB5;HALFWIDTH HANGUL LETTER SIOS;Lo;0;L;<narrow> 3145;;;;N;;;;; +FFB6;HALFWIDTH HANGUL LETTER SSANGSIOS;Lo;0;L;<narrow> 3146;;;;N;HALFWIDTH HANGUL LETTER SSANG SIOS;;;; +FFB7;HALFWIDTH HANGUL LETTER IEUNG;Lo;0;L;<narrow> 3147;;;;N;;;;; +FFB8;HALFWIDTH HANGUL LETTER CIEUC;Lo;0;L;<narrow> 3148;;;;N;HALFWIDTH HANGUL LETTER JIEUJ;;;; +FFB9;HALFWIDTH HANGUL LETTER SSANGCIEUC;Lo;0;L;<narrow> 3149;;;;N;HALFWIDTH HANGUL LETTER SSANG JIEUJ;;;; +FFBA;HALFWIDTH HANGUL LETTER CHIEUCH;Lo;0;L;<narrow> 314A;;;;N;HALFWIDTH HANGUL LETTER CIEUC;;;; +FFBB;HALFWIDTH HANGUL LETTER KHIEUKH;Lo;0;L;<narrow> 314B;;;;N;HALFWIDTH HANGUL LETTER KIYEOK;;;; +FFBC;HALFWIDTH HANGUL LETTER THIEUTH;Lo;0;L;<narrow> 314C;;;;N;HALFWIDTH HANGUL LETTER TIEUT;;;; +FFBD;HALFWIDTH HANGUL LETTER PHIEUPH;Lo;0;L;<narrow> 314D;;;;N;HALFWIDTH HANGUL LETTER PIEUP;;;; +FFBE;HALFWIDTH HANGUL LETTER HIEUH;Lo;0;L;<narrow> 314E;;;;N;;;;; +FFC2;HALFWIDTH HANGUL LETTER A;Lo;0;L;<narrow> 314F;;;;N;;;;; +FFC3;HALFWIDTH HANGUL LETTER AE;Lo;0;L;<narrow> 3150;;;;N;;;;; +FFC4;HALFWIDTH HANGUL LETTER YA;Lo;0;L;<narrow> 3151;;;;N;;;;; +FFC5;HALFWIDTH HANGUL LETTER YAE;Lo;0;L;<narrow> 3152;;;;N;;;;; +FFC6;HALFWIDTH HANGUL LETTER EO;Lo;0;L;<narrow> 3153;;;;N;;;;; +FFC7;HALFWIDTH HANGUL LETTER E;Lo;0;L;<narrow> 3154;;;;N;;;;; +FFCA;HALFWIDTH HANGUL LETTER YEO;Lo;0;L;<narrow> 3155;;;;N;;;;; +FFCB;HALFWIDTH HANGUL LETTER YE;Lo;0;L;<narrow> 3156;;;;N;;;;; +FFCC;HALFWIDTH HANGUL LETTER O;Lo;0;L;<narrow> 3157;;;;N;;;;; +FFCD;HALFWIDTH HANGUL LETTER WA;Lo;0;L;<narrow> 3158;;;;N;;;;; +FFCE;HALFWIDTH HANGUL LETTER WAE;Lo;0;L;<narrow> 3159;;;;N;;;;; +FFCF;HALFWIDTH HANGUL LETTER OE;Lo;0;L;<narrow> 315A;;;;N;;;;; +FFD2;HALFWIDTH HANGUL LETTER YO;Lo;0;L;<narrow> 315B;;;;N;;;;; +FFD3;HALFWIDTH HANGUL LETTER U;Lo;0;L;<narrow> 315C;;;;N;;;;; +FFD4;HALFWIDTH HANGUL LETTER WEO;Lo;0;L;<narrow> 315D;;;;N;;;;; +FFD5;HALFWIDTH HANGUL LETTER WE;Lo;0;L;<narrow> 315E;;;;N;;;;; +FFD6;HALFWIDTH HANGUL LETTER WI;Lo;0;L;<narrow> 315F;;;;N;;;;; +FFD7;HALFWIDTH HANGUL LETTER YU;Lo;0;L;<narrow> 3160;;;;N;;;;; +FFDA;HALFWIDTH HANGUL LETTER EU;Lo;0;L;<narrow> 3161;;;;N;;;;; +FFDB;HALFWIDTH HANGUL LETTER YI;Lo;0;L;<narrow> 3162;;;;N;;;;; +FFDC;HALFWIDTH HANGUL LETTER I;Lo;0;L;<narrow> 3163;;;;N;;;;; +FFE0;FULLWIDTH CENT SIGN;Sc;0;ET;<wide> 00A2;;;;N;;;;; +FFE1;FULLWIDTH POUND SIGN;Sc;0;ET;<wide> 00A3;;;;N;;;;; +FFE2;FULLWIDTH NOT SIGN;Sm;0;ON;<wide> 00AC;;;;N;;;;; +FFE3;FULLWIDTH MACRON;Sk;0;ON;<wide> 00AF;;;;N;FULLWIDTH SPACING MACRON;*;;; +FFE4;FULLWIDTH BROKEN BAR;So;0;ON;<wide> 00A6;;;;N;FULLWIDTH BROKEN VERTICAL BAR;;;; +FFE5;FULLWIDTH YEN SIGN;Sc;0;ET;<wide> 00A5;;;;N;;;;; +FFE6;FULLWIDTH WON SIGN;Sc;0;ET;<wide> 20A9;;;;N;;;;; +FFE8;HALFWIDTH FORMS LIGHT VERTICAL;So;0;ON;<narrow> 2502;;;;N;;;;; +FFE9;HALFWIDTH LEFTWARDS ARROW;Sm;0;ON;<narrow> 2190;;;;N;;;;; +FFEA;HALFWIDTH UPWARDS ARROW;Sm;0;ON;<narrow> 2191;;;;N;;;;; +FFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON;<narrow> 2192;;;;N;;;;; +FFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON;<narrow> 2193;;;;N;;;;; +FFED;HALFWIDTH BLACK SQUARE;So;0;ON;<narrow> 25A0;;;;N;;;;; +FFEE;HALFWIDTH WHITE CIRCLE;So;0;ON;<narrow> 25CB;;;;N;;;;; +FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;BN;;;;;N;;;;; +FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;BN;;;;;N;;;;; +FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;BN;;;;;N;;;;; +FFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; +FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; +10000;LINEAR B SYLLABLE B008 A;Lo;0;L;;;;;N;;;;; +10001;LINEAR B SYLLABLE B038 E;Lo;0;L;;;;;N;;;;; +10002;LINEAR B SYLLABLE B028 I;Lo;0;L;;;;;N;;;;; +10003;LINEAR B SYLLABLE B061 O;Lo;0;L;;;;;N;;;;; +10004;LINEAR B SYLLABLE B010 U;Lo;0;L;;;;;N;;;;; +10005;LINEAR B SYLLABLE B001 DA;Lo;0;L;;;;;N;;;;; +10006;LINEAR B SYLLABLE B045 DE;Lo;0;L;;;;;N;;;;; +10007;LINEAR B SYLLABLE B007 DI;Lo;0;L;;;;;N;;;;; +10008;LINEAR B SYLLABLE B014 DO;Lo;0;L;;;;;N;;;;; +10009;LINEAR B SYLLABLE B051 DU;Lo;0;L;;;;;N;;;;; +1000A;LINEAR B SYLLABLE B057 JA;Lo;0;L;;;;;N;;;;; +1000B;LINEAR B SYLLABLE B046 JE;Lo;0;L;;;;;N;;;;; +1000D;LINEAR B SYLLABLE B036 JO;Lo;0;L;;;;;N;;;;; +1000E;LINEAR B SYLLABLE B065 JU;Lo;0;L;;;;;N;;;;; +1000F;LINEAR B SYLLABLE B077 KA;Lo;0;L;;;;;N;;;;; +10010;LINEAR B SYLLABLE B044 KE;Lo;0;L;;;;;N;;;;; +10011;LINEAR B SYLLABLE B067 KI;Lo;0;L;;;;;N;;;;; +10012;LINEAR B SYLLABLE B070 KO;Lo;0;L;;;;;N;;;;; +10013;LINEAR B SYLLABLE B081 KU;Lo;0;L;;;;;N;;;;; +10014;LINEAR B SYLLABLE B080 MA;Lo;0;L;;;;;N;;;;; +10015;LINEAR B SYLLABLE B013 ME;Lo;0;L;;;;;N;;;;; +10016;LINEAR B SYLLABLE B073 MI;Lo;0;L;;;;;N;;;;; +10017;LINEAR B SYLLABLE B015 MO;Lo;0;L;;;;;N;;;;; +10018;LINEAR B SYLLABLE B023 MU;Lo;0;L;;;;;N;;;;; +10019;LINEAR B SYLLABLE B006 NA;Lo;0;L;;;;;N;;;;; +1001A;LINEAR B SYLLABLE B024 NE;Lo;0;L;;;;;N;;;;; +1001B;LINEAR B SYLLABLE B030 NI;Lo;0;L;;;;;N;;;;; +1001C;LINEAR B SYLLABLE B052 NO;Lo;0;L;;;;;N;;;;; +1001D;LINEAR B SYLLABLE B055 NU;Lo;0;L;;;;;N;;;;; +1001E;LINEAR B SYLLABLE B003 PA;Lo;0;L;;;;;N;;;;; +1001F;LINEAR B SYLLABLE B072 PE;Lo;0;L;;;;;N;;;;; +10020;LINEAR B SYLLABLE B039 PI;Lo;0;L;;;;;N;;;;; +10021;LINEAR B SYLLABLE B011 PO;Lo;0;L;;;;;N;;;;; +10022;LINEAR B SYLLABLE B050 PU;Lo;0;L;;;;;N;;;;; +10023;LINEAR B SYLLABLE B016 QA;Lo;0;L;;;;;N;;;;; +10024;LINEAR B SYLLABLE B078 QE;Lo;0;L;;;;;N;;;;; +10025;LINEAR B SYLLABLE B021 QI;Lo;0;L;;;;;N;;;;; +10026;LINEAR B SYLLABLE B032 QO;Lo;0;L;;;;;N;;;;; +10028;LINEAR B SYLLABLE B060 RA;Lo;0;L;;;;;N;;;;; +10029;LINEAR B SYLLABLE B027 RE;Lo;0;L;;;;;N;;;;; +1002A;LINEAR B SYLLABLE B053 RI;Lo;0;L;;;;;N;;;;; +1002B;LINEAR B SYLLABLE B002 RO;Lo;0;L;;;;;N;;;;; +1002C;LINEAR B SYLLABLE B026 RU;Lo;0;L;;;;;N;;;;; +1002D;LINEAR B SYLLABLE B031 SA;Lo;0;L;;;;;N;;;;; +1002E;LINEAR B SYLLABLE B009 SE;Lo;0;L;;;;;N;;;;; +1002F;LINEAR B SYLLABLE B041 SI;Lo;0;L;;;;;N;;;;; +10030;LINEAR B SYLLABLE B012 SO;Lo;0;L;;;;;N;;;;; +10031;LINEAR B SYLLABLE B058 SU;Lo;0;L;;;;;N;;;;; +10032;LINEAR B SYLLABLE B059 TA;Lo;0;L;;;;;N;;;;; +10033;LINEAR B SYLLABLE B004 TE;Lo;0;L;;;;;N;;;;; +10034;LINEAR B SYLLABLE B037 TI;Lo;0;L;;;;;N;;;;; +10035;LINEAR B SYLLABLE B005 TO;Lo;0;L;;;;;N;;;;; +10036;LINEAR B SYLLABLE B069 TU;Lo;0;L;;;;;N;;;;; +10037;LINEAR B SYLLABLE B054 WA;Lo;0;L;;;;;N;;;;; +10038;LINEAR B SYLLABLE B075 WE;Lo;0;L;;;;;N;;;;; +10039;LINEAR B SYLLABLE B040 WI;Lo;0;L;;;;;N;;;;; +1003A;LINEAR B SYLLABLE B042 WO;Lo;0;L;;;;;N;;;;; +1003C;LINEAR B SYLLABLE B017 ZA;Lo;0;L;;;;;N;;;;; +1003D;LINEAR B SYLLABLE B074 ZE;Lo;0;L;;;;;N;;;;; +1003F;LINEAR B SYLLABLE B020 ZO;Lo;0;L;;;;;N;;;;; +10040;LINEAR B SYLLABLE B025 A2;Lo;0;L;;;;;N;;;;; +10041;LINEAR B SYLLABLE B043 A3;Lo;0;L;;;;;N;;;;; +10042;LINEAR B SYLLABLE B085 AU;Lo;0;L;;;;;N;;;;; +10043;LINEAR B SYLLABLE B071 DWE;Lo;0;L;;;;;N;;;;; +10044;LINEAR B SYLLABLE B090 DWO;Lo;0;L;;;;;N;;;;; +10045;LINEAR B SYLLABLE B048 NWA;Lo;0;L;;;;;N;;;;; +10046;LINEAR B SYLLABLE B029 PU2;Lo;0;L;;;;;N;;;;; +10047;LINEAR B SYLLABLE B062 PTE;Lo;0;L;;;;;N;;;;; +10048;LINEAR B SYLLABLE B076 RA2;Lo;0;L;;;;;N;;;;; +10049;LINEAR B SYLLABLE B033 RA3;Lo;0;L;;;;;N;;;;; +1004A;LINEAR B SYLLABLE B068 RO2;Lo;0;L;;;;;N;;;;; +1004B;LINEAR B SYLLABLE B066 TA2;Lo;0;L;;;;;N;;;;; +1004C;LINEAR B SYLLABLE B087 TWE;Lo;0;L;;;;;N;;;;; +1004D;LINEAR B SYLLABLE B091 TWO;Lo;0;L;;;;;N;;;;; +10050;LINEAR B SYMBOL B018;Lo;0;L;;;;;N;;;;; +10051;LINEAR B SYMBOL B019;Lo;0;L;;;;;N;;;;; +10052;LINEAR B SYMBOL B022;Lo;0;L;;;;;N;;;;; +10053;LINEAR B SYMBOL B034;Lo;0;L;;;;;N;;;;; +10054;LINEAR B SYMBOL B047;Lo;0;L;;;;;N;;;;; +10055;LINEAR B SYMBOL B049;Lo;0;L;;;;;N;;;;; +10056;LINEAR B SYMBOL B056;Lo;0;L;;;;;N;;;;; +10057;LINEAR B SYMBOL B063;Lo;0;L;;;;;N;;;;; +10058;LINEAR B SYMBOL B064;Lo;0;L;;;;;N;;;;; +10059;LINEAR B SYMBOL B079;Lo;0;L;;;;;N;;;;; +1005A;LINEAR B SYMBOL B082;Lo;0;L;;;;;N;;;;; +1005B;LINEAR B SYMBOL B083;Lo;0;L;;;;;N;;;;; +1005C;LINEAR B SYMBOL B086;Lo;0;L;;;;;N;;;;; +1005D;LINEAR B SYMBOL B089;Lo;0;L;;;;;N;;;;; +10080;LINEAR B IDEOGRAM B100 MAN;Lo;0;L;;;;;N;;;;; +10081;LINEAR B IDEOGRAM B102 WOMAN;Lo;0;L;;;;;N;;;;; +10082;LINEAR B IDEOGRAM B104 DEER;Lo;0;L;;;;;N;;;;; +10083;LINEAR B IDEOGRAM B105 EQUID;Lo;0;L;;;;;N;;;;; +10084;LINEAR B IDEOGRAM B105F MARE;Lo;0;L;;;;;N;;;;; +10085;LINEAR B IDEOGRAM B105M STALLION;Lo;0;L;;;;;N;;;;; +10086;LINEAR B IDEOGRAM B106F EWE;Lo;0;L;;;;;N;;;;; +10087;LINEAR B IDEOGRAM B106M RAM;Lo;0;L;;;;;N;;;;; +10088;LINEAR B IDEOGRAM B107F SHE-GOAT;Lo;0;L;;;;;N;;;;; +10089;LINEAR B IDEOGRAM B107M HE-GOAT;Lo;0;L;;;;;N;;;;; +1008A;LINEAR B IDEOGRAM B108F SOW;Lo;0;L;;;;;N;;;;; +1008B;LINEAR B IDEOGRAM B108M BOAR;Lo;0;L;;;;;N;;;;; +1008C;LINEAR B IDEOGRAM B109F COW;Lo;0;L;;;;;N;;;;; +1008D;LINEAR B IDEOGRAM B109M BULL;Lo;0;L;;;;;N;;;;; +1008E;LINEAR B IDEOGRAM B120 WHEAT;Lo;0;L;;;;;N;;;;; +1008F;LINEAR B IDEOGRAM B121 BARLEY;Lo;0;L;;;;;N;;;;; +10090;LINEAR B IDEOGRAM B122 OLIVE;Lo;0;L;;;;;N;;;;; +10091;LINEAR B IDEOGRAM B123 SPICE;Lo;0;L;;;;;N;;;;; +10092;LINEAR B IDEOGRAM B125 CYPERUS;Lo;0;L;;;;;N;;;;; +10093;LINEAR B MONOGRAM B127 KAPO;Lo;0;L;;;;;N;;;;; +10094;LINEAR B MONOGRAM B128 KANAKO;Lo;0;L;;;;;N;;;;; +10095;LINEAR B IDEOGRAM B130 OIL;Lo;0;L;;;;;N;;;;; +10096;LINEAR B IDEOGRAM B131 WINE;Lo;0;L;;;;;N;;;;; +10097;LINEAR B IDEOGRAM B132;Lo;0;L;;;;;N;;;;; +10098;LINEAR B MONOGRAM B133 AREPA;Lo;0;L;;;;;N;;;;; +10099;LINEAR B MONOGRAM B135 MERI;Lo;0;L;;;;;N;;;;; +1009A;LINEAR B IDEOGRAM B140 BRONZE;Lo;0;L;;;;;N;;;;; +1009B;LINEAR B IDEOGRAM B141 GOLD;Lo;0;L;;;;;N;;;;; +1009C;LINEAR B IDEOGRAM B142;Lo;0;L;;;;;N;;;;; +1009D;LINEAR B IDEOGRAM B145 WOOL;Lo;0;L;;;;;N;;;;; +1009E;LINEAR B IDEOGRAM B146;Lo;0;L;;;;;N;;;;; +1009F;LINEAR B IDEOGRAM B150;Lo;0;L;;;;;N;;;;; +100A0;LINEAR B IDEOGRAM B151 HORN;Lo;0;L;;;;;N;;;;; +100A1;LINEAR B IDEOGRAM B152;Lo;0;L;;;;;N;;;;; +100A2;LINEAR B IDEOGRAM B153;Lo;0;L;;;;;N;;;;; +100A3;LINEAR B IDEOGRAM B154;Lo;0;L;;;;;N;;;;; +100A4;LINEAR B MONOGRAM B156 TURO2;Lo;0;L;;;;;N;;;;; +100A5;LINEAR B IDEOGRAM B157;Lo;0;L;;;;;N;;;;; +100A6;LINEAR B IDEOGRAM B158;Lo;0;L;;;;;N;;;;; +100A7;LINEAR B IDEOGRAM B159 CLOTH;Lo;0;L;;;;;N;;;;; +100A8;LINEAR B IDEOGRAM B160;Lo;0;L;;;;;N;;;;; +100A9;LINEAR B IDEOGRAM B161;Lo;0;L;;;;;N;;;;; +100AA;LINEAR B IDEOGRAM B162 GARMENT;Lo;0;L;;;;;N;;;;; +100AB;LINEAR B IDEOGRAM B163 ARMOUR;Lo;0;L;;;;;N;;;;; +100AC;LINEAR B IDEOGRAM B164;Lo;0;L;;;;;N;;;;; +100AD;LINEAR B IDEOGRAM B165;Lo;0;L;;;;;N;;;;; +100AE;LINEAR B IDEOGRAM B166;Lo;0;L;;;;;N;;;;; +100AF;LINEAR B IDEOGRAM B167;Lo;0;L;;;;;N;;;;; +100B0;LINEAR B IDEOGRAM B168;Lo;0;L;;;;;N;;;;; +100B1;LINEAR B IDEOGRAM B169;Lo;0;L;;;;;N;;;;; +100B2;LINEAR B IDEOGRAM B170;Lo;0;L;;;;;N;;;;; +100B3;LINEAR B IDEOGRAM B171;Lo;0;L;;;;;N;;;;; +100B4;LINEAR B IDEOGRAM B172;Lo;0;L;;;;;N;;;;; +100B5;LINEAR B IDEOGRAM B173 MONTH;Lo;0;L;;;;;N;;;;; +100B6;LINEAR B IDEOGRAM B174;Lo;0;L;;;;;N;;;;; +100B7;LINEAR B IDEOGRAM B176 TREE;Lo;0;L;;;;;N;;;;; +100B8;LINEAR B IDEOGRAM B177;Lo;0;L;;;;;N;;;;; +100B9;LINEAR B IDEOGRAM B178;Lo;0;L;;;;;N;;;;; +100BA;LINEAR B IDEOGRAM B179;Lo;0;L;;;;;N;;;;; +100BB;LINEAR B IDEOGRAM B180;Lo;0;L;;;;;N;;;;; +100BC;LINEAR B IDEOGRAM B181;Lo;0;L;;;;;N;;;;; +100BD;LINEAR B IDEOGRAM B182;Lo;0;L;;;;;N;;;;; +100BE;LINEAR B IDEOGRAM B183;Lo;0;L;;;;;N;;;;; +100BF;LINEAR B IDEOGRAM B184;Lo;0;L;;;;;N;;;;; +100C0;LINEAR B IDEOGRAM B185;Lo;0;L;;;;;N;;;;; +100C1;LINEAR B IDEOGRAM B189;Lo;0;L;;;;;N;;;;; +100C2;LINEAR B IDEOGRAM B190;Lo;0;L;;;;;N;;;;; +100C3;LINEAR B IDEOGRAM B191 HELMET;Lo;0;L;;;;;N;;;;; +100C4;LINEAR B IDEOGRAM B220 FOOTSTOOL;Lo;0;L;;;;;N;;;;; +100C5;LINEAR B IDEOGRAM B225 BATHTUB;Lo;0;L;;;;;N;;;;; +100C6;LINEAR B IDEOGRAM B230 SPEAR;Lo;0;L;;;;;N;;;;; +100C7;LINEAR B IDEOGRAM B231 ARROW;Lo;0;L;;;;;N;;;;; +100C8;LINEAR B IDEOGRAM B232;Lo;0;L;;;;;N;;;;; +100C9;LINEAR B IDEOGRAM B233 SWORD;Lo;0;L;;;;;N;;pug;;; +100CA;LINEAR B IDEOGRAM B234;Lo;0;L;;;;;N;;;;; +100CB;LINEAR B IDEOGRAM B236;Lo;0;L;;;;;N;;gup;;; +100CC;LINEAR B IDEOGRAM B240 WHEELED CHARIOT;Lo;0;L;;;;;N;;;;; +100CD;LINEAR B IDEOGRAM B241 CHARIOT;Lo;0;L;;;;;N;;;;; +100CE;LINEAR B IDEOGRAM B242 CHARIOT FRAME;Lo;0;L;;;;;N;;;;; +100CF;LINEAR B IDEOGRAM B243 WHEEL;Lo;0;L;;;;;N;;;;; +100D0;LINEAR B IDEOGRAM B245;Lo;0;L;;;;;N;;;;; +100D1;LINEAR B IDEOGRAM B246;Lo;0;L;;;;;N;;;;; +100D2;LINEAR B MONOGRAM B247 DIPTE;Lo;0;L;;;;;N;;;;; +100D3;LINEAR B IDEOGRAM B248;Lo;0;L;;;;;N;;;;; +100D4;LINEAR B IDEOGRAM B249;Lo;0;L;;;;;N;;;;; +100D5;LINEAR B IDEOGRAM B251;Lo;0;L;;;;;N;;;;; +100D6;LINEAR B IDEOGRAM B252;Lo;0;L;;;;;N;;;;; +100D7;LINEAR B IDEOGRAM B253;Lo;0;L;;;;;N;;;;; +100D8;LINEAR B IDEOGRAM B254 DART;Lo;0;L;;;;;N;;;;; +100D9;LINEAR B IDEOGRAM B255;Lo;0;L;;;;;N;;;;; +100DA;LINEAR B IDEOGRAM B256;Lo;0;L;;;;;N;;;;; +100DB;LINEAR B IDEOGRAM B257;Lo;0;L;;;;;N;;;;; +100DC;LINEAR B IDEOGRAM B258;Lo;0;L;;;;;N;;;;; +100DD;LINEAR B IDEOGRAM B259;Lo;0;L;;;;;N;;;;; +100DE;LINEAR B IDEOGRAM VESSEL B155;Lo;0;L;;;;;N;;;;; +100DF;LINEAR B IDEOGRAM VESSEL B200;Lo;0;L;;;;;N;;;;; +100E0;LINEAR B IDEOGRAM VESSEL B201;Lo;0;L;;;;;N;;;;; +100E1;LINEAR B IDEOGRAM VESSEL B202;Lo;0;L;;;;;N;;;;; +100E2;LINEAR B IDEOGRAM VESSEL B203;Lo;0;L;;;;;N;;;;; +100E3;LINEAR B IDEOGRAM VESSEL B204;Lo;0;L;;;;;N;;;;; +100E4;LINEAR B IDEOGRAM VESSEL B205;Lo;0;L;;;;;N;;;;; +100E5;LINEAR B IDEOGRAM VESSEL B206;Lo;0;L;;;;;N;;;;; +100E6;LINEAR B IDEOGRAM VESSEL B207;Lo;0;L;;;;;N;;;;; +100E7;LINEAR B IDEOGRAM VESSEL B208;Lo;0;L;;;;;N;;;;; +100E8;LINEAR B IDEOGRAM VESSEL B209;Lo;0;L;;;;;N;;;;; +100E9;LINEAR B IDEOGRAM VESSEL B210;Lo;0;L;;;;;N;;;;; +100EA;LINEAR B IDEOGRAM VESSEL B211;Lo;0;L;;;;;N;;;;; +100EB;LINEAR B IDEOGRAM VESSEL B212;Lo;0;L;;;;;N;;;;; +100EC;LINEAR B IDEOGRAM VESSEL B213;Lo;0;L;;;;;N;;;;; +100ED;LINEAR B IDEOGRAM VESSEL B214;Lo;0;L;;;;;N;;;;; +100EE;LINEAR B IDEOGRAM VESSEL B215;Lo;0;L;;;;;N;;;;; +100EF;LINEAR B IDEOGRAM VESSEL B216;Lo;0;L;;;;;N;;;;; +100F0;LINEAR B IDEOGRAM VESSEL B217;Lo;0;L;;;;;N;;;;; +100F1;LINEAR B IDEOGRAM VESSEL B218;Lo;0;L;;;;;N;;;;; +100F2;LINEAR B IDEOGRAM VESSEL B219;Lo;0;L;;;;;N;;;;; +100F3;LINEAR B IDEOGRAM VESSEL B221;Lo;0;L;;;;;N;;;;; +100F4;LINEAR B IDEOGRAM VESSEL B222;Lo;0;L;;;;;N;;;;; +100F5;LINEAR B IDEOGRAM VESSEL B226;Lo;0;L;;;;;N;;;;; +100F6;LINEAR B IDEOGRAM VESSEL B227;Lo;0;L;;;;;N;;;;; +100F7;LINEAR B IDEOGRAM VESSEL B228;Lo;0;L;;;;;N;;;;; +100F8;LINEAR B IDEOGRAM VESSEL B229;Lo;0;L;;;;;N;;;;; +100F9;LINEAR B IDEOGRAM VESSEL B250;Lo;0;L;;;;;N;;;;; +100FA;LINEAR B IDEOGRAM VESSEL B305;Lo;0;L;;;;;N;;;;; +10100;AEGEAN WORD SEPARATOR LINE;Po;0;L;;;;;N;;;;; +10101;AEGEAN WORD SEPARATOR DOT;Po;0;ON;;;;;N;;;;; +10102;AEGEAN CHECK MARK;So;0;L;;;;;N;;;;; +10107;AEGEAN NUMBER ONE;No;0;L;;;;1;N;;;;; +10108;AEGEAN NUMBER TWO;No;0;L;;;;2;N;;;;; +10109;AEGEAN NUMBER THREE;No;0;L;;;;3;N;;;;; +1010A;AEGEAN NUMBER FOUR;No;0;L;;;;4;N;;;;; +1010B;AEGEAN NUMBER FIVE;No;0;L;;;;5;N;;;;; +1010C;AEGEAN NUMBER SIX;No;0;L;;;;6;N;;;;; +1010D;AEGEAN NUMBER SEVEN;No;0;L;;;;7;N;;;;; +1010E;AEGEAN NUMBER EIGHT;No;0;L;;;;8;N;;;;; +1010F;AEGEAN NUMBER NINE;No;0;L;;;;9;N;;;;; +10110;AEGEAN NUMBER TEN;No;0;L;;;;10;N;;;;; +10111;AEGEAN NUMBER TWENTY;No;0;L;;;;20;N;;;;; +10112;AEGEAN NUMBER THIRTY;No;0;L;;;;30;N;;;;; +10113;AEGEAN NUMBER FORTY;No;0;L;;;;40;N;;;;; +10114;AEGEAN NUMBER FIFTY;No;0;L;;;;50;N;;;;; +10115;AEGEAN NUMBER SIXTY;No;0;L;;;;60;N;;;;; +10116;AEGEAN NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +10117;AEGEAN NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +10118;AEGEAN NUMBER NINETY;No;0;L;;;;90;N;;;;; +10119;AEGEAN NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; +1011A;AEGEAN NUMBER TWO HUNDRED;No;0;L;;;;200;N;;;;; +1011B;AEGEAN NUMBER THREE HUNDRED;No;0;L;;;;300;N;;;;; +1011C;AEGEAN NUMBER FOUR HUNDRED;No;0;L;;;;400;N;;;;; +1011D;AEGEAN NUMBER FIVE HUNDRED;No;0;L;;;;500;N;;;;; +1011E;AEGEAN NUMBER SIX HUNDRED;No;0;L;;;;600;N;;;;; +1011F;AEGEAN NUMBER SEVEN HUNDRED;No;0;L;;;;700;N;;;;; +10120;AEGEAN NUMBER EIGHT HUNDRED;No;0;L;;;;800;N;;;;; +10121;AEGEAN NUMBER NINE HUNDRED;No;0;L;;;;900;N;;;;; +10122;AEGEAN NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; +10123;AEGEAN NUMBER TWO THOUSAND;No;0;L;;;;2000;N;;;;; +10124;AEGEAN NUMBER THREE THOUSAND;No;0;L;;;;3000;N;;;;; +10125;AEGEAN NUMBER FOUR THOUSAND;No;0;L;;;;4000;N;;;;; +10126;AEGEAN NUMBER FIVE THOUSAND;No;0;L;;;;5000;N;;;;; +10127;AEGEAN NUMBER SIX THOUSAND;No;0;L;;;;6000;N;;;;; +10128;AEGEAN NUMBER SEVEN THOUSAND;No;0;L;;;;7000;N;;;;; +10129;AEGEAN NUMBER EIGHT THOUSAND;No;0;L;;;;8000;N;;;;; +1012A;AEGEAN NUMBER NINE THOUSAND;No;0;L;;;;9000;N;;;;; +1012B;AEGEAN NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;; +1012C;AEGEAN NUMBER TWENTY THOUSAND;No;0;L;;;;20000;N;;;;; +1012D;AEGEAN NUMBER THIRTY THOUSAND;No;0;L;;;;30000;N;;;;; +1012E;AEGEAN NUMBER FORTY THOUSAND;No;0;L;;;;40000;N;;;;; +1012F;AEGEAN NUMBER FIFTY THOUSAND;No;0;L;;;;50000;N;;;;; +10130;AEGEAN NUMBER SIXTY THOUSAND;No;0;L;;;;60000;N;;;;; +10131;AEGEAN NUMBER SEVENTY THOUSAND;No;0;L;;;;70000;N;;;;; +10132;AEGEAN NUMBER EIGHTY THOUSAND;No;0;L;;;;80000;N;;;;; +10133;AEGEAN NUMBER NINETY THOUSAND;No;0;L;;;;90000;N;;;;; +10137;AEGEAN WEIGHT BASE UNIT;So;0;L;;;;;N;;;;; +10138;AEGEAN WEIGHT FIRST SUBUNIT;So;0;L;;;;;N;;;;; +10139;AEGEAN WEIGHT SECOND SUBUNIT;So;0;L;;;;;N;;;;; +1013A;AEGEAN WEIGHT THIRD SUBUNIT;So;0;L;;;;;N;;;;; +1013B;AEGEAN WEIGHT FOURTH SUBUNIT;So;0;L;;;;;N;;;;; +1013C;AEGEAN DRY MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;; +1013D;AEGEAN LIQUID MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;; +1013E;AEGEAN MEASURE SECOND SUBUNIT;So;0;L;;;;;N;;;;; +1013F;AEGEAN MEASURE THIRD SUBUNIT;So;0;L;;;;;N;;;;; +10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;; +10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;; +10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;; +10303;OLD ITALIC LETTER DE;Lo;0;L;;;;;N;;;;; +10304;OLD ITALIC LETTER E;Lo;0;L;;;;;N;;;;; +10305;OLD ITALIC LETTER VE;Lo;0;L;;;;;N;;;;; +10306;OLD ITALIC LETTER ZE;Lo;0;L;;;;;N;;;;; +10307;OLD ITALIC LETTER HE;Lo;0;L;;;;;N;;;;; +10308;OLD ITALIC LETTER THE;Lo;0;L;;;;;N;;;;; +10309;OLD ITALIC LETTER I;Lo;0;L;;;;;N;;;;; +1030A;OLD ITALIC LETTER KA;Lo;0;L;;;;;N;;;;; +1030B;OLD ITALIC LETTER EL;Lo;0;L;;;;;N;;;;; +1030C;OLD ITALIC LETTER EM;Lo;0;L;;;;;N;;;;; +1030D;OLD ITALIC LETTER EN;Lo;0;L;;;;;N;;;;; +1030E;OLD ITALIC LETTER ESH;Lo;0;L;;;;;N;;;;; +1030F;OLD ITALIC LETTER O;Lo;0;L;;;;;N;;Faliscan;;; +10310;OLD ITALIC LETTER PE;Lo;0;L;;;;;N;;;;; +10311;OLD ITALIC LETTER SHE;Lo;0;L;;;;;N;;;;; +10312;OLD ITALIC LETTER KU;Lo;0;L;;;;;N;;;;; +10313;OLD ITALIC LETTER ER;Lo;0;L;;;;;N;;;;; +10314;OLD ITALIC LETTER ES;Lo;0;L;;;;;N;;;;; +10315;OLD ITALIC LETTER TE;Lo;0;L;;;;;N;;;;; +10316;OLD ITALIC LETTER U;Lo;0;L;;;;;N;;;;; +10317;OLD ITALIC LETTER EKS;Lo;0;L;;;;;N;;Faliscan;;; +10318;OLD ITALIC LETTER PHE;Lo;0;L;;;;;N;;;;; +10319;OLD ITALIC LETTER KHE;Lo;0;L;;;;;N;;;;; +1031A;OLD ITALIC LETTER EF;Lo;0;L;;;;;N;;;;; +1031B;OLD ITALIC LETTER ERS;Lo;0;L;;;;;N;;Umbrian;;; +1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;Umbrian;;; +1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;Oscan;;; +1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;Oscan;;; +10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;; +10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;; +10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;; +10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;; +10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;; +10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;; +10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;; +10333;GOTHIC LETTER DAGS;Lo;0;L;;;;;N;;;;; +10334;GOTHIC LETTER AIHVUS;Lo;0;L;;;;;N;;;;; +10335;GOTHIC LETTER QAIRTHRA;Lo;0;L;;;;;N;;;;; +10336;GOTHIC LETTER IUJA;Lo;0;L;;;;;N;;;;; +10337;GOTHIC LETTER HAGL;Lo;0;L;;;;;N;;;;; +10338;GOTHIC LETTER THIUTH;Lo;0;L;;;;;N;;;;; +10339;GOTHIC LETTER EIS;Lo;0;L;;;;;N;;;;; +1033A;GOTHIC LETTER KUSMA;Lo;0;L;;;;;N;;;;; +1033B;GOTHIC LETTER LAGUS;Lo;0;L;;;;;N;;;;; +1033C;GOTHIC LETTER MANNA;Lo;0;L;;;;;N;;;;; +1033D;GOTHIC LETTER NAUTHS;Lo;0;L;;;;;N;;;;; +1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;; +1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;; +10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;; +10341;GOTHIC LETTER NINETY;Lo;0;L;;;;;N;;;;; +10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;; +10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;; +10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;; +10345;GOTHIC LETTER WINJA;Lo;0;L;;;;;N;;;;; +10346;GOTHIC LETTER FAIHU;Lo;0;L;;;;;N;;;;; +10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;; +10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;; +10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;; +1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;;N;;;;; +10380;UGARITIC LETTER ALPA;Lo;0;L;;;;;N;;;;; +10381;UGARITIC LETTER BETA;Lo;0;L;;;;;N;;;;; +10382;UGARITIC LETTER GAMLA;Lo;0;L;;;;;N;;;;; +10383;UGARITIC LETTER KHA;Lo;0;L;;;;;N;;;;; +10384;UGARITIC LETTER DELTA;Lo;0;L;;;;;N;;;;; +10385;UGARITIC LETTER HO;Lo;0;L;;;;;N;;;;; +10386;UGARITIC LETTER WO;Lo;0;L;;;;;N;;;;; +10387;UGARITIC LETTER ZETA;Lo;0;L;;;;;N;;;;; +10388;UGARITIC LETTER HOTA;Lo;0;L;;;;;N;;;;; +10389;UGARITIC LETTER TET;Lo;0;L;;;;;N;;;;; +1038A;UGARITIC LETTER YOD;Lo;0;L;;;;;N;;;;; +1038B;UGARITIC LETTER KAF;Lo;0;L;;;;;N;;;;; +1038C;UGARITIC LETTER SHIN;Lo;0;L;;;;;N;;;;; +1038D;UGARITIC LETTER LAMDA;Lo;0;L;;;;;N;;;;; +1038E;UGARITIC LETTER MEM;Lo;0;L;;;;;N;;;;; +1038F;UGARITIC LETTER DHAL;Lo;0;L;;;;;N;;;;; +10390;UGARITIC LETTER NUN;Lo;0;L;;;;;N;;;;; +10391;UGARITIC LETTER ZU;Lo;0;L;;;;;N;;;;; +10392;UGARITIC LETTER SAMKA;Lo;0;L;;;;;N;;;;; +10393;UGARITIC LETTER AIN;Lo;0;L;;;;;N;;;;; +10394;UGARITIC LETTER PU;Lo;0;L;;;;;N;;;;; +10395;UGARITIC LETTER SADE;Lo;0;L;;;;;N;;;;; +10396;UGARITIC LETTER QOPA;Lo;0;L;;;;;N;;;;; +10397;UGARITIC LETTER RASHA;Lo;0;L;;;;;N;;;;; +10398;UGARITIC LETTER THANNA;Lo;0;L;;;;;N;;;;; +10399;UGARITIC LETTER GHAIN;Lo;0;L;;;;;N;;;;; +1039A;UGARITIC LETTER TO;Lo;0;L;;;;;N;;;;; +1039B;UGARITIC LETTER I;Lo;0;L;;;;;N;;;;; +1039C;UGARITIC LETTER U;Lo;0;L;;;;;N;;;;; +1039D;UGARITIC LETTER SSU;Lo;0;L;;;;;N;;;;; +1039F;UGARITIC WORD DIVIDER;Po;0;L;;;;;N;;;;; +10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428; +10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429; +10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A; +10403;DESERET CAPITAL LETTER LONG AH;Lu;0;L;;;;;N;;;;1042B; +10404;DESERET CAPITAL LETTER LONG O;Lu;0;L;;;;;N;;;;1042C; +10405;DESERET CAPITAL LETTER LONG OO;Lu;0;L;;;;;N;;;;1042D; +10406;DESERET CAPITAL LETTER SHORT I;Lu;0;L;;;;;N;;;;1042E; +10407;DESERET CAPITAL LETTER SHORT E;Lu;0;L;;;;;N;;;;1042F; +10408;DESERET CAPITAL LETTER SHORT A;Lu;0;L;;;;;N;;;;10430; +10409;DESERET CAPITAL LETTER SHORT AH;Lu;0;L;;;;;N;;;;10431; +1040A;DESERET CAPITAL LETTER SHORT O;Lu;0;L;;;;;N;;;;10432; +1040B;DESERET CAPITAL LETTER SHORT OO;Lu;0;L;;;;;N;;;;10433; +1040C;DESERET CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;10434; +1040D;DESERET CAPITAL LETTER OW;Lu;0;L;;;;;N;;;;10435; +1040E;DESERET CAPITAL LETTER WU;Lu;0;L;;;;;N;;;;10436; +1040F;DESERET CAPITAL LETTER YEE;Lu;0;L;;;;;N;;;;10437; +10410;DESERET CAPITAL LETTER H;Lu;0;L;;;;;N;;;;10438; +10411;DESERET CAPITAL LETTER PEE;Lu;0;L;;;;;N;;;;10439; +10412;DESERET CAPITAL LETTER BEE;Lu;0;L;;;;;N;;;;1043A; +10413;DESERET CAPITAL LETTER TEE;Lu;0;L;;;;;N;;;;1043B; +10414;DESERET CAPITAL LETTER DEE;Lu;0;L;;;;;N;;;;1043C; +10415;DESERET CAPITAL LETTER CHEE;Lu;0;L;;;;;N;;;;1043D; +10416;DESERET CAPITAL LETTER JEE;Lu;0;L;;;;;N;;;;1043E; +10417;DESERET CAPITAL LETTER KAY;Lu;0;L;;;;;N;;;;1043F; +10418;DESERET CAPITAL LETTER GAY;Lu;0;L;;;;;N;;;;10440; +10419;DESERET CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;10441; +1041A;DESERET CAPITAL LETTER VEE;Lu;0;L;;;;;N;;;;10442; +1041B;DESERET CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;10443; +1041C;DESERET CAPITAL LETTER THEE;Lu;0;L;;;;;N;;;;10444; +1041D;DESERET CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;10445; +1041E;DESERET CAPITAL LETTER ZEE;Lu;0;L;;;;;N;;;;10446; +1041F;DESERET CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;10447; +10420;DESERET CAPITAL LETTER ZHEE;Lu;0;L;;;;;N;;;;10448; +10421;DESERET CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;10449; +10422;DESERET CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;1044A; +10423;DESERET CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;1044B; +10424;DESERET CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;1044C; +10425;DESERET CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;1044D; +10426;DESERET CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;1044E; +10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F; +10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400 +10429;DESERET SMALL LETTER LONG E;Ll;0;L;;;;;N;;;10401;;10401 +1042A;DESERET SMALL LETTER LONG A;Ll;0;L;;;;;N;;;10402;;10402 +1042B;DESERET SMALL LETTER LONG AH;Ll;0;L;;;;;N;;;10403;;10403 +1042C;DESERET SMALL LETTER LONG O;Ll;0;L;;;;;N;;;10404;;10404 +1042D;DESERET SMALL LETTER LONG OO;Ll;0;L;;;;;N;;;10405;;10405 +1042E;DESERET SMALL LETTER SHORT I;Ll;0;L;;;;;N;;;10406;;10406 +1042F;DESERET SMALL LETTER SHORT E;Ll;0;L;;;;;N;;;10407;;10407 +10430;DESERET SMALL LETTER SHORT A;Ll;0;L;;;;;N;;;10408;;10408 +10431;DESERET SMALL LETTER SHORT AH;Ll;0;L;;;;;N;;;10409;;10409 +10432;DESERET SMALL LETTER SHORT O;Ll;0;L;;;;;N;;;1040A;;1040A +10433;DESERET SMALL LETTER SHORT OO;Ll;0;L;;;;;N;;;1040B;;1040B +10434;DESERET SMALL LETTER AY;Ll;0;L;;;;;N;;;1040C;;1040C +10435;DESERET SMALL LETTER OW;Ll;0;L;;;;;N;;;1040D;;1040D +10436;DESERET SMALL LETTER WU;Ll;0;L;;;;;N;;;1040E;;1040E +10437;DESERET SMALL LETTER YEE;Ll;0;L;;;;;N;;;1040F;;1040F +10438;DESERET SMALL LETTER H;Ll;0;L;;;;;N;;;10410;;10410 +10439;DESERET SMALL LETTER PEE;Ll;0;L;;;;;N;;;10411;;10411 +1043A;DESERET SMALL LETTER BEE;Ll;0;L;;;;;N;;;10412;;10412 +1043B;DESERET SMALL LETTER TEE;Ll;0;L;;;;;N;;;10413;;10413 +1043C;DESERET SMALL LETTER DEE;Ll;0;L;;;;;N;;;10414;;10414 +1043D;DESERET SMALL LETTER CHEE;Ll;0;L;;;;;N;;;10415;;10415 +1043E;DESERET SMALL LETTER JEE;Ll;0;L;;;;;N;;;10416;;10416 +1043F;DESERET SMALL LETTER KAY;Ll;0;L;;;;;N;;;10417;;10417 +10440;DESERET SMALL LETTER GAY;Ll;0;L;;;;;N;;;10418;;10418 +10441;DESERET SMALL LETTER EF;Ll;0;L;;;;;N;;;10419;;10419 +10442;DESERET SMALL LETTER VEE;Ll;0;L;;;;;N;;;1041A;;1041A +10443;DESERET SMALL LETTER ETH;Ll;0;L;;;;;N;;;1041B;;1041B +10444;DESERET SMALL LETTER THEE;Ll;0;L;;;;;N;;;1041C;;1041C +10445;DESERET SMALL LETTER ES;Ll;0;L;;;;;N;;;1041D;;1041D +10446;DESERET SMALL LETTER ZEE;Ll;0;L;;;;;N;;;1041E;;1041E +10447;DESERET SMALL LETTER ESH;Ll;0;L;;;;;N;;;1041F;;1041F +10448;DESERET SMALL LETTER ZHEE;Ll;0;L;;;;;N;;;10420;;10420 +10449;DESERET SMALL LETTER ER;Ll;0;L;;;;;N;;;10421;;10421 +1044A;DESERET SMALL LETTER EL;Ll;0;L;;;;;N;;;10422;;10422 +1044B;DESERET SMALL LETTER EM;Ll;0;L;;;;;N;;;10423;;10423 +1044C;DESERET SMALL LETTER EN;Ll;0;L;;;;;N;;;10424;;10424 +1044D;DESERET SMALL LETTER ENG;Ll;0;L;;;;;N;;;10425;;10425 +1044E;DESERET SMALL LETTER OI;Ll;0;L;;;;;N;;;10426;;10426 +1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427 +10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;; +10451;SHAVIAN LETTER TOT;Lo;0;L;;;;;N;;;;; +10452;SHAVIAN LETTER KICK;Lo;0;L;;;;;N;;;;; +10453;SHAVIAN LETTER FEE;Lo;0;L;;;;;N;;;;; +10454;SHAVIAN LETTER THIGH;Lo;0;L;;;;;N;;;;; +10455;SHAVIAN LETTER SO;Lo;0;L;;;;;N;;;;; +10456;SHAVIAN LETTER SURE;Lo;0;L;;;;;N;;;;; +10457;SHAVIAN LETTER CHURCH;Lo;0;L;;;;;N;;;;; +10458;SHAVIAN LETTER YEA;Lo;0;L;;;;;N;;;;; +10459;SHAVIAN LETTER HUNG;Lo;0;L;;;;;N;;;;; +1045A;SHAVIAN LETTER BIB;Lo;0;L;;;;;N;;;;; +1045B;SHAVIAN LETTER DEAD;Lo;0;L;;;;;N;;;;; +1045C;SHAVIAN LETTER GAG;Lo;0;L;;;;;N;;;;; +1045D;SHAVIAN LETTER VOW;Lo;0;L;;;;;N;;;;; +1045E;SHAVIAN LETTER THEY;Lo;0;L;;;;;N;;;;; +1045F;SHAVIAN LETTER ZOO;Lo;0;L;;;;;N;;;;; +10460;SHAVIAN LETTER MEASURE;Lo;0;L;;;;;N;;;;; +10461;SHAVIAN LETTER JUDGE;Lo;0;L;;;;;N;;;;; +10462;SHAVIAN LETTER WOE;Lo;0;L;;;;;N;;;;; +10463;SHAVIAN LETTER HA-HA;Lo;0;L;;;;;N;;;;; +10464;SHAVIAN LETTER LOLL;Lo;0;L;;;;;N;;;;; +10465;SHAVIAN LETTER MIME;Lo;0;L;;;;;N;;;;; +10466;SHAVIAN LETTER IF;Lo;0;L;;;;;N;;;;; +10467;SHAVIAN LETTER EGG;Lo;0;L;;;;;N;;;;; +10468;SHAVIAN LETTER ASH;Lo;0;L;;;;;N;;;;; +10469;SHAVIAN LETTER ADO;Lo;0;L;;;;;N;;;;; +1046A;SHAVIAN LETTER ON;Lo;0;L;;;;;N;;;;; +1046B;SHAVIAN LETTER WOOL;Lo;0;L;;;;;N;;;;; +1046C;SHAVIAN LETTER OUT;Lo;0;L;;;;;N;;;;; +1046D;SHAVIAN LETTER AH;Lo;0;L;;;;;N;;;;; +1046E;SHAVIAN LETTER ROAR;Lo;0;L;;;;;N;;;;; +1046F;SHAVIAN LETTER NUN;Lo;0;L;;;;;N;;;;; +10470;SHAVIAN LETTER EAT;Lo;0;L;;;;;N;;;;; +10471;SHAVIAN LETTER AGE;Lo;0;L;;;;;N;;;;; +10472;SHAVIAN LETTER ICE;Lo;0;L;;;;;N;;;;; +10473;SHAVIAN LETTER UP;Lo;0;L;;;;;N;;;;; +10474;SHAVIAN LETTER OAK;Lo;0;L;;;;;N;;;;; +10475;SHAVIAN LETTER OOZE;Lo;0;L;;;;;N;;;;; +10476;SHAVIAN LETTER OIL;Lo;0;L;;;;;N;;;;; +10477;SHAVIAN LETTER AWE;Lo;0;L;;;;;N;;;;; +10478;SHAVIAN LETTER ARE;Lo;0;L;;;;;N;;;;; +10479;SHAVIAN LETTER OR;Lo;0;L;;;;;N;;;;; +1047A;SHAVIAN LETTER AIR;Lo;0;L;;;;;N;;;;; +1047B;SHAVIAN LETTER ERR;Lo;0;L;;;;;N;;;;; +1047C;SHAVIAN LETTER ARRAY;Lo;0;L;;;;;N;;;;; +1047D;SHAVIAN LETTER EAR;Lo;0;L;;;;;N;;;;; +1047E;SHAVIAN LETTER IAN;Lo;0;L;;;;;N;;;;; +1047F;SHAVIAN LETTER YEW;Lo;0;L;;;;;N;;;;; +10480;OSMANYA LETTER ALEF;Lo;0;L;;;;;N;;;;; +10481;OSMANYA LETTER BA;Lo;0;L;;;;;N;;;;; +10482;OSMANYA LETTER TA;Lo;0;L;;;;;N;;;;; +10483;OSMANYA LETTER JA;Lo;0;L;;;;;N;;;;; +10484;OSMANYA LETTER XA;Lo;0;L;;;;;N;;;;; +10485;OSMANYA LETTER KHA;Lo;0;L;;;;;N;;;;; +10486;OSMANYA LETTER DEEL;Lo;0;L;;;;;N;;;;; +10487;OSMANYA LETTER RA;Lo;0;L;;;;;N;;;;; +10488;OSMANYA LETTER SA;Lo;0;L;;;;;N;;;;; +10489;OSMANYA LETTER SHIIN;Lo;0;L;;;;;N;;;;; +1048A;OSMANYA LETTER DHA;Lo;0;L;;;;;N;;;;; +1048B;OSMANYA LETTER CAYN;Lo;0;L;;;;;N;;;;; +1048C;OSMANYA LETTER GA;Lo;0;L;;;;;N;;;;; +1048D;OSMANYA LETTER FA;Lo;0;L;;;;;N;;;;; +1048E;OSMANYA LETTER QAAF;Lo;0;L;;;;;N;;;;; +1048F;OSMANYA LETTER KAAF;Lo;0;L;;;;;N;;;;; +10490;OSMANYA LETTER LAAN;Lo;0;L;;;;;N;;;;; +10491;OSMANYA LETTER MIIN;Lo;0;L;;;;;N;;;;; +10492;OSMANYA LETTER NUUN;Lo;0;L;;;;;N;;;;; +10493;OSMANYA LETTER WAW;Lo;0;L;;;;;N;;;;; +10494;OSMANYA LETTER HA;Lo;0;L;;;;;N;;;;; +10495;OSMANYA LETTER YA;Lo;0;L;;;;;N;;;;; +10496;OSMANYA LETTER A;Lo;0;L;;;;;N;;;;; +10497;OSMANYA LETTER E;Lo;0;L;;;;;N;;;;; +10498;OSMANYA LETTER I;Lo;0;L;;;;;N;;;;; +10499;OSMANYA LETTER O;Lo;0;L;;;;;N;;;;; +1049A;OSMANYA LETTER U;Lo;0;L;;;;;N;;;;; +1049B;OSMANYA LETTER AA;Lo;0;L;;;;;N;;;;; +1049C;OSMANYA LETTER EE;Lo;0;L;;;;;N;;;;; +1049D;OSMANYA LETTER OO;Lo;0;L;;;;;N;;;;; +104A0;OSMANYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +104A1;OSMANYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +104A2;OSMANYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +104A3;OSMANYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +104A4;OSMANYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +104A5;OSMANYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +104A6;OSMANYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +104A7;OSMANYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +104A8;OSMANYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +104A9;OSMANYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +10800;CYPRIOT SYLLABLE A;Lo;0;R;;;;;N;;;;; +10801;CYPRIOT SYLLABLE E;Lo;0;R;;;;;N;;;;; +10802;CYPRIOT SYLLABLE I;Lo;0;R;;;;;N;;;;; +10803;CYPRIOT SYLLABLE O;Lo;0;R;;;;;N;;;;; +10804;CYPRIOT SYLLABLE U;Lo;0;R;;;;;N;;;;; +10805;CYPRIOT SYLLABLE JA;Lo;0;R;;;;;N;;;;; +10808;CYPRIOT SYLLABLE JO;Lo;0;R;;;;;N;;;;; +1080A;CYPRIOT SYLLABLE KA;Lo;0;R;;;;;N;;;;; +1080B;CYPRIOT SYLLABLE KE;Lo;0;R;;;;;N;;;;; +1080C;CYPRIOT SYLLABLE KI;Lo;0;R;;;;;N;;;;; +1080D;CYPRIOT SYLLABLE KO;Lo;0;R;;;;;N;;;;; +1080E;CYPRIOT SYLLABLE KU;Lo;0;R;;;;;N;;;;; +1080F;CYPRIOT SYLLABLE LA;Lo;0;R;;;;;N;;;;; +10810;CYPRIOT SYLLABLE LE;Lo;0;R;;;;;N;;;;; +10811;CYPRIOT SYLLABLE LI;Lo;0;R;;;;;N;;;;; +10812;CYPRIOT SYLLABLE LO;Lo;0;R;;;;;N;;;;; +10813;CYPRIOT SYLLABLE LU;Lo;0;R;;;;;N;;;;; +10814;CYPRIOT SYLLABLE MA;Lo;0;R;;;;;N;;;;; +10815;CYPRIOT SYLLABLE ME;Lo;0;R;;;;;N;;;;; +10816;CYPRIOT SYLLABLE MI;Lo;0;R;;;;;N;;;;; +10817;CYPRIOT SYLLABLE MO;Lo;0;R;;;;;N;;;;; +10818;CYPRIOT SYLLABLE MU;Lo;0;R;;;;;N;;;;; +10819;CYPRIOT SYLLABLE NA;Lo;0;R;;;;;N;;;;; +1081A;CYPRIOT SYLLABLE NE;Lo;0;R;;;;;N;;;;; +1081B;CYPRIOT SYLLABLE NI;Lo;0;R;;;;;N;;;;; +1081C;CYPRIOT SYLLABLE NO;Lo;0;R;;;;;N;;;;; +1081D;CYPRIOT SYLLABLE NU;Lo;0;R;;;;;N;;;;; +1081E;CYPRIOT SYLLABLE PA;Lo;0;R;;;;;N;;;;; +1081F;CYPRIOT SYLLABLE PE;Lo;0;R;;;;;N;;;;; +10820;CYPRIOT SYLLABLE PI;Lo;0;R;;;;;N;;;;; +10821;CYPRIOT SYLLABLE PO;Lo;0;R;;;;;N;;;;; +10822;CYPRIOT SYLLABLE PU;Lo;0;R;;;;;N;;;;; +10823;CYPRIOT SYLLABLE RA;Lo;0;R;;;;;N;;;;; +10824;CYPRIOT SYLLABLE RE;Lo;0;R;;;;;N;;;;; +10825;CYPRIOT SYLLABLE RI;Lo;0;R;;;;;N;;;;; +10826;CYPRIOT SYLLABLE RO;Lo;0;R;;;;;N;;;;; +10827;CYPRIOT SYLLABLE RU;Lo;0;R;;;;;N;;;;; +10828;CYPRIOT SYLLABLE SA;Lo;0;R;;;;;N;;;;; +10829;CYPRIOT SYLLABLE SE;Lo;0;R;;;;;N;;;;; +1082A;CYPRIOT SYLLABLE SI;Lo;0;R;;;;;N;;;;; +1082B;CYPRIOT SYLLABLE SO;Lo;0;R;;;;;N;;;;; +1082C;CYPRIOT SYLLABLE SU;Lo;0;R;;;;;N;;;;; +1082D;CYPRIOT SYLLABLE TA;Lo;0;R;;;;;N;;;;; +1082E;CYPRIOT SYLLABLE TE;Lo;0;R;;;;;N;;;;; +1082F;CYPRIOT SYLLABLE TI;Lo;0;R;;;;;N;;;;; +10830;CYPRIOT SYLLABLE TO;Lo;0;R;;;;;N;;;;; +10831;CYPRIOT SYLLABLE TU;Lo;0;R;;;;;N;;;;; +10832;CYPRIOT SYLLABLE WA;Lo;0;R;;;;;N;;;;; +10833;CYPRIOT SYLLABLE WE;Lo;0;R;;;;;N;;;;; +10834;CYPRIOT SYLLABLE WI;Lo;0;R;;;;;N;;;;; +10835;CYPRIOT SYLLABLE WO;Lo;0;R;;;;;N;;;;; +10837;CYPRIOT SYLLABLE XA;Lo;0;R;;;;;N;;;;; +10838;CYPRIOT SYLLABLE XE;Lo;0;R;;;;;N;;;;; +1083C;CYPRIOT SYLLABLE ZA;Lo;0;R;;;;;N;;;;; +1083F;CYPRIOT SYLLABLE ZO;Lo;0;R;;;;;N;;;;; +1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;; +1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;; +1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;; +1D003;BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON;So;0;L;;;;;N;;;;; +1D004;BYZANTINE MUSICAL SYMBOL OXEIA DIPLI;So;0;L;;;;;N;;;;; +1D005;BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON;So;0;L;;;;;N;;;;; +1D006;BYZANTINE MUSICAL SYMBOL VAREIA DIPLI;So;0;L;;;;;N;;;;; +1D007;BYZANTINE MUSICAL SYMBOL KATHISTI;So;0;L;;;;;N;;;;; +1D008;BYZANTINE MUSICAL SYMBOL SYRMATIKI;So;0;L;;;;;N;;;;; +1D009;BYZANTINE MUSICAL SYMBOL PARAKLITIKI;So;0;L;;;;;N;;;;; +1D00A;BYZANTINE MUSICAL SYMBOL YPOKRISIS;So;0;L;;;;;N;;;;; +1D00B;BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI;So;0;L;;;;;N;;;;; +1D00C;BYZANTINE MUSICAL SYMBOL KREMASTI;So;0;L;;;;;N;;;;; +1D00D;BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON;So;0;L;;;;;N;;;;; +1D00E;BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON;So;0;L;;;;;N;;;;; +1D00F;BYZANTINE MUSICAL SYMBOL TELEIA;So;0;L;;;;;N;;;;; +1D010;BYZANTINE MUSICAL SYMBOL KENTIMATA;So;0;L;;;;;N;;;;; +1D011;BYZANTINE MUSICAL SYMBOL APOSTROFOS;So;0;L;;;;;N;;;;; +1D012;BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI;So;0;L;;;;;N;;;;; +1D013;BYZANTINE MUSICAL SYMBOL SYNEVMA;So;0;L;;;;;N;;;;; +1D014;BYZANTINE MUSICAL SYMBOL THITA;So;0;L;;;;;N;;;;; +1D015;BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION;So;0;L;;;;;N;;;;; +1D016;BYZANTINE MUSICAL SYMBOL GORGON ARCHAION;So;0;L;;;;;N;;;;; +1D017;BYZANTINE MUSICAL SYMBOL PSILON;So;0;L;;;;;N;;;;; +1D018;BYZANTINE MUSICAL SYMBOL CHAMILON;So;0;L;;;;;N;;;;; +1D019;BYZANTINE MUSICAL SYMBOL VATHY;So;0;L;;;;;N;;;;; +1D01A;BYZANTINE MUSICAL SYMBOL ISON ARCHAION;So;0;L;;;;;N;;;;; +1D01B;BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION;So;0;L;;;;;N;;;;; +1D01C;BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION;So;0;L;;;;;N;;;;; +1D01D;BYZANTINE MUSICAL SYMBOL SAXIMATA;So;0;L;;;;;N;;;;; +1D01E;BYZANTINE MUSICAL SYMBOL PARICHON;So;0;L;;;;;N;;;;; +1D01F;BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA;So;0;L;;;;;N;;;;; +1D020;BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION;So;0;L;;;;;N;;;;; +1D021;BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION;So;0;L;;;;;N;;;;; +1D022;BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION;So;0;L;;;;;N;;;;; +1D023;BYZANTINE MUSICAL SYMBOL APOTHEMA;So;0;L;;;;;N;;;;; +1D024;BYZANTINE MUSICAL SYMBOL KLASMA;So;0;L;;;;;N;;;;; +1D025;BYZANTINE MUSICAL SYMBOL REVMA;So;0;L;;;;;N;;;;; +1D026;BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION;So;0;L;;;;;N;;;;; +1D027;BYZANTINE MUSICAL SYMBOL TINAGMA;So;0;L;;;;;N;;;;; +1D028;BYZANTINE MUSICAL SYMBOL ANATRICHISMA;So;0;L;;;;;N;;;;; +1D029;BYZANTINE MUSICAL SYMBOL SEISMA;So;0;L;;;;;N;;;;; +1D02A;BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION;So;0;L;;;;;N;;;;; +1D02B;BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU;So;0;L;;;;;N;;;;; +1D02C;BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION;So;0;L;;;;;N;;;;; +1D02D;BYZANTINE MUSICAL SYMBOL THEMA;So;0;L;;;;;N;;;;; +1D02E;BYZANTINE MUSICAL SYMBOL LEMOI;So;0;L;;;;;N;;;;; +1D02F;BYZANTINE MUSICAL SYMBOL DYO;So;0;L;;;;;N;;;;; +1D030;BYZANTINE MUSICAL SYMBOL TRIA;So;0;L;;;;;N;;;;; +1D031;BYZANTINE MUSICAL SYMBOL TESSERA;So;0;L;;;;;N;;;;; +1D032;BYZANTINE MUSICAL SYMBOL KRATIMATA;So;0;L;;;;;N;;;;; +1D033;BYZANTINE MUSICAL SYMBOL APESO EXO NEO;So;0;L;;;;;N;;;;; +1D034;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION;So;0;L;;;;;N;;;;; +1D035;BYZANTINE MUSICAL SYMBOL IMIFTHORA;So;0;L;;;;;N;;;;; +1D036;BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION;So;0;L;;;;;N;;;;; +1D037;BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON;So;0;L;;;;;N;;;;; +1D038;BYZANTINE MUSICAL SYMBOL PELASTON;So;0;L;;;;;N;;;;; +1D039;BYZANTINE MUSICAL SYMBOL PSIFISTON;So;0;L;;;;;N;;;;; +1D03A;BYZANTINE MUSICAL SYMBOL KONTEVMA;So;0;L;;;;;N;;;;; +1D03B;BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION;So;0;L;;;;;N;;;;; +1D03C;BYZANTINE MUSICAL SYMBOL RAPISMA;So;0;L;;;;;N;;;;; +1D03D;BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION;So;0;L;;;;;N;;;;; +1D03E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION;So;0;L;;;;;N;;;;; +1D03F;BYZANTINE MUSICAL SYMBOL ICHADIN;So;0;L;;;;;N;;;;; +1D040;BYZANTINE MUSICAL SYMBOL NANA;So;0;L;;;;;N;;;;; +1D041;BYZANTINE MUSICAL SYMBOL PETASMA;So;0;L;;;;;N;;;;; +1D042;BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO;So;0;L;;;;;N;;;;; +1D043;BYZANTINE MUSICAL SYMBOL TROMIKON ALLO;So;0;L;;;;;N;;;;; +1D044;BYZANTINE MUSICAL SYMBOL STRAGGISMATA;So;0;L;;;;;N;;;;; +1D045;BYZANTINE MUSICAL SYMBOL GRONTHISMATA;So;0;L;;;;;N;;;;; +1D046;BYZANTINE MUSICAL SYMBOL ISON NEO;So;0;L;;;;;N;;;;; +1D047;BYZANTINE MUSICAL SYMBOL OLIGON NEO;So;0;L;;;;;N;;;;; +1D048;BYZANTINE MUSICAL SYMBOL OXEIA NEO;So;0;L;;;;;N;;;;; +1D049;BYZANTINE MUSICAL SYMBOL PETASTI;So;0;L;;;;;N;;;;; +1D04A;BYZANTINE MUSICAL SYMBOL KOUFISMA;So;0;L;;;;;N;;;;; +1D04B;BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA;So;0;L;;;;;N;;;;; +1D04C;BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA;So;0;L;;;;;N;;;;; +1D04D;BYZANTINE MUSICAL SYMBOL PELASTON NEO;So;0;L;;;;;N;;;;; +1D04E;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO;So;0;L;;;;;N;;;;; +1D04F;BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO;So;0;L;;;;;N;;;;; +1D050;BYZANTINE MUSICAL SYMBOL YPSILI;So;0;L;;;;;N;;;;; +1D051;BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO;So;0;L;;;;;N;;;;; +1D052;BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO;So;0;L;;;;;N;;;;; +1D053;BYZANTINE MUSICAL SYMBOL YPORROI;So;0;L;;;;;N;;;;; +1D054;BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON;So;0;L;;;;;N;;;;; +1D055;BYZANTINE MUSICAL SYMBOL ELAFRON;So;0;L;;;;;N;;;;; +1D056;BYZANTINE MUSICAL SYMBOL CHAMILI;So;0;L;;;;;N;;;;; +1D057;BYZANTINE MUSICAL SYMBOL MIKRON ISON;So;0;L;;;;;N;;;;; +1D058;BYZANTINE MUSICAL SYMBOL VAREIA NEO;So;0;L;;;;;N;;;;; +1D059;BYZANTINE MUSICAL SYMBOL PIASMA NEO;So;0;L;;;;;N;;;;; +1D05A;BYZANTINE MUSICAL SYMBOL PSIFISTON NEO;So;0;L;;;;;N;;;;; +1D05B;BYZANTINE MUSICAL SYMBOL OMALON;So;0;L;;;;;N;;;;; +1D05C;BYZANTINE MUSICAL SYMBOL ANTIKENOMA;So;0;L;;;;;N;;;;; +1D05D;BYZANTINE MUSICAL SYMBOL LYGISMA;So;0;L;;;;;N;;;;; +1D05E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO;So;0;L;;;;;N;;;;; +1D05F;BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO;So;0;L;;;;;N;;;;; +1D060;BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA;So;0;L;;;;;N;;;;; +1D061;BYZANTINE MUSICAL SYMBOL KYLISMA;So;0;L;;;;;N;;;;; +1D062;BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA;So;0;L;;;;;N;;;;; +1D063;BYZANTINE MUSICAL SYMBOL TROMIKON NEO;So;0;L;;;;;N;;;;; +1D064;BYZANTINE MUSICAL SYMBOL EKSTREPTON;So;0;L;;;;;N;;;;; +1D065;BYZANTINE MUSICAL SYMBOL SYNAGMA NEO;So;0;L;;;;;N;;;;; +1D066;BYZANTINE MUSICAL SYMBOL SYRMA;So;0;L;;;;;N;;;;; +1D067;BYZANTINE MUSICAL SYMBOL CHOREVMA NEO;So;0;L;;;;;N;;;;; +1D068;BYZANTINE MUSICAL SYMBOL EPEGERMA;So;0;L;;;;;N;;;;; +1D069;BYZANTINE MUSICAL SYMBOL SEISMA NEO;So;0;L;;;;;N;;;;; +1D06A;BYZANTINE MUSICAL SYMBOL XIRON KLASMA;So;0;L;;;;;N;;;;; +1D06B;BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON;So;0;L;;;;;N;;;;; +1D06C;BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA;So;0;L;;;;;N;;;;; +1D06D;BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA;So;0;L;;;;;N;;;;; +1D06E;BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA;So;0;L;;;;;N;;;;; +1D06F;BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA;So;0;L;;;;;N;;;;; +1D070;BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA;So;0;L;;;;;N;;;;; +1D071;BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA;So;0;L;;;;;N;;;;; +1D072;BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON;So;0;L;;;;;N;;;;; +1D073;BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON;So;0;L;;;;;N;;;;; +1D074;BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON;So;0;L;;;;;N;;;;; +1D075;BYZANTINE MUSICAL SYMBOL OYRANISMA NEO;So;0;L;;;;;N;;;;; +1D076;BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO;So;0;L;;;;;N;;;;; +1D077;BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO;So;0;L;;;;;N;;;;; +1D078;BYZANTINE MUSICAL SYMBOL THEMA APLOUN;So;0;L;;;;;N;;;;; +1D079;BYZANTINE MUSICAL SYMBOL THES KAI APOTHES;So;0;L;;;;;N;;;;; +1D07A;BYZANTINE MUSICAL SYMBOL KATAVASMA;So;0;L;;;;;N;;;;; +1D07B;BYZANTINE MUSICAL SYMBOL ENDOFONON;So;0;L;;;;;N;;;;; +1D07C;BYZANTINE MUSICAL SYMBOL YFEN KATO;So;0;L;;;;;N;;;;; +1D07D;BYZANTINE MUSICAL SYMBOL YFEN ANO;So;0;L;;;;;N;;;;; +1D07E;BYZANTINE MUSICAL SYMBOL STAVROS;So;0;L;;;;;N;;;;; +1D07F;BYZANTINE MUSICAL SYMBOL KLASMA ANO;So;0;L;;;;;N;;;;; +1D080;BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION;So;0;L;;;;;N;;;;; +1D081;BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION;So;0;L;;;;;N;;;;; +1D082;BYZANTINE MUSICAL SYMBOL KRATIMA ALLO;So;0;L;;;;;N;;;;; +1D083;BYZANTINE MUSICAL SYMBOL KRATIMA NEO;So;0;L;;;;;N;;;;; +1D084;BYZANTINE MUSICAL SYMBOL APODERMA NEO;So;0;L;;;;;N;;;;; +1D085;BYZANTINE MUSICAL SYMBOL APLI;So;0;L;;;;;N;;;;; +1D086;BYZANTINE MUSICAL SYMBOL DIPLI;So;0;L;;;;;N;;;;; +1D087;BYZANTINE MUSICAL SYMBOL TRIPLI;So;0;L;;;;;N;;;;; +1D088;BYZANTINE MUSICAL SYMBOL TETRAPLI;So;0;L;;;;;N;;;;; +1D089;BYZANTINE MUSICAL SYMBOL KORONIS;So;0;L;;;;;N;;;;; +1D08A;BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU;So;0;L;;;;;N;;;;; +1D08B;BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON;So;0;L;;;;;N;;;;; +1D08C;BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON;So;0;L;;;;;N;;;;; +1D08D;BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON;So;0;L;;;;;N;;;;; +1D08E;BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU;So;0;L;;;;;N;;;;; +1D08F;BYZANTINE MUSICAL SYMBOL GORGON NEO ANO;So;0;L;;;;;N;;;;; +1D090;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA;So;0;L;;;;;N;;;;; +1D091;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;; +1D092;BYZANTINE MUSICAL SYMBOL DIGORGON;So;0;L;;;;;N;;;;; +1D093;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO;So;0;L;;;;;N;;;;; +1D094;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO;So;0;L;;;;;N;;;;; +1D095;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;; +1D096;BYZANTINE MUSICAL SYMBOL TRIGORGON;So;0;L;;;;;N;;;;; +1D097;BYZANTINE MUSICAL SYMBOL ARGON;So;0;L;;;;;N;;;;; +1D098;BYZANTINE MUSICAL SYMBOL IMIDIARGON;So;0;L;;;;;N;;;;; +1D099;BYZANTINE MUSICAL SYMBOL DIARGON;So;0;L;;;;;N;;;;; +1D09A;BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI;So;0;L;;;;;N;;;;; +1D09B;BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI;So;0;L;;;;;N;;;;; +1D09C;BYZANTINE MUSICAL SYMBOL AGOGI ARGI;So;0;L;;;;;N;;;;; +1D09D;BYZANTINE MUSICAL SYMBOL AGOGI METRIA;So;0;L;;;;;N;;;;; +1D09E;BYZANTINE MUSICAL SYMBOL AGOGI MESI;So;0;L;;;;;N;;;;; +1D09F;BYZANTINE MUSICAL SYMBOL AGOGI GORGI;So;0;L;;;;;N;;;;; +1D0A0;BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI;So;0;L;;;;;N;;;;; +1D0A1;BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI;So;0;L;;;;;N;;;;; +1D0A2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS;So;0;L;;;;;N;;;;; +1D0A3;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS;So;0;L;;;;;N;;;;; +1D0A4;BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS;So;0;L;;;;;N;;;;; +1D0A5;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS;So;0;L;;;;;N;;;;; +1D0A6;BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS;So;0;L;;;;;N;;;;; +1D0A7;BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS;So;0;L;;;;;N;;;;; +1D0A8;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS;So;0;L;;;;;N;;;;; +1D0A9;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS;So;0;L;;;;;N;;;;; +1D0AA;BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS;So;0;L;;;;;N;;;;; +1D0AB;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS;So;0;L;;;;;N;;;;; +1D0AC;BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS;So;0;L;;;;;N;;;;; +1D0AD;BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS;So;0;L;;;;;N;;;;; +1D0AE;BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS;So;0;L;;;;;N;;;;; +1D0AF;BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS;So;0;L;;;;;N;;;;; +1D0B0;BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS;So;0;L;;;;;N;;;;; +1D0B1;BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS;So;0;L;;;;;N;;;;; +1D0B2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS;So;0;L;;;;;N;;;;; +1D0B3;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS;So;0;L;;;;;N;;;;; +1D0B4;BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN;So;0;L;;;;;N;;;;; +1D0B5;BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN;So;0;L;;;;;N;;;;; +1D0B6;BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU;So;0;L;;;;;N;;;;; +1D0B7;BYZANTINE MUSICAL SYMBOL IMIFONON;So;0;L;;;;;N;;;;; +1D0B8;BYZANTINE MUSICAL SYMBOL IMIFTHORON;So;0;L;;;;;N;;;;; +1D0B9;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU;So;0;L;;;;;N;;;;; +1D0BA;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA;So;0;L;;;;;N;;;;; +1D0BB;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA;So;0;L;;;;;N;;;;; +1D0BC;BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS;So;0;L;;;;;N;;;;; +1D0BD;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI;So;0;L;;;;;N;;;;; +1D0BE;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI;So;0;L;;;;;N;;;;; +1D0BF;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE;So;0;L;;;;;N;;;;; +1D0C0;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO;So;0;L;;;;;N;;;;; +1D0C1;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO;So;0;L;;;;;N;;;;; +1D0C2;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO;So;0;L;;;;;N;;;;; +1D0C3;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS;So;0;L;;;;;N;;;;; +1D0C4;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS;So;0;L;;;;;N;;;;; +1D0C5;BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS;So;0;L;;;;;N;;;;; +1D0C6;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI;So;0;L;;;;;N;;;;; +1D0C7;BYZANTINE MUSICAL SYMBOL FTHORA NENANO;So;0;L;;;;;N;;;;; +1D0C8;BYZANTINE MUSICAL SYMBOL CHROA ZYGOS;So;0;L;;;;;N;;;;; +1D0C9;BYZANTINE MUSICAL SYMBOL CHROA KLITON;So;0;L;;;;;N;;;;; +1D0CA;BYZANTINE MUSICAL SYMBOL CHROA SPATHI;So;0;L;;;;;N;;;;; +1D0CB;BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION;So;0;L;;;;;N;;;;; +1D0CC;BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA;So;0;L;;;;;N;;;;; +1D0CD;BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION;So;0;L;;;;;N;;;;; +1D0CE;BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION;So;0;L;;;;;N;;;;; +1D0CF;BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION;So;0;L;;;;;N;;;;; +1D0D0;BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;; +1D0D1;BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;; +1D0D2;BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;; +1D0D3;BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;; +1D0D4;BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;; +1D0D5;BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;; +1D0D6;BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;; +1D0D7;BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;; +1D0D8;BYZANTINE MUSICAL SYMBOL GENIKI DIESIS;So;0;L;;;;;N;;;;; +1D0D9;BYZANTINE MUSICAL SYMBOL GENIKI YFESIS;So;0;L;;;;;N;;;;; +1D0DA;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI;So;0;L;;;;;N;;;;; +1D0DB;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI;So;0;L;;;;;N;;;;; +1D0DC;BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI;So;0;L;;;;;N;;;;; +1D0DD;BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS;So;0;L;;;;;N;;;;; +1D0DE;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS;So;0;L;;;;;N;;;;; +1D0DF;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU;So;0;L;;;;;N;;;;; +1D0E0;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU;So;0;L;;;;;N;;;;; +1D0E1;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU;So;0;L;;;;;N;;;;; +1D0E2;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS;So;0;L;;;;;N;;;;; +1D0E3;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU;So;0;L;;;;;N;;;;; +1D0E4;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU;So;0;L;;;;;N;;;;; +1D0E5;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU;So;0;L;;;;;N;;;;; +1D0E6;BYZANTINE MUSICAL SYMBOL DIGRAMMA GG;So;0;L;;;;;N;;;;; +1D0E7;BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU;So;0;L;;;;;N;;;;; +1D0E8;BYZANTINE MUSICAL SYMBOL STIGMA;So;0;L;;;;;N;;;;; +1D0E9;BYZANTINE MUSICAL SYMBOL ARKTIKO PA;So;0;L;;;;;N;;;;; +1D0EA;BYZANTINE MUSICAL SYMBOL ARKTIKO VOU;So;0;L;;;;;N;;;;; +1D0EB;BYZANTINE MUSICAL SYMBOL ARKTIKO GA;So;0;L;;;;;N;;;;; +1D0EC;BYZANTINE MUSICAL SYMBOL ARKTIKO DI;So;0;L;;;;;N;;;;; +1D0ED;BYZANTINE MUSICAL SYMBOL ARKTIKO KE;So;0;L;;;;;N;;;;; +1D0EE;BYZANTINE MUSICAL SYMBOL ARKTIKO ZO;So;0;L;;;;;N;;;;; +1D0EF;BYZANTINE MUSICAL SYMBOL ARKTIKO NI;So;0;L;;;;;N;;;;; +1D0F0;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO;So;0;L;;;;;N;;;;; +1D0F1;BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO;So;0;L;;;;;N;;;;; +1D0F2;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO;So;0;L;;;;;N;;;;; +1D0F3;BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO;So;0;L;;;;;N;;;;; +1D0F4;BYZANTINE MUSICAL SYMBOL KLASMA KATO;So;0;L;;;;;N;;;;; +1D0F5;BYZANTINE MUSICAL SYMBOL GORGON NEO KATO;So;0;L;;;;;N;;;;; +1D100;MUSICAL SYMBOL SINGLE BARLINE;So;0;L;;;;;N;;;;; +1D101;MUSICAL SYMBOL DOUBLE BARLINE;So;0;L;;;;;N;;;;; +1D102;MUSICAL SYMBOL FINAL BARLINE;So;0;L;;;;;N;;;;; +1D103;MUSICAL SYMBOL REVERSE FINAL BARLINE;So;0;L;;;;;N;;;;; +1D104;MUSICAL SYMBOL DASHED BARLINE;So;0;L;;;;;N;;;;; +1D105;MUSICAL SYMBOL SHORT BARLINE;So;0;L;;;;;N;;;;; +1D106;MUSICAL SYMBOL LEFT REPEAT SIGN;So;0;L;;;;;N;;;;; +1D107;MUSICAL SYMBOL RIGHT REPEAT SIGN;So;0;L;;;;;N;;;;; +1D108;MUSICAL SYMBOL REPEAT DOTS;So;0;L;;;;;N;;;;; +1D109;MUSICAL SYMBOL DAL SEGNO;So;0;L;;;;;N;;;;; +1D10A;MUSICAL SYMBOL DA CAPO;So;0;L;;;;;N;;;;; +1D10B;MUSICAL SYMBOL SEGNO;So;0;L;;;;;N;;;;; +1D10C;MUSICAL SYMBOL CODA;So;0;L;;;;;N;;;;; +1D10D;MUSICAL SYMBOL REPEATED FIGURE-1;So;0;L;;;;;N;;;;; +1D10E;MUSICAL SYMBOL REPEATED FIGURE-2;So;0;L;;;;;N;;;;; +1D10F;MUSICAL SYMBOL REPEATED FIGURE-3;So;0;L;;;;;N;;;;; +1D110;MUSICAL SYMBOL FERMATA;So;0;L;;;;;N;;;;; +1D111;MUSICAL SYMBOL FERMATA BELOW;So;0;L;;;;;N;;;;; +1D112;MUSICAL SYMBOL BREATH MARK;So;0;L;;;;;N;;;;; +1D113;MUSICAL SYMBOL CAESURA;So;0;L;;;;;N;;;;; +1D114;MUSICAL SYMBOL BRACE;So;0;L;;;;;N;;;;; +1D115;MUSICAL SYMBOL BRACKET;So;0;L;;;;;N;;;;; +1D116;MUSICAL SYMBOL ONE-LINE STAFF;So;0;L;;;;;N;;;;; +1D117;MUSICAL SYMBOL TWO-LINE STAFF;So;0;L;;;;;N;;;;; +1D118;MUSICAL SYMBOL THREE-LINE STAFF;So;0;L;;;;;N;;;;; +1D119;MUSICAL SYMBOL FOUR-LINE STAFF;So;0;L;;;;;N;;;;; +1D11A;MUSICAL SYMBOL FIVE-LINE STAFF;So;0;L;;;;;N;;;;; +1D11B;MUSICAL SYMBOL SIX-LINE STAFF;So;0;L;;;;;N;;;;; +1D11C;MUSICAL SYMBOL SIX-STRING FRETBOARD;So;0;L;;;;;N;;;;; +1D11D;MUSICAL SYMBOL FOUR-STRING FRETBOARD;So;0;L;;;;;N;;;;; +1D11E;MUSICAL SYMBOL G CLEF;So;0;L;;;;;N;;;;; +1D11F;MUSICAL SYMBOL G CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;; +1D120;MUSICAL SYMBOL G CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; +1D121;MUSICAL SYMBOL C CLEF;So;0;L;;;;;N;;;;; +1D122;MUSICAL SYMBOL F CLEF;So;0;L;;;;;N;;;;; +1D123;MUSICAL SYMBOL F CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;; +1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; +1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;; +1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;; +1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;; +1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;; +1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;; +1D12D;MUSICAL SYMBOL FLAT DOWN;So;0;L;;;;;N;;;;; +1D12E;MUSICAL SYMBOL NATURAL UP;So;0;L;;;;;N;;;;; +1D12F;MUSICAL SYMBOL NATURAL DOWN;So;0;L;;;;;N;;;;; +1D130;MUSICAL SYMBOL SHARP UP;So;0;L;;;;;N;;;;; +1D131;MUSICAL SYMBOL SHARP DOWN;So;0;L;;;;;N;;;;; +1D132;MUSICAL SYMBOL QUARTER TONE SHARP;So;0;L;;;;;N;;;;; +1D133;MUSICAL SYMBOL QUARTER TONE FLAT;So;0;L;;;;;N;;;;; +1D134;MUSICAL SYMBOL COMMON TIME;So;0;L;;;;;N;;;;; +1D135;MUSICAL SYMBOL CUT TIME;So;0;L;;;;;N;;;;; +1D136;MUSICAL SYMBOL OTTAVA ALTA;So;0;L;;;;;N;;;;; +1D137;MUSICAL SYMBOL OTTAVA BASSA;So;0;L;;;;;N;;;;; +1D138;MUSICAL SYMBOL QUINDICESIMA ALTA;So;0;L;;;;;N;;;;; +1D139;MUSICAL SYMBOL QUINDICESIMA BASSA;So;0;L;;;;;N;;;;; +1D13A;MUSICAL SYMBOL MULTI REST;So;0;L;;;;;N;;;;; +1D13B;MUSICAL SYMBOL WHOLE REST;So;0;L;;;;;N;;;;; +1D13C;MUSICAL SYMBOL HALF REST;So;0;L;;;;;N;;;;; +1D13D;MUSICAL SYMBOL QUARTER REST;So;0;L;;;;;N;;;;; +1D13E;MUSICAL SYMBOL EIGHTH REST;So;0;L;;;;;N;;;;; +1D13F;MUSICAL SYMBOL SIXTEENTH REST;So;0;L;;;;;N;;;;; +1D140;MUSICAL SYMBOL THIRTY-SECOND REST;So;0;L;;;;;N;;;;; +1D141;MUSICAL SYMBOL SIXTY-FOURTH REST;So;0;L;;;;;N;;;;; +1D142;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST;So;0;L;;;;;N;;;;; +1D143;MUSICAL SYMBOL X NOTEHEAD;So;0;L;;;;;N;;;;; +1D144;MUSICAL SYMBOL PLUS NOTEHEAD;So;0;L;;;;;N;;;;; +1D145;MUSICAL SYMBOL CIRCLE X NOTEHEAD;So;0;L;;;;;N;;;;; +1D146;MUSICAL SYMBOL SQUARE NOTEHEAD WHITE;So;0;L;;;;;N;;;;; +1D147;MUSICAL SYMBOL SQUARE NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D148;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE;So;0;L;;;;;N;;;;; +1D149;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK;So;0;L;;;;;N;;;;; +1D14A;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE;So;0;L;;;;;N;;;;; +1D14B;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK;So;0;L;;;;;N;;;;; +1D14C;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE;So;0;L;;;;;N;;;;; +1D14D;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK;So;0;L;;;;;N;;;;; +1D14E;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;; +1D14F;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;; +1D150;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE;So;0;L;;;;;N;;;;; +1D151;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK;So;0;L;;;;;N;;;;; +1D152;MUSICAL SYMBOL MOON NOTEHEAD WHITE;So;0;L;;;;;N;;;;; +1D153;MUSICAL SYMBOL MOON NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D154;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;; +1D155;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;; +1D156;MUSICAL SYMBOL PARENTHESIS NOTEHEAD;So;0;L;;;;;N;;;;; +1D157;MUSICAL SYMBOL VOID NOTEHEAD;So;0;L;;;;;N;;;;; +1D158;MUSICAL SYMBOL NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D159;MUSICAL SYMBOL NULL NOTEHEAD;So;0;L;;;;;N;;;;; +1D15A;MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE;So;0;L;;;;;N;;;;; +1D15B;MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D15C;MUSICAL SYMBOL BREVE;So;0;L;;;;;N;;;;; +1D15D;MUSICAL SYMBOL WHOLE NOTE;So;0;L;;;;;N;;;;; +1D15E;MUSICAL SYMBOL HALF NOTE;So;0;L;1D157 1D165;;;;N;;;;; +1D15F;MUSICAL SYMBOL QUARTER NOTE;So;0;L;1D158 1D165;;;;N;;;;; +1D160;MUSICAL SYMBOL EIGHTH NOTE;So;0;L;1D15F 1D16E;;;;N;;;;; +1D161;MUSICAL SYMBOL SIXTEENTH NOTE;So;0;L;1D15F 1D16F;;;;N;;;;; +1D162;MUSICAL SYMBOL THIRTY-SECOND NOTE;So;0;L;1D15F 1D170;;;;N;;;;; +1D163;MUSICAL SYMBOL SIXTY-FOURTH NOTE;So;0;L;1D15F 1D171;;;;N;;;;; +1D164;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE;So;0;L;1D15F 1D172;;;;N;;;;; +1D165;MUSICAL SYMBOL COMBINING STEM;Mc;216;L;;;;;N;;;;; +1D166;MUSICAL SYMBOL COMBINING SPRECHGESANG STEM;Mc;216;L;;;;;N;;;;; +1D167;MUSICAL SYMBOL COMBINING TREMOLO-1;Mn;1;NSM;;;;;N;;;;; +1D168;MUSICAL SYMBOL COMBINING TREMOLO-2;Mn;1;NSM;;;;;N;;;;; +1D169;MUSICAL SYMBOL COMBINING TREMOLO-3;Mn;1;NSM;;;;;N;;;;; +1D16A;MUSICAL SYMBOL FINGERED TREMOLO-1;So;0;L;;;;;N;;;;; +1D16B;MUSICAL SYMBOL FINGERED TREMOLO-2;So;0;L;;;;;N;;;;; +1D16C;MUSICAL SYMBOL FINGERED TREMOLO-3;So;0;L;;;;;N;;;;; +1D16D;MUSICAL SYMBOL COMBINING AUGMENTATION DOT;Mc;226;L;;;;;N;;;;; +1D16E;MUSICAL SYMBOL COMBINING FLAG-1;Mc;216;L;;;;;N;;;;; +1D16F;MUSICAL SYMBOL COMBINING FLAG-2;Mc;216;L;;;;;N;;;;; +1D170;MUSICAL SYMBOL COMBINING FLAG-3;Mc;216;L;;;;;N;;;;; +1D171;MUSICAL SYMBOL COMBINING FLAG-4;Mc;216;L;;;;;N;;;;; +1D172;MUSICAL SYMBOL COMBINING FLAG-5;Mc;216;L;;;;;N;;;;; +1D173;MUSICAL SYMBOL BEGIN BEAM;Cf;0;BN;;;;;N;;;;; +1D174;MUSICAL SYMBOL END BEAM;Cf;0;BN;;;;;N;;;;; +1D175;MUSICAL SYMBOL BEGIN TIE;Cf;0;BN;;;;;N;;;;; +1D176;MUSICAL SYMBOL END TIE;Cf;0;BN;;;;;N;;;;; +1D177;MUSICAL SYMBOL BEGIN SLUR;Cf;0;BN;;;;;N;;;;; +1D178;MUSICAL SYMBOL END SLUR;Cf;0;BN;;;;;N;;;;; +1D179;MUSICAL SYMBOL BEGIN PHRASE;Cf;0;BN;;;;;N;;;;; +1D17A;MUSICAL SYMBOL END PHRASE;Cf;0;BN;;;;;N;;;;; +1D17B;MUSICAL SYMBOL COMBINING ACCENT;Mn;220;NSM;;;;;N;;;;; +1D17C;MUSICAL SYMBOL COMBINING STACCATO;Mn;220;NSM;;;;;N;;;;; +1D17D;MUSICAL SYMBOL COMBINING TENUTO;Mn;220;NSM;;;;;N;;;;; +1D17E;MUSICAL SYMBOL COMBINING STACCATISSIMO;Mn;220;NSM;;;;;N;;;;; +1D17F;MUSICAL SYMBOL COMBINING MARCATO;Mn;220;NSM;;;;;N;;;;; +1D180;MUSICAL SYMBOL COMBINING MARCATO-STACCATO;Mn;220;NSM;;;;;N;;;;; +1D181;MUSICAL SYMBOL COMBINING ACCENT-STACCATO;Mn;220;NSM;;;;;N;;;;; +1D182;MUSICAL SYMBOL COMBINING LOURE;Mn;220;NSM;;;;;N;;;;; +1D183;MUSICAL SYMBOL ARPEGGIATO UP;So;0;L;;;;;N;;;;; +1D184;MUSICAL SYMBOL ARPEGGIATO DOWN;So;0;L;;;;;N;;;;; +1D185;MUSICAL SYMBOL COMBINING DOIT;Mn;230;NSM;;;;;N;;;;; +1D186;MUSICAL SYMBOL COMBINING RIP;Mn;230;NSM;;;;;N;;;;; +1D187;MUSICAL SYMBOL COMBINING FLIP;Mn;230;NSM;;;;;N;;;;; +1D188;MUSICAL SYMBOL COMBINING SMEAR;Mn;230;NSM;;;;;N;;;;; +1D189;MUSICAL SYMBOL COMBINING BEND;Mn;230;NSM;;;;;N;;;;; +1D18A;MUSICAL SYMBOL COMBINING DOUBLE TONGUE;Mn;220;NSM;;;;;N;;;;; +1D18B;MUSICAL SYMBOL COMBINING TRIPLE TONGUE;Mn;220;NSM;;;;;N;;;;; +1D18C;MUSICAL SYMBOL RINFORZANDO;So;0;L;;;;;N;;;;; +1D18D;MUSICAL SYMBOL SUBITO;So;0;L;;;;;N;;;;; +1D18E;MUSICAL SYMBOL Z;So;0;L;;;;;N;;;;; +1D18F;MUSICAL SYMBOL PIANO;So;0;L;;;;;N;;;;; +1D190;MUSICAL SYMBOL MEZZO;So;0;L;;;;;N;;;;; +1D191;MUSICAL SYMBOL FORTE;So;0;L;;;;;N;;;;; +1D192;MUSICAL SYMBOL CRESCENDO;So;0;L;;;;;N;;;;; +1D193;MUSICAL SYMBOL DECRESCENDO;So;0;L;;;;;N;;;;; +1D194;MUSICAL SYMBOL GRACE NOTE SLASH;So;0;L;;;;;N;;;;; +1D195;MUSICAL SYMBOL GRACE NOTE NO SLASH;So;0;L;;;;;N;;;;; +1D196;MUSICAL SYMBOL TR;So;0;L;;;;;N;;;;; +1D197;MUSICAL SYMBOL TURN;So;0;L;;;;;N;;;;; +1D198;MUSICAL SYMBOL INVERTED TURN;So;0;L;;;;;N;;;;; +1D199;MUSICAL SYMBOL TURN SLASH;So;0;L;;;;;N;;;;; +1D19A;MUSICAL SYMBOL TURN UP;So;0;L;;;;;N;;;;; +1D19B;MUSICAL SYMBOL ORNAMENT STROKE-1;So;0;L;;;;;N;;;;; +1D19C;MUSICAL SYMBOL ORNAMENT STROKE-2;So;0;L;;;;;N;;;;; +1D19D;MUSICAL SYMBOL ORNAMENT STROKE-3;So;0;L;;;;;N;;;;; +1D19E;MUSICAL SYMBOL ORNAMENT STROKE-4;So;0;L;;;;;N;;;;; +1D19F;MUSICAL SYMBOL ORNAMENT STROKE-5;So;0;L;;;;;N;;;;; +1D1A0;MUSICAL SYMBOL ORNAMENT STROKE-6;So;0;L;;;;;N;;;;; +1D1A1;MUSICAL SYMBOL ORNAMENT STROKE-7;So;0;L;;;;;N;;;;; +1D1A2;MUSICAL SYMBOL ORNAMENT STROKE-8;So;0;L;;;;;N;;;;; +1D1A3;MUSICAL SYMBOL ORNAMENT STROKE-9;So;0;L;;;;;N;;;;; +1D1A4;MUSICAL SYMBOL ORNAMENT STROKE-10;So;0;L;;;;;N;;;;; +1D1A5;MUSICAL SYMBOL ORNAMENT STROKE-11;So;0;L;;;;;N;;;;; +1D1A6;MUSICAL SYMBOL HAUPTSTIMME;So;0;L;;;;;N;;;;; +1D1A7;MUSICAL SYMBOL NEBENSTIMME;So;0;L;;;;;N;;;;; +1D1A8;MUSICAL SYMBOL END OF STIMME;So;0;L;;;;;N;;;;; +1D1A9;MUSICAL SYMBOL DEGREE SLASH;So;0;L;;;;;N;;;;; +1D1AA;MUSICAL SYMBOL COMBINING DOWN BOW;Mn;230;NSM;;;;;N;;;;; +1D1AB;MUSICAL SYMBOL COMBINING UP BOW;Mn;230;NSM;;;;;N;;;;; +1D1AC;MUSICAL SYMBOL COMBINING HARMONIC;Mn;230;NSM;;;;;N;;;;; +1D1AD;MUSICAL SYMBOL COMBINING SNAP PIZZICATO;Mn;230;NSM;;;;;N;;;;; +1D1AE;MUSICAL SYMBOL PEDAL MARK;So;0;L;;;;;N;;;;; +1D1AF;MUSICAL SYMBOL PEDAL UP MARK;So;0;L;;;;;N;;;;; +1D1B0;MUSICAL SYMBOL HALF PEDAL MARK;So;0;L;;;;;N;;;;; +1D1B1;MUSICAL SYMBOL GLISSANDO UP;So;0;L;;;;;N;;;;; +1D1B2;MUSICAL SYMBOL GLISSANDO DOWN;So;0;L;;;;;N;;;;; +1D1B3;MUSICAL SYMBOL WITH FINGERNAILS;So;0;L;;;;;N;;;;; +1D1B4;MUSICAL SYMBOL DAMP;So;0;L;;;;;N;;;;; +1D1B5;MUSICAL SYMBOL DAMP ALL;So;0;L;;;;;N;;;;; +1D1B6;MUSICAL SYMBOL MAXIMA;So;0;L;;;;;N;;;;; +1D1B7;MUSICAL SYMBOL LONGA;So;0;L;;;;;N;;;;; +1D1B8;MUSICAL SYMBOL BREVIS;So;0;L;;;;;N;;;;; +1D1B9;MUSICAL SYMBOL SEMIBREVIS WHITE;So;0;L;;;;;N;;;;; +1D1BA;MUSICAL SYMBOL SEMIBREVIS BLACK;So;0;L;;;;;N;;;;; +1D1BB;MUSICAL SYMBOL MINIMA;So;0;L;1D1B9 1D165;;;;N;;;;; +1D1BC;MUSICAL SYMBOL MINIMA BLACK;So;0;L;1D1BA 1D165;;;;N;;;;; +1D1BD;MUSICAL SYMBOL SEMIMINIMA WHITE;So;0;L;1D1BB 1D16E;;;;N;;;;; +1D1BE;MUSICAL SYMBOL SEMIMINIMA BLACK;So;0;L;1D1BC 1D16E;;;;N;;;;; +1D1BF;MUSICAL SYMBOL FUSA WHITE;So;0;L;1D1BB 1D16F;;;;N;;;;; +1D1C0;MUSICAL SYMBOL FUSA BLACK;So;0;L;1D1BC 1D16F;;;;N;;;;; +1D1C1;MUSICAL SYMBOL LONGA PERFECTA REST;So;0;L;;;;;N;;;;; +1D1C2;MUSICAL SYMBOL LONGA IMPERFECTA REST;So;0;L;;;;;N;;;;; +1D1C3;MUSICAL SYMBOL BREVIS REST;So;0;L;;;;;N;;;;; +1D1C4;MUSICAL SYMBOL SEMIBREVIS REST;So;0;L;;;;;N;;;;; +1D1C5;MUSICAL SYMBOL MINIMA REST;So;0;L;;;;;N;;;;; +1D1C6;MUSICAL SYMBOL SEMIMINIMA REST;So;0;L;;;;;N;;;;; +1D1C7;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;; +1D1C8;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;; +1D1C9;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;; +1D1CA;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;; +1D1CB;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;; +1D1CC;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;; +1D1CD;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2;So;0;L;;;;;N;;;;; +1D1CE;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3;So;0;L;;;;;N;;;;; +1D1CF;MUSICAL SYMBOL CROIX;So;0;L;;;;;N;;;;; +1D1D0;MUSICAL SYMBOL GREGORIAN C CLEF;So;0;L;;;;;N;;;;; +1D1D1;MUSICAL SYMBOL GREGORIAN F CLEF;So;0;L;;;;;N;;;;; +1D1D2;MUSICAL SYMBOL SQUARE B;So;0;L;;;;;N;;;;; +1D1D3;MUSICAL SYMBOL VIRGA;So;0;L;;;;;N;;;;; +1D1D4;MUSICAL SYMBOL PODATUS;So;0;L;;;;;N;;;;; +1D1D5;MUSICAL SYMBOL CLIVIS;So;0;L;;;;;N;;;;; +1D1D6;MUSICAL SYMBOL SCANDICUS;So;0;L;;;;;N;;;;; +1D1D7;MUSICAL SYMBOL CLIMACUS;So;0;L;;;;;N;;;;; +1D1D8;MUSICAL SYMBOL TORCULUS;So;0;L;;;;;N;;;;; +1D1D9;MUSICAL SYMBOL PORRECTUS;So;0;L;;;;;N;;;;; +1D1DA;MUSICAL SYMBOL PORRECTUS FLEXUS;So;0;L;;;;;N;;;;; +1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;; +1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;; +1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;; +1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;; +1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;; +1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;; +1D303;DIGRAM FOR EARTHLY HEAVEN;So;0;ON;;;;;N;;;;; +1D304;DIGRAM FOR EARTHLY HUMAN;So;0;ON;;;;;N;;;;; +1D305;DIGRAM FOR EARTH;So;0;ON;;;;;N;;;;; +1D306;TETRAGRAM FOR CENTRE;So;0;ON;;;;;N;;;;; +1D307;TETRAGRAM FOR FULL CIRCLE;So;0;ON;;;;;N;;;;; +1D308;TETRAGRAM FOR MIRED;So;0;ON;;;;;N;;;;; +1D309;TETRAGRAM FOR BARRIER;So;0;ON;;;;;N;;;;; +1D30A;TETRAGRAM FOR KEEPING SMALL;So;0;ON;;;;;N;;;;; +1D30B;TETRAGRAM FOR CONTRARIETY;So;0;ON;;;;;N;;;;; +1D30C;TETRAGRAM FOR ASCENT;So;0;ON;;;;;N;;;;; +1D30D;TETRAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;; +1D30E;TETRAGRAM FOR BRANCHING OUT;So;0;ON;;;;;N;;;;; +1D30F;TETRAGRAM FOR DEFECTIVENESS OR DISTORTION;So;0;ON;;;;;N;;;;; +1D310;TETRAGRAM FOR DIVERGENCE;So;0;ON;;;;;N;;;;; +1D311;TETRAGRAM FOR YOUTHFULNESS;So;0;ON;;;;;N;;;;; +1D312;TETRAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;; +1D313;TETRAGRAM FOR PENETRATION;So;0;ON;;;;;N;;;;; +1D314;TETRAGRAM FOR REACH;So;0;ON;;;;;N;;;;; +1D315;TETRAGRAM FOR CONTACT;So;0;ON;;;;;N;;;;; +1D316;TETRAGRAM FOR HOLDING BACK;So;0;ON;;;;;N;;;;; +1D317;TETRAGRAM FOR WAITING;So;0;ON;;;;;N;;;;; +1D318;TETRAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;; +1D319;TETRAGRAM FOR ADVANCE;So;0;ON;;;;;N;;;;; +1D31A;TETRAGRAM FOR RELEASE;So;0;ON;;;;;N;;;;; +1D31B;TETRAGRAM FOR RESISTANCE;So;0;ON;;;;;N;;;;; +1D31C;TETRAGRAM FOR EASE;So;0;ON;;;;;N;;;;; +1D31D;TETRAGRAM FOR JOY;So;0;ON;;;;;N;;;;; +1D31E;TETRAGRAM FOR CONTENTION;So;0;ON;;;;;N;;;;; +1D31F;TETRAGRAM FOR ENDEAVOUR;So;0;ON;;;;;N;;;;; +1D320;TETRAGRAM FOR DUTIES;So;0;ON;;;;;N;;;;; +1D321;TETRAGRAM FOR CHANGE;So;0;ON;;;;;N;;;;; +1D322;TETRAGRAM FOR DECISIVENESS;So;0;ON;;;;;N;;;;; +1D323;TETRAGRAM FOR BOLD RESOLUTION;So;0;ON;;;;;N;;;;; +1D324;TETRAGRAM FOR PACKING;So;0;ON;;;;;N;;;;; +1D325;TETRAGRAM FOR LEGION;So;0;ON;;;;;N;;;;; +1D326;TETRAGRAM FOR CLOSENESS;So;0;ON;;;;;N;;;;; +1D327;TETRAGRAM FOR KINSHIP;So;0;ON;;;;;N;;;;; +1D328;TETRAGRAM FOR GATHERING;So;0;ON;;;;;N;;;;; +1D329;TETRAGRAM FOR STRENGTH;So;0;ON;;;;;N;;;;; +1D32A;TETRAGRAM FOR PURITY;So;0;ON;;;;;N;;;;; +1D32B;TETRAGRAM FOR FULLNESS;So;0;ON;;;;;N;;;;; +1D32C;TETRAGRAM FOR RESIDENCE;So;0;ON;;;;;N;;;;; +1D32D;TETRAGRAM FOR LAW OR MODEL;So;0;ON;;;;;N;;;;; +1D32E;TETRAGRAM FOR RESPONSE;So;0;ON;;;;;N;;;;; +1D32F;TETRAGRAM FOR GOING TO MEET;So;0;ON;;;;;N;;;;; +1D330;TETRAGRAM FOR ENCOUNTERS;So;0;ON;;;;;N;;;;; +1D331;TETRAGRAM FOR STOVE;So;0;ON;;;;;N;;;;; +1D332;TETRAGRAM FOR GREATNESS;So;0;ON;;;;;N;;;;; +1D333;TETRAGRAM FOR ENLARGEMENT;So;0;ON;;;;;N;;;;; +1D334;TETRAGRAM FOR PATTERN;So;0;ON;;;;;N;;;;; +1D335;TETRAGRAM FOR RITUAL;So;0;ON;;;;;N;;;;; +1D336;TETRAGRAM FOR FLIGHT;So;0;ON;;;;;N;;;;; +1D337;TETRAGRAM FOR VASTNESS OR WASTING;So;0;ON;;;;;N;;;;; +1D338;TETRAGRAM FOR CONSTANCY;So;0;ON;;;;;N;;;;; +1D339;TETRAGRAM FOR MEASURE;So;0;ON;;;;;N;;;;; +1D33A;TETRAGRAM FOR ETERNITY;So;0;ON;;;;;N;;;;; +1D33B;TETRAGRAM FOR UNITY;So;0;ON;;;;;N;;;;; +1D33C;TETRAGRAM FOR DIMINISHMENT;So;0;ON;;;;;N;;;;; +1D33D;TETRAGRAM FOR CLOSED MOUTH;So;0;ON;;;;;N;;;;; +1D33E;TETRAGRAM FOR GUARDEDNESS;So;0;ON;;;;;N;;;;; +1D33F;TETRAGRAM FOR GATHERING IN;So;0;ON;;;;;N;;;;; +1D340;TETRAGRAM FOR MASSING;So;0;ON;;;;;N;;;;; +1D341;TETRAGRAM FOR ACCUMULATION;So;0;ON;;;;;N;;;;; +1D342;TETRAGRAM FOR EMBELLISHMENT;So;0;ON;;;;;N;;;;; +1D343;TETRAGRAM FOR DOUBT;So;0;ON;;;;;N;;;;; +1D344;TETRAGRAM FOR WATCH;So;0;ON;;;;;N;;;;; +1D345;TETRAGRAM FOR SINKING;So;0;ON;;;;;N;;;;; +1D346;TETRAGRAM FOR INNER;So;0;ON;;;;;N;;;;; +1D347;TETRAGRAM FOR DEPARTURE;So;0;ON;;;;;N;;;;; +1D348;TETRAGRAM FOR DARKENING;So;0;ON;;;;;N;;;;; +1D349;TETRAGRAM FOR DIMMING;So;0;ON;;;;;N;;;;; +1D34A;TETRAGRAM FOR EXHAUSTION;So;0;ON;;;;;N;;;;; +1D34B;TETRAGRAM FOR SEVERANCE;So;0;ON;;;;;N;;;;; +1D34C;TETRAGRAM FOR STOPPAGE;So;0;ON;;;;;N;;;;; +1D34D;TETRAGRAM FOR HARDNESS;So;0;ON;;;;;N;;;;; +1D34E;TETRAGRAM FOR COMPLETION;So;0;ON;;;;;N;;;;; +1D34F;TETRAGRAM FOR CLOSURE;So;0;ON;;;;;N;;;;; +1D350;TETRAGRAM FOR FAILURE;So;0;ON;;;;;N;;;;; +1D351;TETRAGRAM FOR AGGRAVATION;So;0;ON;;;;;N;;;;; +1D352;TETRAGRAM FOR COMPLIANCE;So;0;ON;;;;;N;;;;; +1D353;TETRAGRAM FOR ON THE VERGE;So;0;ON;;;;;N;;;;; +1D354;TETRAGRAM FOR DIFFICULTIES;So;0;ON;;;;;N;;;;; +1D355;TETRAGRAM FOR LABOURING;So;0;ON;;;;;N;;;;; +1D356;TETRAGRAM FOR FOSTERING;So;0;ON;;;;;N;;;;; +1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D403;MATHEMATICAL BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D404;MATHEMATICAL BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D405;MATHEMATICAL BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D406;MATHEMATICAL BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D407;MATHEMATICAL BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; +1D408;MATHEMATICAL BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D409;MATHEMATICAL BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D40A;MATHEMATICAL BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D40B;MATHEMATICAL BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D40C;MATHEMATICAL BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D40D;MATHEMATICAL BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D40E;MATHEMATICAL BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D40F;MATHEMATICAL BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D410;MATHEMATICAL BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D411;MATHEMATICAL BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; +1D412;MATHEMATICAL BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D413;MATHEMATICAL BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D414;MATHEMATICAL BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D415;MATHEMATICAL BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D416;MATHEMATICAL BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D417;MATHEMATICAL BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D418;MATHEMATICAL BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D419;MATHEMATICAL BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D41A;MATHEMATICAL BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D41B;MATHEMATICAL BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D41C;MATHEMATICAL BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D41D;MATHEMATICAL BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D41E;MATHEMATICAL BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D41F;MATHEMATICAL BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D420;MATHEMATICAL BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D421;MATHEMATICAL BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D422;MATHEMATICAL BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D423;MATHEMATICAL BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D424;MATHEMATICAL BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D425;MATHEMATICAL BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D426;MATHEMATICAL BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D427;MATHEMATICAL BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D428;MATHEMATICAL BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D429;MATHEMATICAL BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D42A;MATHEMATICAL BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D42B;MATHEMATICAL BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D42C;MATHEMATICAL BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D42D;MATHEMATICAL BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D42E;MATHEMATICAL BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D42F;MATHEMATICAL BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D430;MATHEMATICAL BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D431;MATHEMATICAL BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D432;MATHEMATICAL BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D433;MATHEMATICAL BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D434;MATHEMATICAL ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D435;MATHEMATICAL ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D436;MATHEMATICAL ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D437;MATHEMATICAL ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D438;MATHEMATICAL ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D439;MATHEMATICAL ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D43A;MATHEMATICAL ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D43B;MATHEMATICAL ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; +1D43C;MATHEMATICAL ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D43D;MATHEMATICAL ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D43E;MATHEMATICAL ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D43F;MATHEMATICAL ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D440;MATHEMATICAL ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D441;MATHEMATICAL ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D442;MATHEMATICAL ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D443;MATHEMATICAL ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D444;MATHEMATICAL ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D445;MATHEMATICAL ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; +1D446;MATHEMATICAL ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D447;MATHEMATICAL ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D448;MATHEMATICAL ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D449;MATHEMATICAL ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D44A;MATHEMATICAL ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D44B;MATHEMATICAL ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D44C;MATHEMATICAL ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D44D;MATHEMATICAL ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D44E;MATHEMATICAL ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D44F;MATHEMATICAL ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D450;MATHEMATICAL ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D451;MATHEMATICAL ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D452;MATHEMATICAL ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D453;MATHEMATICAL ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D454;MATHEMATICAL ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D456;MATHEMATICAL ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D457;MATHEMATICAL ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D458;MATHEMATICAL ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D459;MATHEMATICAL ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D45A;MATHEMATICAL ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D45B;MATHEMATICAL ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D45C;MATHEMATICAL ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D45D;MATHEMATICAL ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D45E;MATHEMATICAL ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D45F;MATHEMATICAL ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D460;MATHEMATICAL ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D461;MATHEMATICAL ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D462;MATHEMATICAL ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D463;MATHEMATICAL ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D464;MATHEMATICAL ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D465;MATHEMATICAL ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D466;MATHEMATICAL ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D467;MATHEMATICAL ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D468;MATHEMATICAL BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D469;MATHEMATICAL BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D46A;MATHEMATICAL BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D46B;MATHEMATICAL BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D46C;MATHEMATICAL BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D46D;MATHEMATICAL BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D46E;MATHEMATICAL BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D46F;MATHEMATICAL BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; +1D470;MATHEMATICAL BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D471;MATHEMATICAL BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D472;MATHEMATICAL BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D473;MATHEMATICAL BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D474;MATHEMATICAL BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D475;MATHEMATICAL BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D476;MATHEMATICAL BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D477;MATHEMATICAL BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D478;MATHEMATICAL BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D479;MATHEMATICAL BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; +1D47A;MATHEMATICAL BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D47B;MATHEMATICAL BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D47C;MATHEMATICAL BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D47D;MATHEMATICAL BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D47E;MATHEMATICAL BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D47F;MATHEMATICAL BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D480;MATHEMATICAL BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D481;MATHEMATICAL BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D482;MATHEMATICAL BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D483;MATHEMATICAL BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D484;MATHEMATICAL BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D485;MATHEMATICAL BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D486;MATHEMATICAL BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D487;MATHEMATICAL BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D488;MATHEMATICAL BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D489;MATHEMATICAL BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D48A;MATHEMATICAL BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D48B;MATHEMATICAL BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D48C;MATHEMATICAL BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D48D;MATHEMATICAL BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D48E;MATHEMATICAL BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D48F;MATHEMATICAL BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D490;MATHEMATICAL BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D491;MATHEMATICAL BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D492;MATHEMATICAL BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D493;MATHEMATICAL BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D494;MATHEMATICAL BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D495;MATHEMATICAL BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D496;MATHEMATICAL BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D497;MATHEMATICAL BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D498;MATHEMATICAL BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D499;MATHEMATICAL BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D49A;MATHEMATICAL BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D49B;MATHEMATICAL BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D49C;MATHEMATICAL SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D49E;MATHEMATICAL SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D49F;MATHEMATICAL SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D4A2;MATHEMATICAL SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D4A5;MATHEMATICAL SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D4A6;MATHEMATICAL SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D4A9;MATHEMATICAL SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D4AA;MATHEMATICAL SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D4AB;MATHEMATICAL SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D4AC;MATHEMATICAL SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D4AE;MATHEMATICAL SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D4AF;MATHEMATICAL SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D4B0;MATHEMATICAL SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D4B1;MATHEMATICAL SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D4B2;MATHEMATICAL SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D4B3;MATHEMATICAL SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D4B4;MATHEMATICAL SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D4B5;MATHEMATICAL SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D4B6;MATHEMATICAL SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D4B7;MATHEMATICAL SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D4B8;MATHEMATICAL SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D4B9;MATHEMATICAL SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D4BB;MATHEMATICAL SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D4BD;MATHEMATICAL SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D4BE;MATHEMATICAL SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D4BF;MATHEMATICAL SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D4C0;MATHEMATICAL SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D4C1;MATHEMATICAL SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D4C2;MATHEMATICAL SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D4C3;MATHEMATICAL SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D4C5;MATHEMATICAL SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D4C6;MATHEMATICAL SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D4C7;MATHEMATICAL SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D4C8;MATHEMATICAL SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D4C9;MATHEMATICAL SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D4CA;MATHEMATICAL SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D4CB;MATHEMATICAL SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D4CC;MATHEMATICAL SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D4CD;MATHEMATICAL SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D4CE;MATHEMATICAL SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D4CF;MATHEMATICAL SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D4D0;MATHEMATICAL BOLD SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D4D1;MATHEMATICAL BOLD SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D4D2;MATHEMATICAL BOLD SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D4D3;MATHEMATICAL BOLD SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D4D4;MATHEMATICAL BOLD SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D4D5;MATHEMATICAL BOLD SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D4D6;MATHEMATICAL BOLD SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D4D7;MATHEMATICAL BOLD SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; +1D4D8;MATHEMATICAL BOLD SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D4D9;MATHEMATICAL BOLD SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D4DA;MATHEMATICAL BOLD SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D4DB;MATHEMATICAL BOLD SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D4DC;MATHEMATICAL BOLD SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D4DD;MATHEMATICAL BOLD SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D4DE;MATHEMATICAL BOLD SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D4DF;MATHEMATICAL BOLD SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D4E0;MATHEMATICAL BOLD SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D4E1;MATHEMATICAL BOLD SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; +1D4E2;MATHEMATICAL BOLD SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D4E3;MATHEMATICAL BOLD SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D4E4;MATHEMATICAL BOLD SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D4E5;MATHEMATICAL BOLD SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D4E6;MATHEMATICAL BOLD SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D4E7;MATHEMATICAL BOLD SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D4E8;MATHEMATICAL BOLD SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D4E9;MATHEMATICAL BOLD SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D4EA;MATHEMATICAL BOLD SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D4EB;MATHEMATICAL BOLD SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D4EC;MATHEMATICAL BOLD SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D4ED;MATHEMATICAL BOLD SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D4EE;MATHEMATICAL BOLD SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D4EF;MATHEMATICAL BOLD SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D4F0;MATHEMATICAL BOLD SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D4F1;MATHEMATICAL BOLD SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D4F2;MATHEMATICAL BOLD SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D4F3;MATHEMATICAL BOLD SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D4F4;MATHEMATICAL BOLD SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D4F5;MATHEMATICAL BOLD SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D4F6;MATHEMATICAL BOLD SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D4F7;MATHEMATICAL BOLD SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D4F8;MATHEMATICAL BOLD SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D4F9;MATHEMATICAL BOLD SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D4FA;MATHEMATICAL BOLD SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D4FB;MATHEMATICAL BOLD SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D4FC;MATHEMATICAL BOLD SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D4FD;MATHEMATICAL BOLD SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D4FE;MATHEMATICAL BOLD SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D4FF;MATHEMATICAL BOLD SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D500;MATHEMATICAL BOLD SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D501;MATHEMATICAL BOLD SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D502;MATHEMATICAL BOLD SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D503;MATHEMATICAL BOLD SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D504;MATHEMATICAL FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D505;MATHEMATICAL FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D507;MATHEMATICAL FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D508;MATHEMATICAL FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D509;MATHEMATICAL FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D50A;MATHEMATICAL FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D50D;MATHEMATICAL FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D50E;MATHEMATICAL FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D50F;MATHEMATICAL FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D510;MATHEMATICAL FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D511;MATHEMATICAL FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D512;MATHEMATICAL FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D513;MATHEMATICAL FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D514;MATHEMATICAL FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D516;MATHEMATICAL FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D517;MATHEMATICAL FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D518;MATHEMATICAL FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D519;MATHEMATICAL FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D51A;MATHEMATICAL FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D51B;MATHEMATICAL FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D51C;MATHEMATICAL FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D51E;MATHEMATICAL FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D51F;MATHEMATICAL FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D520;MATHEMATICAL FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D521;MATHEMATICAL FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D522;MATHEMATICAL FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D523;MATHEMATICAL FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D524;MATHEMATICAL FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D525;MATHEMATICAL FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D526;MATHEMATICAL FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D527;MATHEMATICAL FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D528;MATHEMATICAL FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D529;MATHEMATICAL FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D52A;MATHEMATICAL FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D52B;MATHEMATICAL FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D52C;MATHEMATICAL FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D52D;MATHEMATICAL FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D52E;MATHEMATICAL FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D52F;MATHEMATICAL FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D530;MATHEMATICAL FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D531;MATHEMATICAL FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D532;MATHEMATICAL FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D533;MATHEMATICAL FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D534;MATHEMATICAL FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D535;MATHEMATICAL FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D536;MATHEMATICAL FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D537;MATHEMATICAL FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D538;MATHEMATICAL DOUBLE-STRUCK CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D539;MATHEMATICAL DOUBLE-STRUCK CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D53B;MATHEMATICAL DOUBLE-STRUCK CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D53C;MATHEMATICAL DOUBLE-STRUCK CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D53D;MATHEMATICAL DOUBLE-STRUCK CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D53E;MATHEMATICAL DOUBLE-STRUCK CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D540;MATHEMATICAL DOUBLE-STRUCK CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D541;MATHEMATICAL DOUBLE-STRUCK CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D542;MATHEMATICAL DOUBLE-STRUCK CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D543;MATHEMATICAL DOUBLE-STRUCK CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D544;MATHEMATICAL DOUBLE-STRUCK CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D546;MATHEMATICAL DOUBLE-STRUCK CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D54A;MATHEMATICAL DOUBLE-STRUCK CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D54B;MATHEMATICAL DOUBLE-STRUCK CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D54C;MATHEMATICAL DOUBLE-STRUCK CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D54D;MATHEMATICAL DOUBLE-STRUCK CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D54E;MATHEMATICAL DOUBLE-STRUCK CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D54F;MATHEMATICAL DOUBLE-STRUCK CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D550;MATHEMATICAL DOUBLE-STRUCK CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D552;MATHEMATICAL DOUBLE-STRUCK SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D553;MATHEMATICAL DOUBLE-STRUCK SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D554;MATHEMATICAL DOUBLE-STRUCK SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D555;MATHEMATICAL DOUBLE-STRUCK SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D556;MATHEMATICAL DOUBLE-STRUCK SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D557;MATHEMATICAL DOUBLE-STRUCK SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D558;MATHEMATICAL DOUBLE-STRUCK SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D559;MATHEMATICAL DOUBLE-STRUCK SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D55A;MATHEMATICAL DOUBLE-STRUCK SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D55B;MATHEMATICAL DOUBLE-STRUCK SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D55C;MATHEMATICAL DOUBLE-STRUCK SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D55D;MATHEMATICAL DOUBLE-STRUCK SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D55E;MATHEMATICAL DOUBLE-STRUCK SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D55F;MATHEMATICAL DOUBLE-STRUCK SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D560;MATHEMATICAL DOUBLE-STRUCK SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D561;MATHEMATICAL DOUBLE-STRUCK SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D562;MATHEMATICAL DOUBLE-STRUCK SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D563;MATHEMATICAL DOUBLE-STRUCK SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D564;MATHEMATICAL DOUBLE-STRUCK SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D565;MATHEMATICAL DOUBLE-STRUCK SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D566;MATHEMATICAL DOUBLE-STRUCK SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D567;MATHEMATICAL DOUBLE-STRUCK SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D568;MATHEMATICAL DOUBLE-STRUCK SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D569;MATHEMATICAL DOUBLE-STRUCK SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D56A;MATHEMATICAL DOUBLE-STRUCK SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D56B;MATHEMATICAL DOUBLE-STRUCK SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D56C;MATHEMATICAL BOLD FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D56D;MATHEMATICAL BOLD FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D56E;MATHEMATICAL BOLD FRAKTUR CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D56F;MATHEMATICAL BOLD FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D570;MATHEMATICAL BOLD FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D571;MATHEMATICAL BOLD FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D572;MATHEMATICAL BOLD FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D573;MATHEMATICAL BOLD FRAKTUR CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; +1D574;MATHEMATICAL BOLD FRAKTUR CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D575;MATHEMATICAL BOLD FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D576;MATHEMATICAL BOLD FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D577;MATHEMATICAL BOLD FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D578;MATHEMATICAL BOLD FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D579;MATHEMATICAL BOLD FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D57A;MATHEMATICAL BOLD FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D57B;MATHEMATICAL BOLD FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D57C;MATHEMATICAL BOLD FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D57D;MATHEMATICAL BOLD FRAKTUR CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; +1D57E;MATHEMATICAL BOLD FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D57F;MATHEMATICAL BOLD FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D580;MATHEMATICAL BOLD FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D581;MATHEMATICAL BOLD FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D582;MATHEMATICAL BOLD FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D583;MATHEMATICAL BOLD FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D584;MATHEMATICAL BOLD FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D585;MATHEMATICAL BOLD FRAKTUR CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D586;MATHEMATICAL BOLD FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D587;MATHEMATICAL BOLD FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D588;MATHEMATICAL BOLD FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D589;MATHEMATICAL BOLD FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D58A;MATHEMATICAL BOLD FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D58B;MATHEMATICAL BOLD FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D58C;MATHEMATICAL BOLD FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D58D;MATHEMATICAL BOLD FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D58E;MATHEMATICAL BOLD FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D58F;MATHEMATICAL BOLD FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D590;MATHEMATICAL BOLD FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D591;MATHEMATICAL BOLD FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D592;MATHEMATICAL BOLD FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D593;MATHEMATICAL BOLD FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D594;MATHEMATICAL BOLD FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D595;MATHEMATICAL BOLD FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D596;MATHEMATICAL BOLD FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D597;MATHEMATICAL BOLD FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D598;MATHEMATICAL BOLD FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D599;MATHEMATICAL BOLD FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D59A;MATHEMATICAL BOLD FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D59B;MATHEMATICAL BOLD FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D59C;MATHEMATICAL BOLD FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D59D;MATHEMATICAL BOLD FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D59E;MATHEMATICAL BOLD FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D59F;MATHEMATICAL BOLD FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D5A0;MATHEMATICAL SANS-SERIF CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D5A1;MATHEMATICAL SANS-SERIF CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D5A2;MATHEMATICAL SANS-SERIF CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D5A3;MATHEMATICAL SANS-SERIF CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D5A4;MATHEMATICAL SANS-SERIF CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D5A5;MATHEMATICAL SANS-SERIF CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D5A6;MATHEMATICAL SANS-SERIF CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D5A7;MATHEMATICAL SANS-SERIF CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; +1D5A8;MATHEMATICAL SANS-SERIF CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D5A9;MATHEMATICAL SANS-SERIF CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D5AA;MATHEMATICAL SANS-SERIF CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D5AB;MATHEMATICAL SANS-SERIF CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D5AC;MATHEMATICAL SANS-SERIF CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D5AD;MATHEMATICAL SANS-SERIF CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D5AE;MATHEMATICAL SANS-SERIF CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D5AF;MATHEMATICAL SANS-SERIF CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D5B0;MATHEMATICAL SANS-SERIF CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D5B1;MATHEMATICAL SANS-SERIF CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; +1D5B2;MATHEMATICAL SANS-SERIF CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D5B3;MATHEMATICAL SANS-SERIF CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D5B4;MATHEMATICAL SANS-SERIF CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D5B5;MATHEMATICAL SANS-SERIF CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D5B6;MATHEMATICAL SANS-SERIF CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D5B7;MATHEMATICAL SANS-SERIF CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D5B8;MATHEMATICAL SANS-SERIF CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D5B9;MATHEMATICAL SANS-SERIF CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D5BA;MATHEMATICAL SANS-SERIF SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D5BB;MATHEMATICAL SANS-SERIF SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D5BC;MATHEMATICAL SANS-SERIF SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D5BD;MATHEMATICAL SANS-SERIF SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D5BE;MATHEMATICAL SANS-SERIF SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D5BF;MATHEMATICAL SANS-SERIF SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D5C0;MATHEMATICAL SANS-SERIF SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D5C1;MATHEMATICAL SANS-SERIF SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D5C2;MATHEMATICAL SANS-SERIF SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D5C3;MATHEMATICAL SANS-SERIF SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D5C4;MATHEMATICAL SANS-SERIF SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D5C5;MATHEMATICAL SANS-SERIF SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D5C6;MATHEMATICAL SANS-SERIF SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D5C7;MATHEMATICAL SANS-SERIF SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D5C8;MATHEMATICAL SANS-SERIF SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D5C9;MATHEMATICAL SANS-SERIF SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D5CA;MATHEMATICAL SANS-SERIF SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D5CB;MATHEMATICAL SANS-SERIF SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D5CC;MATHEMATICAL SANS-SERIF SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D5CD;MATHEMATICAL SANS-SERIF SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D5CE;MATHEMATICAL SANS-SERIF SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D5CF;MATHEMATICAL SANS-SERIF SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D5D0;MATHEMATICAL SANS-SERIF SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D5D1;MATHEMATICAL SANS-SERIF SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D5D2;MATHEMATICAL SANS-SERIF SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D5D3;MATHEMATICAL SANS-SERIF SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D5D4;MATHEMATICAL SANS-SERIF BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D5D5;MATHEMATICAL SANS-SERIF BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D5D6;MATHEMATICAL SANS-SERIF BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D5D7;MATHEMATICAL SANS-SERIF BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D5D8;MATHEMATICAL SANS-SERIF BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D5D9;MATHEMATICAL SANS-SERIF BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D5DA;MATHEMATICAL SANS-SERIF BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D5DB;MATHEMATICAL SANS-SERIF BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; +1D5DC;MATHEMATICAL SANS-SERIF BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D5DD;MATHEMATICAL SANS-SERIF BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D5DE;MATHEMATICAL SANS-SERIF BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D5DF;MATHEMATICAL SANS-SERIF BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D5E0;MATHEMATICAL SANS-SERIF BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D5E1;MATHEMATICAL SANS-SERIF BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D5E2;MATHEMATICAL SANS-SERIF BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D5E3;MATHEMATICAL SANS-SERIF BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D5E4;MATHEMATICAL SANS-SERIF BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D5E5;MATHEMATICAL SANS-SERIF BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; +1D5E6;MATHEMATICAL SANS-SERIF BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D5E7;MATHEMATICAL SANS-SERIF BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D5E8;MATHEMATICAL SANS-SERIF BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D5E9;MATHEMATICAL SANS-SERIF BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D5EA;MATHEMATICAL SANS-SERIF BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D5EB;MATHEMATICAL SANS-SERIF BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D5EC;MATHEMATICAL SANS-SERIF BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D5ED;MATHEMATICAL SANS-SERIF BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D5EE;MATHEMATICAL SANS-SERIF BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D5EF;MATHEMATICAL SANS-SERIF BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D5F0;MATHEMATICAL SANS-SERIF BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D5F1;MATHEMATICAL SANS-SERIF BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D5F2;MATHEMATICAL SANS-SERIF BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D5F3;MATHEMATICAL SANS-SERIF BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D5F4;MATHEMATICAL SANS-SERIF BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D5F5;MATHEMATICAL SANS-SERIF BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D5F6;MATHEMATICAL SANS-SERIF BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D5F7;MATHEMATICAL SANS-SERIF BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D5F8;MATHEMATICAL SANS-SERIF BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D5F9;MATHEMATICAL SANS-SERIF BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D5FA;MATHEMATICAL SANS-SERIF BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D5FB;MATHEMATICAL SANS-SERIF BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D5FC;MATHEMATICAL SANS-SERIF BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D5FD;MATHEMATICAL SANS-SERIF BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D5FE;MATHEMATICAL SANS-SERIF BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D5FF;MATHEMATICAL SANS-SERIF BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D600;MATHEMATICAL SANS-SERIF BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D601;MATHEMATICAL SANS-SERIF BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D602;MATHEMATICAL SANS-SERIF BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D603;MATHEMATICAL SANS-SERIF BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D604;MATHEMATICAL SANS-SERIF BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D605;MATHEMATICAL SANS-SERIF BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D606;MATHEMATICAL SANS-SERIF BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D607;MATHEMATICAL SANS-SERIF BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D608;MATHEMATICAL SANS-SERIF ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D609;MATHEMATICAL SANS-SERIF ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D60A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D60B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D60C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D60D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D60E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D60F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; +1D610;MATHEMATICAL SANS-SERIF ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D611;MATHEMATICAL SANS-SERIF ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D612;MATHEMATICAL SANS-SERIF ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D613;MATHEMATICAL SANS-SERIF ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D614;MATHEMATICAL SANS-SERIF ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D615;MATHEMATICAL SANS-SERIF ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D616;MATHEMATICAL SANS-SERIF ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D617;MATHEMATICAL SANS-SERIF ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D618;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D619;MATHEMATICAL SANS-SERIF ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; +1D61A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D61B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D61C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D61D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D61E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D61F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D620;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D621;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D622;MATHEMATICAL SANS-SERIF ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D623;MATHEMATICAL SANS-SERIF ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D624;MATHEMATICAL SANS-SERIF ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D625;MATHEMATICAL SANS-SERIF ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D626;MATHEMATICAL SANS-SERIF ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D627;MATHEMATICAL SANS-SERIF ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D628;MATHEMATICAL SANS-SERIF ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D629;MATHEMATICAL SANS-SERIF ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D62A;MATHEMATICAL SANS-SERIF ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D62B;MATHEMATICAL SANS-SERIF ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D62C;MATHEMATICAL SANS-SERIF ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D62D;MATHEMATICAL SANS-SERIF ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D62E;MATHEMATICAL SANS-SERIF ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D62F;MATHEMATICAL SANS-SERIF ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D630;MATHEMATICAL SANS-SERIF ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D631;MATHEMATICAL SANS-SERIF ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D632;MATHEMATICAL SANS-SERIF ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D633;MATHEMATICAL SANS-SERIF ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D634;MATHEMATICAL SANS-SERIF ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D635;MATHEMATICAL SANS-SERIF ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D636;MATHEMATICAL SANS-SERIF ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D637;MATHEMATICAL SANS-SERIF ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D638;MATHEMATICAL SANS-SERIF ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D639;MATHEMATICAL SANS-SERIF ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D63A;MATHEMATICAL SANS-SERIF ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D63B;MATHEMATICAL SANS-SERIF ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D63C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D63D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D63E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D63F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D640;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D641;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D642;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D643;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; +1D644;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D645;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D646;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D647;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D648;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D649;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D64A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D64B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D64C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D64D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; +1D64E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D64F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D650;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D651;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D652;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D653;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D654;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D655;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D656;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D657;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D658;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D659;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D65A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D65B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D65C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D65D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D65E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D65F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D660;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D661;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D662;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D663;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D664;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D665;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D666;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D667;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D668;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D669;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D66A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D66B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D66C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D66D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D66E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D66F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D670;MATHEMATICAL MONOSPACE CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;; +1D671;MATHEMATICAL MONOSPACE CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;; +1D672;MATHEMATICAL MONOSPACE CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;; +1D673;MATHEMATICAL MONOSPACE CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;; +1D674;MATHEMATICAL MONOSPACE CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;; +1D675;MATHEMATICAL MONOSPACE CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;; +1D676;MATHEMATICAL MONOSPACE CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;; +1D677;MATHEMATICAL MONOSPACE CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;; +1D678;MATHEMATICAL MONOSPACE CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;; +1D679;MATHEMATICAL MONOSPACE CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;; +1D67A;MATHEMATICAL MONOSPACE CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;; +1D67B;MATHEMATICAL MONOSPACE CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;; +1D67C;MATHEMATICAL MONOSPACE CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;; +1D67D;MATHEMATICAL MONOSPACE CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;; +1D67E;MATHEMATICAL MONOSPACE CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;; +1D67F;MATHEMATICAL MONOSPACE CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;; +1D680;MATHEMATICAL MONOSPACE CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;; +1D681;MATHEMATICAL MONOSPACE CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;; +1D682;MATHEMATICAL MONOSPACE CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;; +1D683;MATHEMATICAL MONOSPACE CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;; +1D684;MATHEMATICAL MONOSPACE CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;; +1D685;MATHEMATICAL MONOSPACE CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;; +1D686;MATHEMATICAL MONOSPACE CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;; +1D687;MATHEMATICAL MONOSPACE CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;; +1D688;MATHEMATICAL MONOSPACE CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;; +1D689;MATHEMATICAL MONOSPACE CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;; +1D68A;MATHEMATICAL MONOSPACE SMALL A;Ll;0;L;<font> 0061;;;;N;;;;; +1D68B;MATHEMATICAL MONOSPACE SMALL B;Ll;0;L;<font> 0062;;;;N;;;;; +1D68C;MATHEMATICAL MONOSPACE SMALL C;Ll;0;L;<font> 0063;;;;N;;;;; +1D68D;MATHEMATICAL MONOSPACE SMALL D;Ll;0;L;<font> 0064;;;;N;;;;; +1D68E;MATHEMATICAL MONOSPACE SMALL E;Ll;0;L;<font> 0065;;;;N;;;;; +1D68F;MATHEMATICAL MONOSPACE SMALL F;Ll;0;L;<font> 0066;;;;N;;;;; +1D690;MATHEMATICAL MONOSPACE SMALL G;Ll;0;L;<font> 0067;;;;N;;;;; +1D691;MATHEMATICAL MONOSPACE SMALL H;Ll;0;L;<font> 0068;;;;N;;;;; +1D692;MATHEMATICAL MONOSPACE SMALL I;Ll;0;L;<font> 0069;;;;N;;;;; +1D693;MATHEMATICAL MONOSPACE SMALL J;Ll;0;L;<font> 006A;;;;N;;;;; +1D694;MATHEMATICAL MONOSPACE SMALL K;Ll;0;L;<font> 006B;;;;N;;;;; +1D695;MATHEMATICAL MONOSPACE SMALL L;Ll;0;L;<font> 006C;;;;N;;;;; +1D696;MATHEMATICAL MONOSPACE SMALL M;Ll;0;L;<font> 006D;;;;N;;;;; +1D697;MATHEMATICAL MONOSPACE SMALL N;Ll;0;L;<font> 006E;;;;N;;;;; +1D698;MATHEMATICAL MONOSPACE SMALL O;Ll;0;L;<font> 006F;;;;N;;;;; +1D699;MATHEMATICAL MONOSPACE SMALL P;Ll;0;L;<font> 0070;;;;N;;;;; +1D69A;MATHEMATICAL MONOSPACE SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;; +1D69B;MATHEMATICAL MONOSPACE SMALL R;Ll;0;L;<font> 0072;;;;N;;;;; +1D69C;MATHEMATICAL MONOSPACE SMALL S;Ll;0;L;<font> 0073;;;;N;;;;; +1D69D;MATHEMATICAL MONOSPACE SMALL T;Ll;0;L;<font> 0074;;;;N;;;;; +1D69E;MATHEMATICAL MONOSPACE SMALL U;Ll;0;L;<font> 0075;;;;N;;;;; +1D69F;MATHEMATICAL MONOSPACE SMALL V;Ll;0;L;<font> 0076;;;;N;;;;; +1D6A0;MATHEMATICAL MONOSPACE SMALL W;Ll;0;L;<font> 0077;;;;N;;;;; +1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L;<font> 0078;;;;N;;;;; +1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;; +1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;; +1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; +1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; +1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; +1D6AB;MATHEMATICAL BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;; +1D6AC;MATHEMATICAL BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;; +1D6AD;MATHEMATICAL BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;; +1D6AE;MATHEMATICAL BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;; +1D6AF;MATHEMATICAL BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;; +1D6B0;MATHEMATICAL BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;; +1D6B1;MATHEMATICAL BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;; +1D6B2;MATHEMATICAL BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;; +1D6B3;MATHEMATICAL BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;; +1D6B4;MATHEMATICAL BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;; +1D6B5;MATHEMATICAL BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;; +1D6B6;MATHEMATICAL BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;; +1D6B7;MATHEMATICAL BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; +1D6B8;MATHEMATICAL BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;; +1D6B9;MATHEMATICAL BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;; +1D6BA;MATHEMATICAL BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;; +1D6BB;MATHEMATICAL BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;; +1D6BC;MATHEMATICAL BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;; +1D6BD;MATHEMATICAL BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;; +1D6BE;MATHEMATICAL BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;; +1D6BF;MATHEMATICAL BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;; +1D6C0;MATHEMATICAL BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;; +1D6C1;MATHEMATICAL BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;; +1D6C2;MATHEMATICAL BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;; +1D6C3;MATHEMATICAL BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;; +1D6C4;MATHEMATICAL BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; +1D6C5;MATHEMATICAL BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;; +1D6C6;MATHEMATICAL BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;; +1D6C7;MATHEMATICAL BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;; +1D6C8;MATHEMATICAL BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;; +1D6C9;MATHEMATICAL BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;; +1D6CA;MATHEMATICAL BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;; +1D6CB;MATHEMATICAL BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;; +1D6CC;MATHEMATICAL BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;; +1D6CD;MATHEMATICAL BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;; +1D6CE;MATHEMATICAL BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;; +1D6CF;MATHEMATICAL BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;; +1D6D0;MATHEMATICAL BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;; +1D6D1;MATHEMATICAL BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; +1D6D2;MATHEMATICAL BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;; +1D6D3;MATHEMATICAL BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;; +1D6D4;MATHEMATICAL BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;; +1D6D5;MATHEMATICAL BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;; +1D6D6;MATHEMATICAL BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;; +1D6D7;MATHEMATICAL BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;; +1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; +1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; +1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; +1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;; +1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; +1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; +1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; +1D6DF;MATHEMATICAL BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; +1D6E0;MATHEMATICAL BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; +1D6E1;MATHEMATICAL BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; +1D6E2;MATHEMATICAL ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; +1D6E3;MATHEMATICAL ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; +1D6E4;MATHEMATICAL ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; +1D6E5;MATHEMATICAL ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;; +1D6E6;MATHEMATICAL ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;; +1D6E7;MATHEMATICAL ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;; +1D6E8;MATHEMATICAL ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;; +1D6E9;MATHEMATICAL ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;; +1D6EA;MATHEMATICAL ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;; +1D6EB;MATHEMATICAL ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;; +1D6EC;MATHEMATICAL ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;; +1D6ED;MATHEMATICAL ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;; +1D6EE;MATHEMATICAL ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;; +1D6EF;MATHEMATICAL ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;; +1D6F0;MATHEMATICAL ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;; +1D6F1;MATHEMATICAL ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; +1D6F2;MATHEMATICAL ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;; +1D6F3;MATHEMATICAL ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;; +1D6F4;MATHEMATICAL ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;; +1D6F5;MATHEMATICAL ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;; +1D6F6;MATHEMATICAL ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;; +1D6F7;MATHEMATICAL ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;; +1D6F8;MATHEMATICAL ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;; +1D6F9;MATHEMATICAL ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;; +1D6FA;MATHEMATICAL ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;; +1D6FB;MATHEMATICAL ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;; +1D6FC;MATHEMATICAL ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;; +1D6FD;MATHEMATICAL ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;; +1D6FE;MATHEMATICAL ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; +1D6FF;MATHEMATICAL ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;; +1D700;MATHEMATICAL ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;; +1D701;MATHEMATICAL ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;; +1D702;MATHEMATICAL ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;; +1D703;MATHEMATICAL ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;; +1D704;MATHEMATICAL ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;; +1D705;MATHEMATICAL ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;; +1D706;MATHEMATICAL ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;; +1D707;MATHEMATICAL ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;; +1D708;MATHEMATICAL ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;; +1D709;MATHEMATICAL ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;; +1D70A;MATHEMATICAL ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;; +1D70B;MATHEMATICAL ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; +1D70C;MATHEMATICAL ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;; +1D70D;MATHEMATICAL ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;; +1D70E;MATHEMATICAL ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;; +1D70F;MATHEMATICAL ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;; +1D710;MATHEMATICAL ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;; +1D711;MATHEMATICAL ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;; +1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; +1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; +1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; +1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;; +1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; +1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; +1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; +1D719;MATHEMATICAL ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; +1D71A;MATHEMATICAL ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; +1D71B;MATHEMATICAL ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; +1D71C;MATHEMATICAL BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; +1D71D;MATHEMATICAL BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; +1D71E;MATHEMATICAL BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; +1D71F;MATHEMATICAL BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;; +1D720;MATHEMATICAL BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;; +1D721;MATHEMATICAL BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;; +1D722;MATHEMATICAL BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;; +1D723;MATHEMATICAL BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;; +1D724;MATHEMATICAL BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;; +1D725;MATHEMATICAL BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;; +1D726;MATHEMATICAL BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;; +1D727;MATHEMATICAL BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;; +1D728;MATHEMATICAL BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;; +1D729;MATHEMATICAL BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;; +1D72A;MATHEMATICAL BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;; +1D72B;MATHEMATICAL BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; +1D72C;MATHEMATICAL BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;; +1D72D;MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;; +1D72E;MATHEMATICAL BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;; +1D72F;MATHEMATICAL BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;; +1D730;MATHEMATICAL BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;; +1D731;MATHEMATICAL BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;; +1D732;MATHEMATICAL BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;; +1D733;MATHEMATICAL BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;; +1D734;MATHEMATICAL BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;; +1D735;MATHEMATICAL BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;; +1D736;MATHEMATICAL BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;; +1D737;MATHEMATICAL BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;; +1D738;MATHEMATICAL BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; +1D739;MATHEMATICAL BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;; +1D73A;MATHEMATICAL BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;; +1D73B;MATHEMATICAL BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;; +1D73C;MATHEMATICAL BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;; +1D73D;MATHEMATICAL BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;; +1D73E;MATHEMATICAL BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;; +1D73F;MATHEMATICAL BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;; +1D740;MATHEMATICAL BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;; +1D741;MATHEMATICAL BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;; +1D742;MATHEMATICAL BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;; +1D743;MATHEMATICAL BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;; +1D744;MATHEMATICAL BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;; +1D745;MATHEMATICAL BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; +1D746;MATHEMATICAL BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;; +1D747;MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;; +1D748;MATHEMATICAL BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;; +1D749;MATHEMATICAL BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;; +1D74A;MATHEMATICAL BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;; +1D74B;MATHEMATICAL BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;; +1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; +1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; +1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; +1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;; +1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; +1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; +1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; +1D753;MATHEMATICAL BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; +1D754;MATHEMATICAL BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; +1D755;MATHEMATICAL BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; +1D756;MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; +1D757;MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; +1D758;MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; +1D759;MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;; +1D75A;MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;; +1D75B;MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;; +1D75C;MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;; +1D75D;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;; +1D75E;MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;; +1D75F;MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;; +1D760;MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;; +1D761;MATHEMATICAL SANS-SERIF BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;; +1D762;MATHEMATICAL SANS-SERIF BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;; +1D763;MATHEMATICAL SANS-SERIF BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;; +1D764;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;; +1D765;MATHEMATICAL SANS-SERIF BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; +1D766;MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;; +1D767;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;; +1D768;MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;; +1D769;MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;; +1D76A;MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;; +1D76B;MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;; +1D76C;MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;; +1D76D;MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;; +1D76E;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;; +1D76F;MATHEMATICAL SANS-SERIF BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;; +1D770;MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;; +1D771;MATHEMATICAL SANS-SERIF BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;; +1D772;MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; +1D773;MATHEMATICAL SANS-SERIF BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;; +1D774;MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;; +1D775;MATHEMATICAL SANS-SERIF BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;; +1D776;MATHEMATICAL SANS-SERIF BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;; +1D777;MATHEMATICAL SANS-SERIF BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;; +1D778;MATHEMATICAL SANS-SERIF BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;; +1D779;MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;; +1D77A;MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;; +1D77B;MATHEMATICAL SANS-SERIF BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;; +1D77C;MATHEMATICAL SANS-SERIF BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;; +1D77D;MATHEMATICAL SANS-SERIF BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;; +1D77E;MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;; +1D77F;MATHEMATICAL SANS-SERIF BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; +1D780;MATHEMATICAL SANS-SERIF BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;; +1D781;MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;; +1D782;MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;; +1D783;MATHEMATICAL SANS-SERIF BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;; +1D784;MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;; +1D785;MATHEMATICAL SANS-SERIF BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;; +1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; +1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; +1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; +1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;; +1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; +1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; +1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; +1D78D;MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; +1D78E;MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; +1D78F;MATHEMATICAL SANS-SERIF BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; +1D790;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;; +1D791;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;; +1D792;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;; +1D793;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;; +1D794;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;; +1D795;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;; +1D796;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;; +1D797;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;; +1D798;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;; +1D799;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;; +1D79A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;; +1D79B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;; +1D79C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;; +1D79D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;; +1D79E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;; +1D79F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;; +1D7A0;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;; +1D7A1;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;; +1D7A2;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;; +1D7A3;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;; +1D7A4;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;; +1D7A5;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;; +1D7A6;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;; +1D7A7;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;; +1D7A8;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;; +1D7A9;MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;; +1D7AA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;; +1D7AB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;; +1D7AC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;; +1D7AD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;; +1D7AE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;; +1D7AF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;; +1D7B0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;; +1D7B1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;; +1D7B2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;; +1D7B3;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;; +1D7B4;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;; +1D7B5;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;; +1D7B6;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;; +1D7B7;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;; +1D7B8;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;; +1D7B9;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;; +1D7BA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;; +1D7BB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;; +1D7BC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;; +1D7BD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;; +1D7BE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;; +1D7BF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;; +1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;; +1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;; +1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;; +1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;; +1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;; +1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;; +1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;; +1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;; +1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;; +1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;; +1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; +1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; +1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; +1D7D1;MATHEMATICAL BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; +1D7D2;MATHEMATICAL BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; +1D7D3;MATHEMATICAL BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; +1D7D4;MATHEMATICAL BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; +1D7D5;MATHEMATICAL BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; +1D7D6;MATHEMATICAL BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; +1D7D7;MATHEMATICAL BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; +1D7D8;MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; +1D7D9;MATHEMATICAL DOUBLE-STRUCK DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; +1D7DA;MATHEMATICAL DOUBLE-STRUCK DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; +1D7DB;MATHEMATICAL DOUBLE-STRUCK DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; +1D7DC;MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; +1D7DD;MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; +1D7DE;MATHEMATICAL DOUBLE-STRUCK DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; +1D7DF;MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; +1D7E0;MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; +1D7E1;MATHEMATICAL DOUBLE-STRUCK DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; +1D7E2;MATHEMATICAL SANS-SERIF DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; +1D7E3;MATHEMATICAL SANS-SERIF DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; +1D7E4;MATHEMATICAL SANS-SERIF DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; +1D7E5;MATHEMATICAL SANS-SERIF DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; +1D7E6;MATHEMATICAL SANS-SERIF DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; +1D7E7;MATHEMATICAL SANS-SERIF DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; +1D7E8;MATHEMATICAL SANS-SERIF DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; +1D7E9;MATHEMATICAL SANS-SERIF DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; +1D7EA;MATHEMATICAL SANS-SERIF DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; +1D7EB;MATHEMATICAL SANS-SERIF DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; +1D7EC;MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; +1D7ED;MATHEMATICAL SANS-SERIF BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; +1D7EE;MATHEMATICAL SANS-SERIF BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; +1D7EF;MATHEMATICAL SANS-SERIF BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; +1D7F0;MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; +1D7F1;MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; +1D7F2;MATHEMATICAL SANS-SERIF BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; +1D7F3;MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; +1D7F4;MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; +1D7F5;MATHEMATICAL SANS-SERIF BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; +1D7F6;MATHEMATICAL MONOSPACE DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;; +1D7F7;MATHEMATICAL MONOSPACE DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;; +1D7F8;MATHEMATICAL MONOSPACE DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;; +1D7F9;MATHEMATICAL MONOSPACE DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;; +1D7FA;MATHEMATICAL MONOSPACE DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;; +1D7FB;MATHEMATICAL MONOSPACE DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;; +1D7FC;MATHEMATICAL MONOSPACE DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;; +1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;; +1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;; +1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;; +20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;; +2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;; +2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;; +2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;; +2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;; +2F803;CJK COMPATIBILITY IDEOGRAPH-2F803;Lo;0;L;20122;;;;N;;;;; +2F804;CJK COMPATIBILITY IDEOGRAPH-2F804;Lo;0;L;4F60;;;;N;;;;; +2F805;CJK COMPATIBILITY IDEOGRAPH-2F805;Lo;0;L;4FAE;;;;N;;;;; +2F806;CJK COMPATIBILITY IDEOGRAPH-2F806;Lo;0;L;4FBB;;;;N;;;;; +2F807;CJK COMPATIBILITY IDEOGRAPH-2F807;Lo;0;L;5002;;;;N;;;;; +2F808;CJK COMPATIBILITY IDEOGRAPH-2F808;Lo;0;L;507A;;;;N;;;;; +2F809;CJK COMPATIBILITY IDEOGRAPH-2F809;Lo;0;L;5099;;;;N;;;;; +2F80A;CJK COMPATIBILITY IDEOGRAPH-2F80A;Lo;0;L;50E7;;;;N;;;;; +2F80B;CJK COMPATIBILITY IDEOGRAPH-2F80B;Lo;0;L;50CF;;;;N;;;;; +2F80C;CJK COMPATIBILITY IDEOGRAPH-2F80C;Lo;0;L;349E;;;;N;;;;; +2F80D;CJK COMPATIBILITY IDEOGRAPH-2F80D;Lo;0;L;2063A;;;;N;;;;; +2F80E;CJK COMPATIBILITY IDEOGRAPH-2F80E;Lo;0;L;514D;;;;N;;;;; +2F80F;CJK COMPATIBILITY IDEOGRAPH-2F80F;Lo;0;L;5154;;;;N;;;;; +2F810;CJK COMPATIBILITY IDEOGRAPH-2F810;Lo;0;L;5164;;;;N;;;;; +2F811;CJK COMPATIBILITY IDEOGRAPH-2F811;Lo;0;L;5177;;;;N;;;;; +2F812;CJK COMPATIBILITY IDEOGRAPH-2F812;Lo;0;L;2051C;;;;N;;;;; +2F813;CJK COMPATIBILITY IDEOGRAPH-2F813;Lo;0;L;34B9;;;;N;;;;; +2F814;CJK COMPATIBILITY IDEOGRAPH-2F814;Lo;0;L;5167;;;;N;;;;; +2F815;CJK COMPATIBILITY IDEOGRAPH-2F815;Lo;0;L;518D;;;;N;;;;; +2F816;CJK COMPATIBILITY IDEOGRAPH-2F816;Lo;0;L;2054B;;;;N;;;;; +2F817;CJK COMPATIBILITY IDEOGRAPH-2F817;Lo;0;L;5197;;;;N;;;;; +2F818;CJK COMPATIBILITY IDEOGRAPH-2F818;Lo;0;L;51A4;;;;N;;;;; +2F819;CJK COMPATIBILITY IDEOGRAPH-2F819;Lo;0;L;4ECC;;;;N;;;;; +2F81A;CJK COMPATIBILITY IDEOGRAPH-2F81A;Lo;0;L;51AC;;;;N;;;;; +2F81B;CJK COMPATIBILITY IDEOGRAPH-2F81B;Lo;0;L;51B5;;;;N;;;;; +2F81C;CJK COMPATIBILITY IDEOGRAPH-2F81C;Lo;0;L;291DF;;;;N;;;;; +2F81D;CJK COMPATIBILITY IDEOGRAPH-2F81D;Lo;0;L;51F5;;;;N;;;;; +2F81E;CJK COMPATIBILITY IDEOGRAPH-2F81E;Lo;0;L;5203;;;;N;;;;; +2F81F;CJK COMPATIBILITY IDEOGRAPH-2F81F;Lo;0;L;34DF;;;;N;;;;; +2F820;CJK COMPATIBILITY IDEOGRAPH-2F820;Lo;0;L;523B;;;;N;;;;; +2F821;CJK COMPATIBILITY IDEOGRAPH-2F821;Lo;0;L;5246;;;;N;;;;; +2F822;CJK COMPATIBILITY IDEOGRAPH-2F822;Lo;0;L;5272;;;;N;;;;; +2F823;CJK COMPATIBILITY IDEOGRAPH-2F823;Lo;0;L;5277;;;;N;;;;; +2F824;CJK COMPATIBILITY IDEOGRAPH-2F824;Lo;0;L;3515;;;;N;;;;; +2F825;CJK COMPATIBILITY IDEOGRAPH-2F825;Lo;0;L;52C7;;;;N;;;;; +2F826;CJK COMPATIBILITY IDEOGRAPH-2F826;Lo;0;L;52C9;;;;N;;;;; +2F827;CJK COMPATIBILITY IDEOGRAPH-2F827;Lo;0;L;52E4;;;;N;;;;; +2F828;CJK COMPATIBILITY IDEOGRAPH-2F828;Lo;0;L;52FA;;;;N;;;;; +2F829;CJK COMPATIBILITY IDEOGRAPH-2F829;Lo;0;L;5305;;;;N;;;;; +2F82A;CJK COMPATIBILITY IDEOGRAPH-2F82A;Lo;0;L;5306;;;;N;;;;; +2F82B;CJK COMPATIBILITY IDEOGRAPH-2F82B;Lo;0;L;5317;;;;N;;;;; +2F82C;CJK COMPATIBILITY IDEOGRAPH-2F82C;Lo;0;L;5349;;;;N;;;;; +2F82D;CJK COMPATIBILITY IDEOGRAPH-2F82D;Lo;0;L;5351;;;;N;;;;; +2F82E;CJK COMPATIBILITY IDEOGRAPH-2F82E;Lo;0;L;535A;;;;N;;;;; +2F82F;CJK COMPATIBILITY IDEOGRAPH-2F82F;Lo;0;L;5373;;;;N;;;;; +2F830;CJK COMPATIBILITY IDEOGRAPH-2F830;Lo;0;L;537D;;;;N;;;;; +2F831;CJK COMPATIBILITY IDEOGRAPH-2F831;Lo;0;L;537F;;;;N;;;;; +2F832;CJK COMPATIBILITY IDEOGRAPH-2F832;Lo;0;L;537F;;;;N;;;;; +2F833;CJK COMPATIBILITY IDEOGRAPH-2F833;Lo;0;L;537F;;;;N;;;;; +2F834;CJK COMPATIBILITY IDEOGRAPH-2F834;Lo;0;L;20A2C;;;;N;;;;; +2F835;CJK COMPATIBILITY IDEOGRAPH-2F835;Lo;0;L;7070;;;;N;;;;; +2F836;CJK COMPATIBILITY IDEOGRAPH-2F836;Lo;0;L;53CA;;;;N;;;;; +2F837;CJK COMPATIBILITY IDEOGRAPH-2F837;Lo;0;L;53DF;;;;N;;;;; +2F838;CJK COMPATIBILITY IDEOGRAPH-2F838;Lo;0;L;20B63;;;;N;;;;; +2F839;CJK COMPATIBILITY IDEOGRAPH-2F839;Lo;0;L;53EB;;;;N;;;;; +2F83A;CJK COMPATIBILITY IDEOGRAPH-2F83A;Lo;0;L;53F1;;;;N;;;;; +2F83B;CJK COMPATIBILITY IDEOGRAPH-2F83B;Lo;0;L;5406;;;;N;;;;; +2F83C;CJK COMPATIBILITY IDEOGRAPH-2F83C;Lo;0;L;549E;;;;N;;;;; +2F83D;CJK COMPATIBILITY IDEOGRAPH-2F83D;Lo;0;L;5438;;;;N;;;;; +2F83E;CJK COMPATIBILITY IDEOGRAPH-2F83E;Lo;0;L;5448;;;;N;;;;; +2F83F;CJK COMPATIBILITY IDEOGRAPH-2F83F;Lo;0;L;5468;;;;N;;;;; +2F840;CJK COMPATIBILITY IDEOGRAPH-2F840;Lo;0;L;54A2;;;;N;;;;; +2F841;CJK COMPATIBILITY IDEOGRAPH-2F841;Lo;0;L;54F6;;;;N;;;;; +2F842;CJK COMPATIBILITY IDEOGRAPH-2F842;Lo;0;L;5510;;;;N;;;;; +2F843;CJK COMPATIBILITY IDEOGRAPH-2F843;Lo;0;L;5553;;;;N;;;;; +2F844;CJK COMPATIBILITY IDEOGRAPH-2F844;Lo;0;L;5563;;;;N;;;;; +2F845;CJK COMPATIBILITY IDEOGRAPH-2F845;Lo;0;L;5584;;;;N;;;;; +2F846;CJK COMPATIBILITY IDEOGRAPH-2F846;Lo;0;L;5584;;;;N;;;;; +2F847;CJK COMPATIBILITY IDEOGRAPH-2F847;Lo;0;L;5599;;;;N;;;;; +2F848;CJK COMPATIBILITY IDEOGRAPH-2F848;Lo;0;L;55AB;;;;N;;;;; +2F849;CJK COMPATIBILITY IDEOGRAPH-2F849;Lo;0;L;55B3;;;;N;;;;; +2F84A;CJK COMPATIBILITY IDEOGRAPH-2F84A;Lo;0;L;55C2;;;;N;;;;; +2F84B;CJK COMPATIBILITY IDEOGRAPH-2F84B;Lo;0;L;5716;;;;N;;;;; +2F84C;CJK COMPATIBILITY IDEOGRAPH-2F84C;Lo;0;L;5606;;;;N;;;;; +2F84D;CJK COMPATIBILITY IDEOGRAPH-2F84D;Lo;0;L;5717;;;;N;;;;; +2F84E;CJK COMPATIBILITY IDEOGRAPH-2F84E;Lo;0;L;5651;;;;N;;;;; +2F84F;CJK COMPATIBILITY IDEOGRAPH-2F84F;Lo;0;L;5674;;;;N;;;;; +2F850;CJK COMPATIBILITY IDEOGRAPH-2F850;Lo;0;L;5207;;;;N;;;;; +2F851;CJK COMPATIBILITY IDEOGRAPH-2F851;Lo;0;L;58EE;;;;N;;;;; +2F852;CJK COMPATIBILITY IDEOGRAPH-2F852;Lo;0;L;57CE;;;;N;;;;; +2F853;CJK COMPATIBILITY IDEOGRAPH-2F853;Lo;0;L;57F4;;;;N;;;;; +2F854;CJK COMPATIBILITY IDEOGRAPH-2F854;Lo;0;L;580D;;;;N;;;;; +2F855;CJK COMPATIBILITY IDEOGRAPH-2F855;Lo;0;L;578B;;;;N;;;;; +2F856;CJK COMPATIBILITY IDEOGRAPH-2F856;Lo;0;L;5832;;;;N;;;;; +2F857;CJK COMPATIBILITY IDEOGRAPH-2F857;Lo;0;L;5831;;;;N;;;;; +2F858;CJK COMPATIBILITY IDEOGRAPH-2F858;Lo;0;L;58AC;;;;N;;;;; +2F859;CJK COMPATIBILITY IDEOGRAPH-2F859;Lo;0;L;214E4;;;;N;;;;; +2F85A;CJK COMPATIBILITY IDEOGRAPH-2F85A;Lo;0;L;58F2;;;;N;;;;; +2F85B;CJK COMPATIBILITY IDEOGRAPH-2F85B;Lo;0;L;58F7;;;;N;;;;; +2F85C;CJK COMPATIBILITY IDEOGRAPH-2F85C;Lo;0;L;5906;;;;N;;;;; +2F85D;CJK COMPATIBILITY IDEOGRAPH-2F85D;Lo;0;L;591A;;;;N;;;;; +2F85E;CJK COMPATIBILITY IDEOGRAPH-2F85E;Lo;0;L;5922;;;;N;;;;; +2F85F;CJK COMPATIBILITY IDEOGRAPH-2F85F;Lo;0;L;5962;;;;N;;;;; +2F860;CJK COMPATIBILITY IDEOGRAPH-2F860;Lo;0;L;216A8;;;;N;;;;; +2F861;CJK COMPATIBILITY IDEOGRAPH-2F861;Lo;0;L;216EA;;;;N;;;;; +2F862;CJK COMPATIBILITY IDEOGRAPH-2F862;Lo;0;L;59EC;;;;N;;;;; +2F863;CJK COMPATIBILITY IDEOGRAPH-2F863;Lo;0;L;5A1B;;;;N;;;;; +2F864;CJK COMPATIBILITY IDEOGRAPH-2F864;Lo;0;L;5A27;;;;N;;;;; +2F865;CJK COMPATIBILITY IDEOGRAPH-2F865;Lo;0;L;59D8;;;;N;;;;; +2F866;CJK COMPATIBILITY IDEOGRAPH-2F866;Lo;0;L;5A66;;;;N;;;;; +2F867;CJK COMPATIBILITY IDEOGRAPH-2F867;Lo;0;L;36EE;;;;N;;;;; +2F868;CJK COMPATIBILITY IDEOGRAPH-2F868;Lo;0;L;36FC;;;;N;;;;; +2F869;CJK COMPATIBILITY IDEOGRAPH-2F869;Lo;0;L;5B08;;;;N;;;;; +2F86A;CJK COMPATIBILITY IDEOGRAPH-2F86A;Lo;0;L;5B3E;;;;N;;;;; +2F86B;CJK COMPATIBILITY IDEOGRAPH-2F86B;Lo;0;L;5B3E;;;;N;;;;; +2F86C;CJK COMPATIBILITY IDEOGRAPH-2F86C;Lo;0;L;219C8;;;;N;;;;; +2F86D;CJK COMPATIBILITY IDEOGRAPH-2F86D;Lo;0;L;5BC3;;;;N;;;;; +2F86E;CJK COMPATIBILITY IDEOGRAPH-2F86E;Lo;0;L;5BD8;;;;N;;;;; +2F86F;CJK COMPATIBILITY IDEOGRAPH-2F86F;Lo;0;L;5BE7;;;;N;;;;; +2F870;CJK COMPATIBILITY IDEOGRAPH-2F870;Lo;0;L;5BF3;;;;N;;;;; +2F871;CJK COMPATIBILITY IDEOGRAPH-2F871;Lo;0;L;21B18;;;;N;;;;; +2F872;CJK COMPATIBILITY IDEOGRAPH-2F872;Lo;0;L;5BFF;;;;N;;;;; +2F873;CJK COMPATIBILITY IDEOGRAPH-2F873;Lo;0;L;5C06;;;;N;;;;; +2F874;CJK COMPATIBILITY IDEOGRAPH-2F874;Lo;0;L;5F53;;;;N;;;;; +2F875;CJK COMPATIBILITY IDEOGRAPH-2F875;Lo;0;L;5C22;;;;N;;;;; +2F876;CJK COMPATIBILITY IDEOGRAPH-2F876;Lo;0;L;3781;;;;N;;;;; +2F877;CJK COMPATIBILITY IDEOGRAPH-2F877;Lo;0;L;5C60;;;;N;;;;; +2F878;CJK COMPATIBILITY IDEOGRAPH-2F878;Lo;0;L;5C6E;;;;N;;;;; +2F879;CJK COMPATIBILITY IDEOGRAPH-2F879;Lo;0;L;5CC0;;;;N;;;;; +2F87A;CJK COMPATIBILITY IDEOGRAPH-2F87A;Lo;0;L;5C8D;;;;N;;;;; +2F87B;CJK COMPATIBILITY IDEOGRAPH-2F87B;Lo;0;L;21DE4;;;;N;;;;; +2F87C;CJK COMPATIBILITY IDEOGRAPH-2F87C;Lo;0;L;5D43;;;;N;;;;; +2F87D;CJK COMPATIBILITY IDEOGRAPH-2F87D;Lo;0;L;21DE6;;;;N;;;;; +2F87E;CJK COMPATIBILITY IDEOGRAPH-2F87E;Lo;0;L;5D6E;;;;N;;;;; +2F87F;CJK COMPATIBILITY IDEOGRAPH-2F87F;Lo;0;L;5D6B;;;;N;;;;; +2F880;CJK COMPATIBILITY IDEOGRAPH-2F880;Lo;0;L;5D7C;;;;N;;;;; +2F881;CJK COMPATIBILITY IDEOGRAPH-2F881;Lo;0;L;5DE1;;;;N;;;;; +2F882;CJK COMPATIBILITY IDEOGRAPH-2F882;Lo;0;L;5DE2;;;;N;;;;; +2F883;CJK COMPATIBILITY IDEOGRAPH-2F883;Lo;0;L;382F;;;;N;;;;; +2F884;CJK COMPATIBILITY IDEOGRAPH-2F884;Lo;0;L;5DFD;;;;N;;;;; +2F885;CJK COMPATIBILITY IDEOGRAPH-2F885;Lo;0;L;5E28;;;;N;;;;; +2F886;CJK COMPATIBILITY IDEOGRAPH-2F886;Lo;0;L;5E3D;;;;N;;;;; +2F887;CJK COMPATIBILITY IDEOGRAPH-2F887;Lo;0;L;5E69;;;;N;;;;; +2F888;CJK COMPATIBILITY IDEOGRAPH-2F888;Lo;0;L;3862;;;;N;;;;; +2F889;CJK COMPATIBILITY IDEOGRAPH-2F889;Lo;0;L;22183;;;;N;;;;; +2F88A;CJK COMPATIBILITY IDEOGRAPH-2F88A;Lo;0;L;387C;;;;N;;;;; +2F88B;CJK COMPATIBILITY IDEOGRAPH-2F88B;Lo;0;L;5EB0;;;;N;;;;; +2F88C;CJK COMPATIBILITY IDEOGRAPH-2F88C;Lo;0;L;5EB3;;;;N;;;;; +2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;; +2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;; +2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;; +2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;;N;;;;; +2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;; +2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;; +2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;; +2F894;CJK COMPATIBILITY IDEOGRAPH-2F894;Lo;0;L;5F22;;;;N;;;;; +2F895;CJK COMPATIBILITY IDEOGRAPH-2F895;Lo;0;L;5F22;;;;N;;;;; +2F896;CJK COMPATIBILITY IDEOGRAPH-2F896;Lo;0;L;38C7;;;;N;;;;; +2F897;CJK COMPATIBILITY IDEOGRAPH-2F897;Lo;0;L;232B8;;;;N;;;;; +2F898;CJK COMPATIBILITY IDEOGRAPH-2F898;Lo;0;L;261DA;;;;N;;;;; +2F899;CJK COMPATIBILITY IDEOGRAPH-2F899;Lo;0;L;5F62;;;;N;;;;; +2F89A;CJK COMPATIBILITY IDEOGRAPH-2F89A;Lo;0;L;5F6B;;;;N;;;;; +2F89B;CJK COMPATIBILITY IDEOGRAPH-2F89B;Lo;0;L;38E3;;;;N;;;;; +2F89C;CJK COMPATIBILITY IDEOGRAPH-2F89C;Lo;0;L;5F9A;;;;N;;;;; +2F89D;CJK COMPATIBILITY IDEOGRAPH-2F89D;Lo;0;L;5FCD;;;;N;;;;; +2F89E;CJK COMPATIBILITY IDEOGRAPH-2F89E;Lo;0;L;5FD7;;;;N;;;;; +2F89F;CJK COMPATIBILITY IDEOGRAPH-2F89F;Lo;0;L;5FF9;;;;N;;;;; +2F8A0;CJK COMPATIBILITY IDEOGRAPH-2F8A0;Lo;0;L;6081;;;;N;;;;; +2F8A1;CJK COMPATIBILITY IDEOGRAPH-2F8A1;Lo;0;L;393A;;;;N;;;;; +2F8A2;CJK COMPATIBILITY IDEOGRAPH-2F8A2;Lo;0;L;391C;;;;N;;;;; +2F8A3;CJK COMPATIBILITY IDEOGRAPH-2F8A3;Lo;0;L;6094;;;;N;;;;; +2F8A4;CJK COMPATIBILITY IDEOGRAPH-2F8A4;Lo;0;L;226D4;;;;N;;;;; +2F8A5;CJK COMPATIBILITY IDEOGRAPH-2F8A5;Lo;0;L;60C7;;;;N;;;;; +2F8A6;CJK COMPATIBILITY IDEOGRAPH-2F8A6;Lo;0;L;6148;;;;N;;;;; +2F8A7;CJK COMPATIBILITY IDEOGRAPH-2F8A7;Lo;0;L;614C;;;;N;;;;; +2F8A8;CJK COMPATIBILITY IDEOGRAPH-2F8A8;Lo;0;L;614E;;;;N;;;;; +2F8A9;CJK COMPATIBILITY IDEOGRAPH-2F8A9;Lo;0;L;614C;;;;N;;;;; +2F8AA;CJK COMPATIBILITY IDEOGRAPH-2F8AA;Lo;0;L;617A;;;;N;;;;; +2F8AB;CJK COMPATIBILITY IDEOGRAPH-2F8AB;Lo;0;L;618E;;;;N;;;;; +2F8AC;CJK COMPATIBILITY IDEOGRAPH-2F8AC;Lo;0;L;61B2;;;;N;;;;; +2F8AD;CJK COMPATIBILITY IDEOGRAPH-2F8AD;Lo;0;L;61A4;;;;N;;;;; +2F8AE;CJK COMPATIBILITY IDEOGRAPH-2F8AE;Lo;0;L;61AF;;;;N;;;;; +2F8AF;CJK COMPATIBILITY IDEOGRAPH-2F8AF;Lo;0;L;61DE;;;;N;;;;; +2F8B0;CJK COMPATIBILITY IDEOGRAPH-2F8B0;Lo;0;L;61F2;;;;N;;;;; +2F8B1;CJK COMPATIBILITY IDEOGRAPH-2F8B1;Lo;0;L;61F6;;;;N;;;;; +2F8B2;CJK COMPATIBILITY IDEOGRAPH-2F8B2;Lo;0;L;6210;;;;N;;;;; +2F8B3;CJK COMPATIBILITY IDEOGRAPH-2F8B3;Lo;0;L;621B;;;;N;;;;; +2F8B4;CJK COMPATIBILITY IDEOGRAPH-2F8B4;Lo;0;L;625D;;;;N;;;;; +2F8B5;CJK COMPATIBILITY IDEOGRAPH-2F8B5;Lo;0;L;62B1;;;;N;;;;; +2F8B6;CJK COMPATIBILITY IDEOGRAPH-2F8B6;Lo;0;L;62D4;;;;N;;;;; +2F8B7;CJK COMPATIBILITY IDEOGRAPH-2F8B7;Lo;0;L;6350;;;;N;;;;; +2F8B8;CJK COMPATIBILITY IDEOGRAPH-2F8B8;Lo;0;L;22B0C;;;;N;;;;; +2F8B9;CJK COMPATIBILITY IDEOGRAPH-2F8B9;Lo;0;L;633D;;;;N;;;;; +2F8BA;CJK COMPATIBILITY IDEOGRAPH-2F8BA;Lo;0;L;62FC;;;;N;;;;; +2F8BB;CJK COMPATIBILITY IDEOGRAPH-2F8BB;Lo;0;L;6368;;;;N;;;;; +2F8BC;CJK COMPATIBILITY IDEOGRAPH-2F8BC;Lo;0;L;6383;;;;N;;;;; +2F8BD;CJK COMPATIBILITY IDEOGRAPH-2F8BD;Lo;0;L;63E4;;;;N;;;;; +2F8BE;CJK COMPATIBILITY IDEOGRAPH-2F8BE;Lo;0;L;22BF1;;;;N;;;;; +2F8BF;CJK COMPATIBILITY IDEOGRAPH-2F8BF;Lo;0;L;6422;;;;N;;;;; +2F8C0;CJK COMPATIBILITY IDEOGRAPH-2F8C0;Lo;0;L;63C5;;;;N;;;;; +2F8C1;CJK COMPATIBILITY IDEOGRAPH-2F8C1;Lo;0;L;63A9;;;;N;;;;; +2F8C2;CJK COMPATIBILITY IDEOGRAPH-2F8C2;Lo;0;L;3A2E;;;;N;;;;; +2F8C3;CJK COMPATIBILITY IDEOGRAPH-2F8C3;Lo;0;L;6469;;;;N;;;;; +2F8C4;CJK COMPATIBILITY IDEOGRAPH-2F8C4;Lo;0;L;647E;;;;N;;;;; +2F8C5;CJK COMPATIBILITY IDEOGRAPH-2F8C5;Lo;0;L;649D;;;;N;;;;; +2F8C6;CJK COMPATIBILITY IDEOGRAPH-2F8C6;Lo;0;L;6477;;;;N;;;;; +2F8C7;CJK COMPATIBILITY IDEOGRAPH-2F8C7;Lo;0;L;3A6C;;;;N;;;;; +2F8C8;CJK COMPATIBILITY IDEOGRAPH-2F8C8;Lo;0;L;654F;;;;N;;;;; +2F8C9;CJK COMPATIBILITY IDEOGRAPH-2F8C9;Lo;0;L;656C;;;;N;;;;; +2F8CA;CJK COMPATIBILITY IDEOGRAPH-2F8CA;Lo;0;L;2300A;;;;N;;;;; +2F8CB;CJK COMPATIBILITY IDEOGRAPH-2F8CB;Lo;0;L;65E3;;;;N;;;;; +2F8CC;CJK COMPATIBILITY IDEOGRAPH-2F8CC;Lo;0;L;66F8;;;;N;;;;; +2F8CD;CJK COMPATIBILITY IDEOGRAPH-2F8CD;Lo;0;L;6649;;;;N;;;;; +2F8CE;CJK COMPATIBILITY IDEOGRAPH-2F8CE;Lo;0;L;3B19;;;;N;;;;; +2F8CF;CJK COMPATIBILITY IDEOGRAPH-2F8CF;Lo;0;L;6691;;;;N;;;;; +2F8D0;CJK COMPATIBILITY IDEOGRAPH-2F8D0;Lo;0;L;3B08;;;;N;;;;; +2F8D1;CJK COMPATIBILITY IDEOGRAPH-2F8D1;Lo;0;L;3AE4;;;;N;;;;; +2F8D2;CJK COMPATIBILITY IDEOGRAPH-2F8D2;Lo;0;L;5192;;;;N;;;;; +2F8D3;CJK COMPATIBILITY IDEOGRAPH-2F8D3;Lo;0;L;5195;;;;N;;;;; +2F8D4;CJK COMPATIBILITY IDEOGRAPH-2F8D4;Lo;0;L;6700;;;;N;;;;; +2F8D5;CJK COMPATIBILITY IDEOGRAPH-2F8D5;Lo;0;L;669C;;;;N;;;;; +2F8D6;CJK COMPATIBILITY IDEOGRAPH-2F8D6;Lo;0;L;80AD;;;;N;;;;; +2F8D7;CJK COMPATIBILITY IDEOGRAPH-2F8D7;Lo;0;L;43D9;;;;N;;;;; +2F8D8;CJK COMPATIBILITY IDEOGRAPH-2F8D8;Lo;0;L;6717;;;;N;;;;; +2F8D9;CJK COMPATIBILITY IDEOGRAPH-2F8D9;Lo;0;L;671B;;;;N;;;;; +2F8DA;CJK COMPATIBILITY IDEOGRAPH-2F8DA;Lo;0;L;6721;;;;N;;;;; +2F8DB;CJK COMPATIBILITY IDEOGRAPH-2F8DB;Lo;0;L;675E;;;;N;;;;; +2F8DC;CJK COMPATIBILITY IDEOGRAPH-2F8DC;Lo;0;L;6753;;;;N;;;;; +2F8DD;CJK COMPATIBILITY IDEOGRAPH-2F8DD;Lo;0;L;233C3;;;;N;;;;; +2F8DE;CJK COMPATIBILITY IDEOGRAPH-2F8DE;Lo;0;L;3B49;;;;N;;;;; +2F8DF;CJK COMPATIBILITY IDEOGRAPH-2F8DF;Lo;0;L;67FA;;;;N;;;;; +2F8E0;CJK COMPATIBILITY IDEOGRAPH-2F8E0;Lo;0;L;6785;;;;N;;;;; +2F8E1;CJK COMPATIBILITY IDEOGRAPH-2F8E1;Lo;0;L;6852;;;;N;;;;; +2F8E2;CJK COMPATIBILITY IDEOGRAPH-2F8E2;Lo;0;L;6885;;;;N;;;;; +2F8E3;CJK COMPATIBILITY IDEOGRAPH-2F8E3;Lo;0;L;2346D;;;;N;;;;; +2F8E4;CJK COMPATIBILITY IDEOGRAPH-2F8E4;Lo;0;L;688E;;;;N;;;;; +2F8E5;CJK COMPATIBILITY IDEOGRAPH-2F8E5;Lo;0;L;681F;;;;N;;;;; +2F8E6;CJK COMPATIBILITY IDEOGRAPH-2F8E6;Lo;0;L;6914;;;;N;;;;; +2F8E7;CJK COMPATIBILITY IDEOGRAPH-2F8E7;Lo;0;L;3B9D;;;;N;;;;; +2F8E8;CJK COMPATIBILITY IDEOGRAPH-2F8E8;Lo;0;L;6942;;;;N;;;;; +2F8E9;CJK COMPATIBILITY IDEOGRAPH-2F8E9;Lo;0;L;69A3;;;;N;;;;; +2F8EA;CJK COMPATIBILITY IDEOGRAPH-2F8EA;Lo;0;L;69EA;;;;N;;;;; +2F8EB;CJK COMPATIBILITY IDEOGRAPH-2F8EB;Lo;0;L;6AA8;;;;N;;;;; +2F8EC;CJK COMPATIBILITY IDEOGRAPH-2F8EC;Lo;0;L;236A3;;;;N;;;;; +2F8ED;CJK COMPATIBILITY IDEOGRAPH-2F8ED;Lo;0;L;6ADB;;;;N;;;;; +2F8EE;CJK COMPATIBILITY IDEOGRAPH-2F8EE;Lo;0;L;3C18;;;;N;;;;; +2F8EF;CJK COMPATIBILITY IDEOGRAPH-2F8EF;Lo;0;L;6B21;;;;N;;;;; +2F8F0;CJK COMPATIBILITY IDEOGRAPH-2F8F0;Lo;0;L;238A7;;;;N;;;;; +2F8F1;CJK COMPATIBILITY IDEOGRAPH-2F8F1;Lo;0;L;6B54;;;;N;;;;; +2F8F2;CJK COMPATIBILITY IDEOGRAPH-2F8F2;Lo;0;L;3C4E;;;;N;;;;; +2F8F3;CJK COMPATIBILITY IDEOGRAPH-2F8F3;Lo;0;L;6B72;;;;N;;;;; +2F8F4;CJK COMPATIBILITY IDEOGRAPH-2F8F4;Lo;0;L;6B9F;;;;N;;;;; +2F8F5;CJK COMPATIBILITY IDEOGRAPH-2F8F5;Lo;0;L;6BBA;;;;N;;;;; +2F8F6;CJK COMPATIBILITY IDEOGRAPH-2F8F6;Lo;0;L;6BBB;;;;N;;;;; +2F8F7;CJK COMPATIBILITY IDEOGRAPH-2F8F7;Lo;0;L;23A8D;;;;N;;;;; +2F8F8;CJK COMPATIBILITY IDEOGRAPH-2F8F8;Lo;0;L;21D0B;;;;N;;;;; +2F8F9;CJK COMPATIBILITY IDEOGRAPH-2F8F9;Lo;0;L;23AFA;;;;N;;;;; +2F8FA;CJK COMPATIBILITY IDEOGRAPH-2F8FA;Lo;0;L;6C4E;;;;N;;;;; +2F8FB;CJK COMPATIBILITY IDEOGRAPH-2F8FB;Lo;0;L;23CBC;;;;N;;;;; +2F8FC;CJK COMPATIBILITY IDEOGRAPH-2F8FC;Lo;0;L;6CBF;;;;N;;;;; +2F8FD;CJK COMPATIBILITY IDEOGRAPH-2F8FD;Lo;0;L;6CCD;;;;N;;;;; +2F8FE;CJK COMPATIBILITY IDEOGRAPH-2F8FE;Lo;0;L;6C67;;;;N;;;;; +2F8FF;CJK COMPATIBILITY IDEOGRAPH-2F8FF;Lo;0;L;6D16;;;;N;;;;; +2F900;CJK COMPATIBILITY IDEOGRAPH-2F900;Lo;0;L;6D3E;;;;N;;;;; +2F901;CJK COMPATIBILITY IDEOGRAPH-2F901;Lo;0;L;6D77;;;;N;;;;; +2F902;CJK COMPATIBILITY IDEOGRAPH-2F902;Lo;0;L;6D41;;;;N;;;;; +2F903;CJK COMPATIBILITY IDEOGRAPH-2F903;Lo;0;L;6D69;;;;N;;;;; +2F904;CJK COMPATIBILITY IDEOGRAPH-2F904;Lo;0;L;6D78;;;;N;;;;; +2F905;CJK COMPATIBILITY IDEOGRAPH-2F905;Lo;0;L;6D85;;;;N;;;;; +2F906;CJK COMPATIBILITY IDEOGRAPH-2F906;Lo;0;L;23D1E;;;;N;;;;; +2F907;CJK COMPATIBILITY IDEOGRAPH-2F907;Lo;0;L;6D34;;;;N;;;;; +2F908;CJK COMPATIBILITY IDEOGRAPH-2F908;Lo;0;L;6E2F;;;;N;;;;; +2F909;CJK COMPATIBILITY IDEOGRAPH-2F909;Lo;0;L;6E6E;;;;N;;;;; +2F90A;CJK COMPATIBILITY IDEOGRAPH-2F90A;Lo;0;L;3D33;;;;N;;;;; +2F90B;CJK COMPATIBILITY IDEOGRAPH-2F90B;Lo;0;L;6ECB;;;;N;;;;; +2F90C;CJK COMPATIBILITY IDEOGRAPH-2F90C;Lo;0;L;6EC7;;;;N;;;;; +2F90D;CJK COMPATIBILITY IDEOGRAPH-2F90D;Lo;0;L;23ED1;;;;N;;;;; +2F90E;CJK COMPATIBILITY IDEOGRAPH-2F90E;Lo;0;L;6DF9;;;;N;;;;; +2F90F;CJK COMPATIBILITY IDEOGRAPH-2F90F;Lo;0;L;6F6E;;;;N;;;;; +2F910;CJK COMPATIBILITY IDEOGRAPH-2F910;Lo;0;L;23F5E;;;;N;;;;; +2F911;CJK COMPATIBILITY IDEOGRAPH-2F911;Lo;0;L;23F8E;;;;N;;;;; +2F912;CJK COMPATIBILITY IDEOGRAPH-2F912;Lo;0;L;6FC6;;;;N;;;;; +2F913;CJK COMPATIBILITY IDEOGRAPH-2F913;Lo;0;L;7039;;;;N;;;;; +2F914;CJK COMPATIBILITY IDEOGRAPH-2F914;Lo;0;L;701E;;;;N;;;;; +2F915;CJK COMPATIBILITY IDEOGRAPH-2F915;Lo;0;L;701B;;;;N;;;;; +2F916;CJK COMPATIBILITY IDEOGRAPH-2F916;Lo;0;L;3D96;;;;N;;;;; +2F917;CJK COMPATIBILITY IDEOGRAPH-2F917;Lo;0;L;704A;;;;N;;;;; +2F918;CJK COMPATIBILITY IDEOGRAPH-2F918;Lo;0;L;707D;;;;N;;;;; +2F919;CJK COMPATIBILITY IDEOGRAPH-2F919;Lo;0;L;7077;;;;N;;;;; +2F91A;CJK COMPATIBILITY IDEOGRAPH-2F91A;Lo;0;L;70AD;;;;N;;;;; +2F91B;CJK COMPATIBILITY IDEOGRAPH-2F91B;Lo;0;L;20525;;;;N;;;;; +2F91C;CJK COMPATIBILITY IDEOGRAPH-2F91C;Lo;0;L;7145;;;;N;;;;; +2F91D;CJK COMPATIBILITY IDEOGRAPH-2F91D;Lo;0;L;24263;;;;N;;;;; +2F91E;CJK COMPATIBILITY IDEOGRAPH-2F91E;Lo;0;L;719C;;;;N;;;;; +2F91F;CJK COMPATIBILITY IDEOGRAPH-2F91F;Lo;0;L;243AB;;;;N;;;;; +2F920;CJK COMPATIBILITY IDEOGRAPH-2F920;Lo;0;L;7228;;;;N;;;;; +2F921;CJK COMPATIBILITY IDEOGRAPH-2F921;Lo;0;L;7235;;;;N;;;;; +2F922;CJK COMPATIBILITY IDEOGRAPH-2F922;Lo;0;L;7250;;;;N;;;;; +2F923;CJK COMPATIBILITY IDEOGRAPH-2F923;Lo;0;L;24608;;;;N;;;;; +2F924;CJK COMPATIBILITY IDEOGRAPH-2F924;Lo;0;L;7280;;;;N;;;;; +2F925;CJK COMPATIBILITY IDEOGRAPH-2F925;Lo;0;L;7295;;;;N;;;;; +2F926;CJK COMPATIBILITY IDEOGRAPH-2F926;Lo;0;L;24735;;;;N;;;;; +2F927;CJK COMPATIBILITY IDEOGRAPH-2F927;Lo;0;L;24814;;;;N;;;;; +2F928;CJK COMPATIBILITY IDEOGRAPH-2F928;Lo;0;L;737A;;;;N;;;;; +2F929;CJK COMPATIBILITY IDEOGRAPH-2F929;Lo;0;L;738B;;;;N;;;;; +2F92A;CJK COMPATIBILITY IDEOGRAPH-2F92A;Lo;0;L;3EAC;;;;N;;;;; +2F92B;CJK COMPATIBILITY IDEOGRAPH-2F92B;Lo;0;L;73A5;;;;N;;;;; +2F92C;CJK COMPATIBILITY IDEOGRAPH-2F92C;Lo;0;L;3EB8;;;;N;;;;; +2F92D;CJK COMPATIBILITY IDEOGRAPH-2F92D;Lo;0;L;3EB8;;;;N;;;;; +2F92E;CJK COMPATIBILITY IDEOGRAPH-2F92E;Lo;0;L;7447;;;;N;;;;; +2F92F;CJK COMPATIBILITY IDEOGRAPH-2F92F;Lo;0;L;745C;;;;N;;;;; +2F930;CJK COMPATIBILITY IDEOGRAPH-2F930;Lo;0;L;7471;;;;N;;;;; +2F931;CJK COMPATIBILITY IDEOGRAPH-2F931;Lo;0;L;7485;;;;N;;;;; +2F932;CJK COMPATIBILITY IDEOGRAPH-2F932;Lo;0;L;74CA;;;;N;;;;; +2F933;CJK COMPATIBILITY IDEOGRAPH-2F933;Lo;0;L;3F1B;;;;N;;;;; +2F934;CJK COMPATIBILITY IDEOGRAPH-2F934;Lo;0;L;7524;;;;N;;;;; +2F935;CJK COMPATIBILITY IDEOGRAPH-2F935;Lo;0;L;24C36;;;;N;;;;; +2F936;CJK COMPATIBILITY IDEOGRAPH-2F936;Lo;0;L;753E;;;;N;;;;; +2F937;CJK COMPATIBILITY IDEOGRAPH-2F937;Lo;0;L;24C92;;;;N;;;;; +2F938;CJK COMPATIBILITY IDEOGRAPH-2F938;Lo;0;L;7570;;;;N;;;;; +2F939;CJK COMPATIBILITY IDEOGRAPH-2F939;Lo;0;L;2219F;;;;N;;;;; +2F93A;CJK COMPATIBILITY IDEOGRAPH-2F93A;Lo;0;L;7610;;;;N;;;;; +2F93B;CJK COMPATIBILITY IDEOGRAPH-2F93B;Lo;0;L;24FA1;;;;N;;;;; +2F93C;CJK COMPATIBILITY IDEOGRAPH-2F93C;Lo;0;L;24FB8;;;;N;;;;; +2F93D;CJK COMPATIBILITY IDEOGRAPH-2F93D;Lo;0;L;25044;;;;N;;;;; +2F93E;CJK COMPATIBILITY IDEOGRAPH-2F93E;Lo;0;L;3FFC;;;;N;;;;; +2F93F;CJK COMPATIBILITY IDEOGRAPH-2F93F;Lo;0;L;4008;;;;N;;;;; +2F940;CJK COMPATIBILITY IDEOGRAPH-2F940;Lo;0;L;76F4;;;;N;;;;; +2F941;CJK COMPATIBILITY IDEOGRAPH-2F941;Lo;0;L;250F3;;;;N;;;;; +2F942;CJK COMPATIBILITY IDEOGRAPH-2F942;Lo;0;L;250F2;;;;N;;;;; +2F943;CJK COMPATIBILITY IDEOGRAPH-2F943;Lo;0;L;25119;;;;N;;;;; +2F944;CJK COMPATIBILITY IDEOGRAPH-2F944;Lo;0;L;25133;;;;N;;;;; +2F945;CJK COMPATIBILITY IDEOGRAPH-2F945;Lo;0;L;771E;;;;N;;;;; +2F946;CJK COMPATIBILITY IDEOGRAPH-2F946;Lo;0;L;771F;;;;N;;;;; +2F947;CJK COMPATIBILITY IDEOGRAPH-2F947;Lo;0;L;771F;;;;N;;;;; +2F948;CJK COMPATIBILITY IDEOGRAPH-2F948;Lo;0;L;774A;;;;N;;;;; +2F949;CJK COMPATIBILITY IDEOGRAPH-2F949;Lo;0;L;4039;;;;N;;;;; +2F94A;CJK COMPATIBILITY IDEOGRAPH-2F94A;Lo;0;L;778B;;;;N;;;;; +2F94B;CJK COMPATIBILITY IDEOGRAPH-2F94B;Lo;0;L;4046;;;;N;;;;; +2F94C;CJK COMPATIBILITY IDEOGRAPH-2F94C;Lo;0;L;4096;;;;N;;;;; +2F94D;CJK COMPATIBILITY IDEOGRAPH-2F94D;Lo;0;L;2541D;;;;N;;;;; +2F94E;CJK COMPATIBILITY IDEOGRAPH-2F94E;Lo;0;L;784E;;;;N;;;;; +2F94F;CJK COMPATIBILITY IDEOGRAPH-2F94F;Lo;0;L;788C;;;;N;;;;; +2F950;CJK COMPATIBILITY IDEOGRAPH-2F950;Lo;0;L;78CC;;;;N;;;;; +2F951;CJK COMPATIBILITY IDEOGRAPH-2F951;Lo;0;L;40E3;;;;N;;;;; +2F952;CJK COMPATIBILITY IDEOGRAPH-2F952;Lo;0;L;25626;;;;N;;;;; +2F953;CJK COMPATIBILITY IDEOGRAPH-2F953;Lo;0;L;7956;;;;N;;;;; +2F954;CJK COMPATIBILITY IDEOGRAPH-2F954;Lo;0;L;2569A;;;;N;;;;; +2F955;CJK COMPATIBILITY IDEOGRAPH-2F955;Lo;0;L;256C5;;;;N;;;;; +2F956;CJK COMPATIBILITY IDEOGRAPH-2F956;Lo;0;L;798F;;;;N;;;;; +2F957;CJK COMPATIBILITY IDEOGRAPH-2F957;Lo;0;L;79EB;;;;N;;;;; +2F958;CJK COMPATIBILITY IDEOGRAPH-2F958;Lo;0;L;412F;;;;N;;;;; +2F959;CJK COMPATIBILITY IDEOGRAPH-2F959;Lo;0;L;7A40;;;;N;;;;; +2F95A;CJK COMPATIBILITY IDEOGRAPH-2F95A;Lo;0;L;7A4A;;;;N;;;;; +2F95B;CJK COMPATIBILITY IDEOGRAPH-2F95B;Lo;0;L;7A4F;;;;N;;;;; +2F95C;CJK COMPATIBILITY IDEOGRAPH-2F95C;Lo;0;L;2597C;;;;N;;;;; +2F95D;CJK COMPATIBILITY IDEOGRAPH-2F95D;Lo;0;L;25AA7;;;;N;;;;; +2F95E;CJK COMPATIBILITY IDEOGRAPH-2F95E;Lo;0;L;25AA7;;;;N;;;;; +2F95F;CJK COMPATIBILITY IDEOGRAPH-2F95F;Lo;0;L;7AEE;;;;N;;;;; +2F960;CJK COMPATIBILITY IDEOGRAPH-2F960;Lo;0;L;4202;;;;N;;;;; +2F961;CJK COMPATIBILITY IDEOGRAPH-2F961;Lo;0;L;25BAB;;;;N;;;;; +2F962;CJK COMPATIBILITY IDEOGRAPH-2F962;Lo;0;L;7BC6;;;;N;;;;; +2F963;CJK COMPATIBILITY IDEOGRAPH-2F963;Lo;0;L;7BC9;;;;N;;;;; +2F964;CJK COMPATIBILITY IDEOGRAPH-2F964;Lo;0;L;4227;;;;N;;;;; +2F965;CJK COMPATIBILITY IDEOGRAPH-2F965;Lo;0;L;25C80;;;;N;;;;; +2F966;CJK COMPATIBILITY IDEOGRAPH-2F966;Lo;0;L;7CD2;;;;N;;;;; +2F967;CJK COMPATIBILITY IDEOGRAPH-2F967;Lo;0;L;42A0;;;;N;;;;; +2F968;CJK COMPATIBILITY IDEOGRAPH-2F968;Lo;0;L;7CE8;;;;N;;;;; +2F969;CJK COMPATIBILITY IDEOGRAPH-2F969;Lo;0;L;7CE3;;;;N;;;;; +2F96A;CJK COMPATIBILITY IDEOGRAPH-2F96A;Lo;0;L;7D00;;;;N;;;;; +2F96B;CJK COMPATIBILITY IDEOGRAPH-2F96B;Lo;0;L;25F86;;;;N;;;;; +2F96C;CJK COMPATIBILITY IDEOGRAPH-2F96C;Lo;0;L;7D63;;;;N;;;;; +2F96D;CJK COMPATIBILITY IDEOGRAPH-2F96D;Lo;0;L;4301;;;;N;;;;; +2F96E;CJK COMPATIBILITY IDEOGRAPH-2F96E;Lo;0;L;7DC7;;;;N;;;;; +2F96F;CJK COMPATIBILITY IDEOGRAPH-2F96F;Lo;0;L;7E02;;;;N;;;;; +2F970;CJK COMPATIBILITY IDEOGRAPH-2F970;Lo;0;L;7E45;;;;N;;;;; +2F971;CJK COMPATIBILITY IDEOGRAPH-2F971;Lo;0;L;4334;;;;N;;;;; +2F972;CJK COMPATIBILITY IDEOGRAPH-2F972;Lo;0;L;26228;;;;N;;;;; +2F973;CJK COMPATIBILITY IDEOGRAPH-2F973;Lo;0;L;26247;;;;N;;;;; +2F974;CJK COMPATIBILITY IDEOGRAPH-2F974;Lo;0;L;4359;;;;N;;;;; +2F975;CJK COMPATIBILITY IDEOGRAPH-2F975;Lo;0;L;262D9;;;;N;;;;; +2F976;CJK COMPATIBILITY IDEOGRAPH-2F976;Lo;0;L;7F7A;;;;N;;;;; +2F977;CJK COMPATIBILITY IDEOGRAPH-2F977;Lo;0;L;2633E;;;;N;;;;; +2F978;CJK COMPATIBILITY IDEOGRAPH-2F978;Lo;0;L;7F95;;;;N;;;;; +2F979;CJK COMPATIBILITY IDEOGRAPH-2F979;Lo;0;L;7FFA;;;;N;;;;; +2F97A;CJK COMPATIBILITY IDEOGRAPH-2F97A;Lo;0;L;8005;;;;N;;;;; +2F97B;CJK COMPATIBILITY IDEOGRAPH-2F97B;Lo;0;L;264DA;;;;N;;;;; +2F97C;CJK COMPATIBILITY IDEOGRAPH-2F97C;Lo;0;L;26523;;;;N;;;;; +2F97D;CJK COMPATIBILITY IDEOGRAPH-2F97D;Lo;0;L;8060;;;;N;;;;; +2F97E;CJK COMPATIBILITY IDEOGRAPH-2F97E;Lo;0;L;265A8;;;;N;;;;; +2F97F;CJK COMPATIBILITY IDEOGRAPH-2F97F;Lo;0;L;8070;;;;N;;;;; +2F980;CJK COMPATIBILITY IDEOGRAPH-2F980;Lo;0;L;2335F;;;;N;;;;; +2F981;CJK COMPATIBILITY IDEOGRAPH-2F981;Lo;0;L;43D5;;;;N;;;;; +2F982;CJK COMPATIBILITY IDEOGRAPH-2F982;Lo;0;L;80B2;;;;N;;;;; +2F983;CJK COMPATIBILITY IDEOGRAPH-2F983;Lo;0;L;8103;;;;N;;;;; +2F984;CJK COMPATIBILITY IDEOGRAPH-2F984;Lo;0;L;440B;;;;N;;;;; +2F985;CJK COMPATIBILITY IDEOGRAPH-2F985;Lo;0;L;813E;;;;N;;;;; +2F986;CJK COMPATIBILITY IDEOGRAPH-2F986;Lo;0;L;5AB5;;;;N;;;;; +2F987;CJK COMPATIBILITY IDEOGRAPH-2F987;Lo;0;L;267A7;;;;N;;;;; +2F988;CJK COMPATIBILITY IDEOGRAPH-2F988;Lo;0;L;267B5;;;;N;;;;; +2F989;CJK COMPATIBILITY IDEOGRAPH-2F989;Lo;0;L;23393;;;;N;;;;; +2F98A;CJK COMPATIBILITY IDEOGRAPH-2F98A;Lo;0;L;2339C;;;;N;;;;; +2F98B;CJK COMPATIBILITY IDEOGRAPH-2F98B;Lo;0;L;8201;;;;N;;;;; +2F98C;CJK COMPATIBILITY IDEOGRAPH-2F98C;Lo;0;L;8204;;;;N;;;;; +2F98D;CJK COMPATIBILITY IDEOGRAPH-2F98D;Lo;0;L;8F9E;;;;N;;;;; +2F98E;CJK COMPATIBILITY IDEOGRAPH-2F98E;Lo;0;L;446B;;;;N;;;;; +2F98F;CJK COMPATIBILITY IDEOGRAPH-2F98F;Lo;0;L;8291;;;;N;;;;; +2F990;CJK COMPATIBILITY IDEOGRAPH-2F990;Lo;0;L;828B;;;;N;;;;; +2F991;CJK COMPATIBILITY IDEOGRAPH-2F991;Lo;0;L;829D;;;;N;;;;; +2F992;CJK COMPATIBILITY IDEOGRAPH-2F992;Lo;0;L;52B3;;;;N;;;;; +2F993;CJK COMPATIBILITY IDEOGRAPH-2F993;Lo;0;L;82B1;;;;N;;;;; +2F994;CJK COMPATIBILITY IDEOGRAPH-2F994;Lo;0;L;82B3;;;;N;;;;; +2F995;CJK COMPATIBILITY IDEOGRAPH-2F995;Lo;0;L;82BD;;;;N;;;;; +2F996;CJK COMPATIBILITY IDEOGRAPH-2F996;Lo;0;L;82E6;;;;N;;;;; +2F997;CJK COMPATIBILITY IDEOGRAPH-2F997;Lo;0;L;26B3C;;;;N;;;;; +2F998;CJK COMPATIBILITY IDEOGRAPH-2F998;Lo;0;L;82E5;;;;N;;;;; +2F999;CJK COMPATIBILITY IDEOGRAPH-2F999;Lo;0;L;831D;;;;N;;;;; +2F99A;CJK COMPATIBILITY IDEOGRAPH-2F99A;Lo;0;L;8363;;;;N;;;;; +2F99B;CJK COMPATIBILITY IDEOGRAPH-2F99B;Lo;0;L;83AD;;;;N;;;;; +2F99C;CJK COMPATIBILITY IDEOGRAPH-2F99C;Lo;0;L;8323;;;;N;;;;; +2F99D;CJK COMPATIBILITY IDEOGRAPH-2F99D;Lo;0;L;83BD;;;;N;;;;; +2F99E;CJK COMPATIBILITY IDEOGRAPH-2F99E;Lo;0;L;83E7;;;;N;;;;; +2F99F;CJK COMPATIBILITY IDEOGRAPH-2F99F;Lo;0;L;8457;;;;N;;;;; +2F9A0;CJK COMPATIBILITY IDEOGRAPH-2F9A0;Lo;0;L;8353;;;;N;;;;; +2F9A1;CJK COMPATIBILITY IDEOGRAPH-2F9A1;Lo;0;L;83CA;;;;N;;;;; +2F9A2;CJK COMPATIBILITY IDEOGRAPH-2F9A2;Lo;0;L;83CC;;;;N;;;;; +2F9A3;CJK COMPATIBILITY IDEOGRAPH-2F9A3;Lo;0;L;83DC;;;;N;;;;; +2F9A4;CJK COMPATIBILITY IDEOGRAPH-2F9A4;Lo;0;L;26C36;;;;N;;;;; +2F9A5;CJK COMPATIBILITY IDEOGRAPH-2F9A5;Lo;0;L;26D6B;;;;N;;;;; +2F9A6;CJK COMPATIBILITY IDEOGRAPH-2F9A6;Lo;0;L;26CD5;;;;N;;;;; +2F9A7;CJK COMPATIBILITY IDEOGRAPH-2F9A7;Lo;0;L;452B;;;;N;;;;; +2F9A8;CJK COMPATIBILITY IDEOGRAPH-2F9A8;Lo;0;L;84F1;;;;N;;;;; +2F9A9;CJK COMPATIBILITY IDEOGRAPH-2F9A9;Lo;0;L;84F3;;;;N;;;;; +2F9AA;CJK COMPATIBILITY IDEOGRAPH-2F9AA;Lo;0;L;8516;;;;N;;;;; +2F9AB;CJK COMPATIBILITY IDEOGRAPH-2F9AB;Lo;0;L;273CA;;;;N;;;;; +2F9AC;CJK COMPATIBILITY IDEOGRAPH-2F9AC;Lo;0;L;8564;;;;N;;;;; +2F9AD;CJK COMPATIBILITY IDEOGRAPH-2F9AD;Lo;0;L;26F2C;;;;N;;;;; +2F9AE;CJK COMPATIBILITY IDEOGRAPH-2F9AE;Lo;0;L;455D;;;;N;;;;; +2F9AF;CJK COMPATIBILITY IDEOGRAPH-2F9AF;Lo;0;L;4561;;;;N;;;;; +2F9B0;CJK COMPATIBILITY IDEOGRAPH-2F9B0;Lo;0;L;26FB1;;;;N;;;;; +2F9B1;CJK COMPATIBILITY IDEOGRAPH-2F9B1;Lo;0;L;270D2;;;;N;;;;; +2F9B2;CJK COMPATIBILITY IDEOGRAPH-2F9B2;Lo;0;L;456B;;;;N;;;;; +2F9B3;CJK COMPATIBILITY IDEOGRAPH-2F9B3;Lo;0;L;8650;;;;N;;;;; +2F9B4;CJK COMPATIBILITY IDEOGRAPH-2F9B4;Lo;0;L;865C;;;;N;;;;; +2F9B5;CJK COMPATIBILITY IDEOGRAPH-2F9B5;Lo;0;L;8667;;;;N;;;;; +2F9B6;CJK COMPATIBILITY IDEOGRAPH-2F9B6;Lo;0;L;8669;;;;N;;;;; +2F9B7;CJK COMPATIBILITY IDEOGRAPH-2F9B7;Lo;0;L;86A9;;;;N;;;;; +2F9B8;CJK COMPATIBILITY IDEOGRAPH-2F9B8;Lo;0;L;8688;;;;N;;;;; +2F9B9;CJK COMPATIBILITY IDEOGRAPH-2F9B9;Lo;0;L;870E;;;;N;;;;; +2F9BA;CJK COMPATIBILITY IDEOGRAPH-2F9BA;Lo;0;L;86E2;;;;N;;;;; +2F9BB;CJK COMPATIBILITY IDEOGRAPH-2F9BB;Lo;0;L;8779;;;;N;;;;; +2F9BC;CJK COMPATIBILITY IDEOGRAPH-2F9BC;Lo;0;L;8728;;;;N;;;;; +2F9BD;CJK COMPATIBILITY IDEOGRAPH-2F9BD;Lo;0;L;876B;;;;N;;;;; +2F9BE;CJK COMPATIBILITY IDEOGRAPH-2F9BE;Lo;0;L;8786;;;;N;;;;; +2F9BF;CJK COMPATIBILITY IDEOGRAPH-2F9BF;Lo;0;L;45D7;;;;N;;;;; +2F9C0;CJK COMPATIBILITY IDEOGRAPH-2F9C0;Lo;0;L;87E1;;;;N;;;;; +2F9C1;CJK COMPATIBILITY IDEOGRAPH-2F9C1;Lo;0;L;8801;;;;N;;;;; +2F9C2;CJK COMPATIBILITY IDEOGRAPH-2F9C2;Lo;0;L;45F9;;;;N;;;;; +2F9C3;CJK COMPATIBILITY IDEOGRAPH-2F9C3;Lo;0;L;8860;;;;N;;;;; +2F9C4;CJK COMPATIBILITY IDEOGRAPH-2F9C4;Lo;0;L;8863;;;;N;;;;; +2F9C5;CJK COMPATIBILITY IDEOGRAPH-2F9C5;Lo;0;L;27667;;;;N;;;;; +2F9C6;CJK COMPATIBILITY IDEOGRAPH-2F9C6;Lo;0;L;88D7;;;;N;;;;; +2F9C7;CJK COMPATIBILITY IDEOGRAPH-2F9C7;Lo;0;L;88DE;;;;N;;;;; +2F9C8;CJK COMPATIBILITY IDEOGRAPH-2F9C8;Lo;0;L;4635;;;;N;;;;; +2F9C9;CJK COMPATIBILITY IDEOGRAPH-2F9C9;Lo;0;L;88FA;;;;N;;;;; +2F9CA;CJK COMPATIBILITY IDEOGRAPH-2F9CA;Lo;0;L;34BB;;;;N;;;;; +2F9CB;CJK COMPATIBILITY IDEOGRAPH-2F9CB;Lo;0;L;278AE;;;;N;;;;; +2F9CC;CJK COMPATIBILITY IDEOGRAPH-2F9CC;Lo;0;L;27966;;;;N;;;;; +2F9CD;CJK COMPATIBILITY IDEOGRAPH-2F9CD;Lo;0;L;46BE;;;;N;;;;; +2F9CE;CJK COMPATIBILITY IDEOGRAPH-2F9CE;Lo;0;L;46C7;;;;N;;;;; +2F9CF;CJK COMPATIBILITY IDEOGRAPH-2F9CF;Lo;0;L;8AA0;;;;N;;;;; +2F9D0;CJK COMPATIBILITY IDEOGRAPH-2F9D0;Lo;0;L;8AED;;;;N;;;;; +2F9D1;CJK COMPATIBILITY IDEOGRAPH-2F9D1;Lo;0;L;8B8A;;;;N;;;;; +2F9D2;CJK COMPATIBILITY IDEOGRAPH-2F9D2;Lo;0;L;8C55;;;;N;;;;; +2F9D3;CJK COMPATIBILITY IDEOGRAPH-2F9D3;Lo;0;L;27CA8;;;;N;;;;; +2F9D4;CJK COMPATIBILITY IDEOGRAPH-2F9D4;Lo;0;L;8CAB;;;;N;;;;; +2F9D5;CJK COMPATIBILITY IDEOGRAPH-2F9D5;Lo;0;L;8CC1;;;;N;;;;; +2F9D6;CJK COMPATIBILITY IDEOGRAPH-2F9D6;Lo;0;L;8D1B;;;;N;;;;; +2F9D7;CJK COMPATIBILITY IDEOGRAPH-2F9D7;Lo;0;L;8D77;;;;N;;;;; +2F9D8;CJK COMPATIBILITY IDEOGRAPH-2F9D8;Lo;0;L;27F2F;;;;N;;;;; +2F9D9;CJK COMPATIBILITY IDEOGRAPH-2F9D9;Lo;0;L;20804;;;;N;;;;; +2F9DA;CJK COMPATIBILITY IDEOGRAPH-2F9DA;Lo;0;L;8DCB;;;;N;;;;; +2F9DB;CJK COMPATIBILITY IDEOGRAPH-2F9DB;Lo;0;L;8DBC;;;;N;;;;; +2F9DC;CJK COMPATIBILITY IDEOGRAPH-2F9DC;Lo;0;L;8DF0;;;;N;;;;; +2F9DD;CJK COMPATIBILITY IDEOGRAPH-2F9DD;Lo;0;L;208DE;;;;N;;;;; +2F9DE;CJK COMPATIBILITY IDEOGRAPH-2F9DE;Lo;0;L;8ED4;;;;N;;;;; +2F9DF;CJK COMPATIBILITY IDEOGRAPH-2F9DF;Lo;0;L;8F38;;;;N;;;;; +2F9E0;CJK COMPATIBILITY IDEOGRAPH-2F9E0;Lo;0;L;285D2;;;;N;;;;; +2F9E1;CJK COMPATIBILITY IDEOGRAPH-2F9E1;Lo;0;L;285ED;;;;N;;;;; +2F9E2;CJK COMPATIBILITY IDEOGRAPH-2F9E2;Lo;0;L;9094;;;;N;;;;; +2F9E3;CJK COMPATIBILITY IDEOGRAPH-2F9E3;Lo;0;L;90F1;;;;N;;;;; +2F9E4;CJK COMPATIBILITY IDEOGRAPH-2F9E4;Lo;0;L;9111;;;;N;;;;; +2F9E5;CJK COMPATIBILITY IDEOGRAPH-2F9E5;Lo;0;L;2872E;;;;N;;;;; +2F9E6;CJK COMPATIBILITY IDEOGRAPH-2F9E6;Lo;0;L;911B;;;;N;;;;; +2F9E7;CJK COMPATIBILITY IDEOGRAPH-2F9E7;Lo;0;L;9238;;;;N;;;;; +2F9E8;CJK COMPATIBILITY IDEOGRAPH-2F9E8;Lo;0;L;92D7;;;;N;;;;; +2F9E9;CJK COMPATIBILITY IDEOGRAPH-2F9E9;Lo;0;L;92D8;;;;N;;;;; +2F9EA;CJK COMPATIBILITY IDEOGRAPH-2F9EA;Lo;0;L;927C;;;;N;;;;; +2F9EB;CJK COMPATIBILITY IDEOGRAPH-2F9EB;Lo;0;L;93F9;;;;N;;;;; +2F9EC;CJK COMPATIBILITY IDEOGRAPH-2F9EC;Lo;0;L;9415;;;;N;;;;; +2F9ED;CJK COMPATIBILITY IDEOGRAPH-2F9ED;Lo;0;L;28BFA;;;;N;;;;; +2F9EE;CJK COMPATIBILITY IDEOGRAPH-2F9EE;Lo;0;L;958B;;;;N;;;;; +2F9EF;CJK COMPATIBILITY IDEOGRAPH-2F9EF;Lo;0;L;4995;;;;N;;;;; +2F9F0;CJK COMPATIBILITY IDEOGRAPH-2F9F0;Lo;0;L;95B7;;;;N;;;;; +2F9F1;CJK COMPATIBILITY IDEOGRAPH-2F9F1;Lo;0;L;28D77;;;;N;;;;; +2F9F2;CJK COMPATIBILITY IDEOGRAPH-2F9F2;Lo;0;L;49E6;;;;N;;;;; +2F9F3;CJK COMPATIBILITY IDEOGRAPH-2F9F3;Lo;0;L;96C3;;;;N;;;;; +2F9F4;CJK COMPATIBILITY IDEOGRAPH-2F9F4;Lo;0;L;5DB2;;;;N;;;;; +2F9F5;CJK COMPATIBILITY IDEOGRAPH-2F9F5;Lo;0;L;9723;;;;N;;;;; +2F9F6;CJK COMPATIBILITY IDEOGRAPH-2F9F6;Lo;0;L;29145;;;;N;;;;; +2F9F7;CJK COMPATIBILITY IDEOGRAPH-2F9F7;Lo;0;L;2921A;;;;N;;;;; +2F9F8;CJK COMPATIBILITY IDEOGRAPH-2F9F8;Lo;0;L;4A6E;;;;N;;;;; +2F9F9;CJK COMPATIBILITY IDEOGRAPH-2F9F9;Lo;0;L;4A76;;;;N;;;;; +2F9FA;CJK COMPATIBILITY IDEOGRAPH-2F9FA;Lo;0;L;97E0;;;;N;;;;; +2F9FB;CJK COMPATIBILITY IDEOGRAPH-2F9FB;Lo;0;L;2940A;;;;N;;;;; +2F9FC;CJK COMPATIBILITY IDEOGRAPH-2F9FC;Lo;0;L;4AB2;;;;N;;;;; +2F9FD;CJK COMPATIBILITY IDEOGRAPH-2F9FD;Lo;0;L;29496;;;;N;;;;; +2F9FE;CJK COMPATIBILITY IDEOGRAPH-2F9FE;Lo;0;L;980B;;;;N;;;;; +2F9FF;CJK COMPATIBILITY IDEOGRAPH-2F9FF;Lo;0;L;980B;;;;N;;;;; +2FA00;CJK COMPATIBILITY IDEOGRAPH-2FA00;Lo;0;L;9829;;;;N;;;;; +2FA01;CJK COMPATIBILITY IDEOGRAPH-2FA01;Lo;0;L;295B6;;;;N;;;;; +2FA02;CJK COMPATIBILITY IDEOGRAPH-2FA02;Lo;0;L;98E2;;;;N;;;;; +2FA03;CJK COMPATIBILITY IDEOGRAPH-2FA03;Lo;0;L;4B33;;;;N;;;;; +2FA04;CJK COMPATIBILITY IDEOGRAPH-2FA04;Lo;0;L;9929;;;;N;;;;; +2FA05;CJK COMPATIBILITY IDEOGRAPH-2FA05;Lo;0;L;99A7;;;;N;;;;; +2FA06;CJK COMPATIBILITY IDEOGRAPH-2FA06;Lo;0;L;99C2;;;;N;;;;; +2FA07;CJK COMPATIBILITY IDEOGRAPH-2FA07;Lo;0;L;99FE;;;;N;;;;; +2FA08;CJK COMPATIBILITY IDEOGRAPH-2FA08;Lo;0;L;4BCE;;;;N;;;;; +2FA09;CJK COMPATIBILITY IDEOGRAPH-2FA09;Lo;0;L;29B30;;;;N;;;;; +2FA0A;CJK COMPATIBILITY IDEOGRAPH-2FA0A;Lo;0;L;9B12;;;;N;;;;; +2FA0B;CJK COMPATIBILITY IDEOGRAPH-2FA0B;Lo;0;L;9C40;;;;N;;;;; +2FA0C;CJK COMPATIBILITY IDEOGRAPH-2FA0C;Lo;0;L;9CFD;;;;N;;;;; +2FA0D;CJK COMPATIBILITY IDEOGRAPH-2FA0D;Lo;0;L;4CCE;;;;N;;;;; +2FA0E;CJK COMPATIBILITY IDEOGRAPH-2FA0E;Lo;0;L;4CED;;;;N;;;;; +2FA0F;CJK COMPATIBILITY IDEOGRAPH-2FA0F;Lo;0;L;9D67;;;;N;;;;; +2FA10;CJK COMPATIBILITY IDEOGRAPH-2FA10;Lo;0;L;2A0CE;;;;N;;;;; +2FA11;CJK COMPATIBILITY IDEOGRAPH-2FA11;Lo;0;L;4CF8;;;;N;;;;; +2FA12;CJK COMPATIBILITY IDEOGRAPH-2FA12;Lo;0;L;2A105;;;;N;;;;; +2FA13;CJK COMPATIBILITY IDEOGRAPH-2FA13;Lo;0;L;2A20E;;;;N;;;;; +2FA14;CJK COMPATIBILITY IDEOGRAPH-2FA14;Lo;0;L;2A291;;;;N;;;;; +2FA15;CJK COMPATIBILITY IDEOGRAPH-2FA15;Lo;0;L;9EBB;;;;N;;;;; +2FA16;CJK COMPATIBILITY IDEOGRAPH-2FA16;Lo;0;L;4D56;;;;N;;;;; +2FA17;CJK COMPATIBILITY IDEOGRAPH-2FA17;Lo;0;L;9EF9;;;;N;;;;; +2FA18;CJK COMPATIBILITY IDEOGRAPH-2FA18;Lo;0;L;9EFE;;;;N;;;;; +2FA19;CJK COMPATIBILITY IDEOGRAPH-2FA19;Lo;0;L;9F05;;;;N;;;;; +2FA1A;CJK COMPATIBILITY IDEOGRAPH-2FA1A;Lo;0;L;9F0F;;;;N;;;;; +2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;; +2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;; +2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;; +E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;; +E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;; +E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;; +E0022;TAG QUOTATION MARK;Cf;0;BN;;;;;N;;;;; +E0023;TAG NUMBER SIGN;Cf;0;BN;;;;;N;;;;; +E0024;TAG DOLLAR SIGN;Cf;0;BN;;;;;N;;;;; +E0025;TAG PERCENT SIGN;Cf;0;BN;;;;;N;;;;; +E0026;TAG AMPERSAND;Cf;0;BN;;;;;N;;;;; +E0027;TAG APOSTROPHE;Cf;0;BN;;;;;N;;;;; +E0028;TAG LEFT PARENTHESIS;Cf;0;BN;;;;;N;;;;; +E0029;TAG RIGHT PARENTHESIS;Cf;0;BN;;;;;N;;;;; +E002A;TAG ASTERISK;Cf;0;BN;;;;;N;;;;; +E002B;TAG PLUS SIGN;Cf;0;BN;;;;;N;;;;; +E002C;TAG COMMA;Cf;0;BN;;;;;N;;;;; +E002D;TAG HYPHEN-MINUS;Cf;0;BN;;;;;N;;;;; +E002E;TAG FULL STOP;Cf;0;BN;;;;;N;;;;; +E002F;TAG SOLIDUS;Cf;0;BN;;;;;N;;;;; +E0030;TAG DIGIT ZERO;Cf;0;BN;;;;;N;;;;; +E0031;TAG DIGIT ONE;Cf;0;BN;;;;;N;;;;; +E0032;TAG DIGIT TWO;Cf;0;BN;;;;;N;;;;; +E0033;TAG DIGIT THREE;Cf;0;BN;;;;;N;;;;; +E0034;TAG DIGIT FOUR;Cf;0;BN;;;;;N;;;;; +E0035;TAG DIGIT FIVE;Cf;0;BN;;;;;N;;;;; +E0036;TAG DIGIT SIX;Cf;0;BN;;;;;N;;;;; +E0037;TAG DIGIT SEVEN;Cf;0;BN;;;;;N;;;;; +E0038;TAG DIGIT EIGHT;Cf;0;BN;;;;;N;;;;; +E0039;TAG DIGIT NINE;Cf;0;BN;;;;;N;;;;; +E003A;TAG COLON;Cf;0;BN;;;;;N;;;;; +E003B;TAG SEMICOLON;Cf;0;BN;;;;;N;;;;; +E003C;TAG LESS-THAN SIGN;Cf;0;BN;;;;;N;;;;; +E003D;TAG EQUALS SIGN;Cf;0;BN;;;;;N;;;;; +E003E;TAG GREATER-THAN SIGN;Cf;0;BN;;;;;N;;;;; +E003F;TAG QUESTION MARK;Cf;0;BN;;;;;N;;;;; +E0040;TAG COMMERCIAL AT;Cf;0;BN;;;;;N;;;;; +E0041;TAG LATIN CAPITAL LETTER A;Cf;0;BN;;;;;N;;;;; +E0042;TAG LATIN CAPITAL LETTER B;Cf;0;BN;;;;;N;;;;; +E0043;TAG LATIN CAPITAL LETTER C;Cf;0;BN;;;;;N;;;;; +E0044;TAG LATIN CAPITAL LETTER D;Cf;0;BN;;;;;N;;;;; +E0045;TAG LATIN CAPITAL LETTER E;Cf;0;BN;;;;;N;;;;; +E0046;TAG LATIN CAPITAL LETTER F;Cf;0;BN;;;;;N;;;;; +E0047;TAG LATIN CAPITAL LETTER G;Cf;0;BN;;;;;N;;;;; +E0048;TAG LATIN CAPITAL LETTER H;Cf;0;BN;;;;;N;;;;; +E0049;TAG LATIN CAPITAL LETTER I;Cf;0;BN;;;;;N;;;;; +E004A;TAG LATIN CAPITAL LETTER J;Cf;0;BN;;;;;N;;;;; +E004B;TAG LATIN CAPITAL LETTER K;Cf;0;BN;;;;;N;;;;; +E004C;TAG LATIN CAPITAL LETTER L;Cf;0;BN;;;;;N;;;;; +E004D;TAG LATIN CAPITAL LETTER M;Cf;0;BN;;;;;N;;;;; +E004E;TAG LATIN CAPITAL LETTER N;Cf;0;BN;;;;;N;;;;; +E004F;TAG LATIN CAPITAL LETTER O;Cf;0;BN;;;;;N;;;;; +E0050;TAG LATIN CAPITAL LETTER P;Cf;0;BN;;;;;N;;;;; +E0051;TAG LATIN CAPITAL LETTER Q;Cf;0;BN;;;;;N;;;;; +E0052;TAG LATIN CAPITAL LETTER R;Cf;0;BN;;;;;N;;;;; +E0053;TAG LATIN CAPITAL LETTER S;Cf;0;BN;;;;;N;;;;; +E0054;TAG LATIN CAPITAL LETTER T;Cf;0;BN;;;;;N;;;;; +E0055;TAG LATIN CAPITAL LETTER U;Cf;0;BN;;;;;N;;;;; +E0056;TAG LATIN CAPITAL LETTER V;Cf;0;BN;;;;;N;;;;; +E0057;TAG LATIN CAPITAL LETTER W;Cf;0;BN;;;;;N;;;;; +E0058;TAG LATIN CAPITAL LETTER X;Cf;0;BN;;;;;N;;;;; +E0059;TAG LATIN CAPITAL LETTER Y;Cf;0;BN;;;;;N;;;;; +E005A;TAG LATIN CAPITAL LETTER Z;Cf;0;BN;;;;;N;;;;; +E005B;TAG LEFT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;; +E005C;TAG REVERSE SOLIDUS;Cf;0;BN;;;;;N;;;;; +E005D;TAG RIGHT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;; +E005E;TAG CIRCUMFLEX ACCENT;Cf;0;BN;;;;;N;;;;; +E005F;TAG LOW LINE;Cf;0;BN;;;;;N;;;;; +E0060;TAG GRAVE ACCENT;Cf;0;BN;;;;;N;;;;; +E0061;TAG LATIN SMALL LETTER A;Cf;0;BN;;;;;N;;;;; +E0062;TAG LATIN SMALL LETTER B;Cf;0;BN;;;;;N;;;;; +E0063;TAG LATIN SMALL LETTER C;Cf;0;BN;;;;;N;;;;; +E0064;TAG LATIN SMALL LETTER D;Cf;0;BN;;;;;N;;;;; +E0065;TAG LATIN SMALL LETTER E;Cf;0;BN;;;;;N;;;;; +E0066;TAG LATIN SMALL LETTER F;Cf;0;BN;;;;;N;;;;; +E0067;TAG LATIN SMALL LETTER G;Cf;0;BN;;;;;N;;;;; +E0068;TAG LATIN SMALL LETTER H;Cf;0;BN;;;;;N;;;;; +E0069;TAG LATIN SMALL LETTER I;Cf;0;BN;;;;;N;;;;; +E006A;TAG LATIN SMALL LETTER J;Cf;0;BN;;;;;N;;;;; +E006B;TAG LATIN SMALL LETTER K;Cf;0;BN;;;;;N;;;;; +E006C;TAG LATIN SMALL LETTER L;Cf;0;BN;;;;;N;;;;; +E006D;TAG LATIN SMALL LETTER M;Cf;0;BN;;;;;N;;;;; +E006E;TAG LATIN SMALL LETTER N;Cf;0;BN;;;;;N;;;;; +E006F;TAG LATIN SMALL LETTER O;Cf;0;BN;;;;;N;;;;; +E0070;TAG LATIN SMALL LETTER P;Cf;0;BN;;;;;N;;;;; +E0071;TAG LATIN SMALL LETTER Q;Cf;0;BN;;;;;N;;;;; +E0072;TAG LATIN SMALL LETTER R;Cf;0;BN;;;;;N;;;;; +E0073;TAG LATIN SMALL LETTER S;Cf;0;BN;;;;;N;;;;; +E0074;TAG LATIN SMALL LETTER T;Cf;0;BN;;;;;N;;;;; +E0075;TAG LATIN SMALL LETTER U;Cf;0;BN;;;;;N;;;;; +E0076;TAG LATIN SMALL LETTER V;Cf;0;BN;;;;;N;;;;; +E0077;TAG LATIN SMALL LETTER W;Cf;0;BN;;;;;N;;;;; +E0078;TAG LATIN SMALL LETTER X;Cf;0;BN;;;;;N;;;;; +E0079;TAG LATIN SMALL LETTER Y;Cf;0;BN;;;;;N;;;;; +E007A;TAG LATIN SMALL LETTER Z;Cf;0;BN;;;;;N;;;;; +E007B;TAG LEFT CURLY BRACKET;Cf;0;BN;;;;;N;;;;; +E007C;TAG VERTICAL LINE;Cf;0;BN;;;;;N;;;;; +E007D;TAG RIGHT CURLY BRACKET;Cf;0;BN;;;;;N;;;;; +E007E;TAG TILDE;Cf;0;BN;;;;;N;;;;; +E007F;CANCEL TAG;Cf;0;BN;;;;;N;;;;; +E0100;VARIATION SELECTOR-17;Mn;0;NSM;;;;;N;;;;; +E0101;VARIATION SELECTOR-18;Mn;0;NSM;;;;;N;;;;; +E0102;VARIATION SELECTOR-19;Mn;0;NSM;;;;;N;;;;; +E0103;VARIATION SELECTOR-20;Mn;0;NSM;;;;;N;;;;; +E0104;VARIATION SELECTOR-21;Mn;0;NSM;;;;;N;;;;; +E0105;VARIATION SELECTOR-22;Mn;0;NSM;;;;;N;;;;; +E0106;VARIATION SELECTOR-23;Mn;0;NSM;;;;;N;;;;; +E0107;VARIATION SELECTOR-24;Mn;0;NSM;;;;;N;;;;; +E0108;VARIATION SELECTOR-25;Mn;0;NSM;;;;;N;;;;; +E0109;VARIATION SELECTOR-26;Mn;0;NSM;;;;;N;;;;; +E010A;VARIATION SELECTOR-27;Mn;0;NSM;;;;;N;;;;; +E010B;VARIATION SELECTOR-28;Mn;0;NSM;;;;;N;;;;; +E010C;VARIATION SELECTOR-29;Mn;0;NSM;;;;;N;;;;; +E010D;VARIATION SELECTOR-30;Mn;0;NSM;;;;;N;;;;; +E010E;VARIATION SELECTOR-31;Mn;0;NSM;;;;;N;;;;; +E010F;VARIATION SELECTOR-32;Mn;0;NSM;;;;;N;;;;; +E0110;VARIATION SELECTOR-33;Mn;0;NSM;;;;;N;;;;; +E0111;VARIATION SELECTOR-34;Mn;0;NSM;;;;;N;;;;; +E0112;VARIATION SELECTOR-35;Mn;0;NSM;;;;;N;;;;; +E0113;VARIATION SELECTOR-36;Mn;0;NSM;;;;;N;;;;; +E0114;VARIATION SELECTOR-37;Mn;0;NSM;;;;;N;;;;; +E0115;VARIATION SELECTOR-38;Mn;0;NSM;;;;;N;;;;; +E0116;VARIATION SELECTOR-39;Mn;0;NSM;;;;;N;;;;; +E0117;VARIATION SELECTOR-40;Mn;0;NSM;;;;;N;;;;; +E0118;VARIATION SELECTOR-41;Mn;0;NSM;;;;;N;;;;; +E0119;VARIATION SELECTOR-42;Mn;0;NSM;;;;;N;;;;; +E011A;VARIATION SELECTOR-43;Mn;0;NSM;;;;;N;;;;; +E011B;VARIATION SELECTOR-44;Mn;0;NSM;;;;;N;;;;; +E011C;VARIATION SELECTOR-45;Mn;0;NSM;;;;;N;;;;; +E011D;VARIATION SELECTOR-46;Mn;0;NSM;;;;;N;;;;; +E011E;VARIATION SELECTOR-47;Mn;0;NSM;;;;;N;;;;; +E011F;VARIATION SELECTOR-48;Mn;0;NSM;;;;;N;;;;; +E0120;VARIATION SELECTOR-49;Mn;0;NSM;;;;;N;;;;; +E0121;VARIATION SELECTOR-50;Mn;0;NSM;;;;;N;;;;; +E0122;VARIATION SELECTOR-51;Mn;0;NSM;;;;;N;;;;; +E0123;VARIATION SELECTOR-52;Mn;0;NSM;;;;;N;;;;; +E0124;VARIATION SELECTOR-53;Mn;0;NSM;;;;;N;;;;; +E0125;VARIATION SELECTOR-54;Mn;0;NSM;;;;;N;;;;; +E0126;VARIATION SELECTOR-55;Mn;0;NSM;;;;;N;;;;; +E0127;VARIATION SELECTOR-56;Mn;0;NSM;;;;;N;;;;; +E0128;VARIATION SELECTOR-57;Mn;0;NSM;;;;;N;;;;; +E0129;VARIATION SELECTOR-58;Mn;0;NSM;;;;;N;;;;; +E012A;VARIATION SELECTOR-59;Mn;0;NSM;;;;;N;;;;; +E012B;VARIATION SELECTOR-60;Mn;0;NSM;;;;;N;;;;; +E012C;VARIATION SELECTOR-61;Mn;0;NSM;;;;;N;;;;; +E012D;VARIATION SELECTOR-62;Mn;0;NSM;;;;;N;;;;; +E012E;VARIATION SELECTOR-63;Mn;0;NSM;;;;;N;;;;; +E012F;VARIATION SELECTOR-64;Mn;0;NSM;;;;;N;;;;; +E0130;VARIATION SELECTOR-65;Mn;0;NSM;;;;;N;;;;; +E0131;VARIATION SELECTOR-66;Mn;0;NSM;;;;;N;;;;; +E0132;VARIATION SELECTOR-67;Mn;0;NSM;;;;;N;;;;; +E0133;VARIATION SELECTOR-68;Mn;0;NSM;;;;;N;;;;; +E0134;VARIATION SELECTOR-69;Mn;0;NSM;;;;;N;;;;; +E0135;VARIATION SELECTOR-70;Mn;0;NSM;;;;;N;;;;; +E0136;VARIATION SELECTOR-71;Mn;0;NSM;;;;;N;;;;; +E0137;VARIATION SELECTOR-72;Mn;0;NSM;;;;;N;;;;; +E0138;VARIATION SELECTOR-73;Mn;0;NSM;;;;;N;;;;; +E0139;VARIATION SELECTOR-74;Mn;0;NSM;;;;;N;;;;; +E013A;VARIATION SELECTOR-75;Mn;0;NSM;;;;;N;;;;; +E013B;VARIATION SELECTOR-76;Mn;0;NSM;;;;;N;;;;; +E013C;VARIATION SELECTOR-77;Mn;0;NSM;;;;;N;;;;; +E013D;VARIATION SELECTOR-78;Mn;0;NSM;;;;;N;;;;; +E013E;VARIATION SELECTOR-79;Mn;0;NSM;;;;;N;;;;; +E013F;VARIATION SELECTOR-80;Mn;0;NSM;;;;;N;;;;; +E0140;VARIATION SELECTOR-81;Mn;0;NSM;;;;;N;;;;; +E0141;VARIATION SELECTOR-82;Mn;0;NSM;;;;;N;;;;; +E0142;VARIATION SELECTOR-83;Mn;0;NSM;;;;;N;;;;; +E0143;VARIATION SELECTOR-84;Mn;0;NSM;;;;;N;;;;; +E0144;VARIATION SELECTOR-85;Mn;0;NSM;;;;;N;;;;; +E0145;VARIATION SELECTOR-86;Mn;0;NSM;;;;;N;;;;; +E0146;VARIATION SELECTOR-87;Mn;0;NSM;;;;;N;;;;; +E0147;VARIATION SELECTOR-88;Mn;0;NSM;;;;;N;;;;; +E0148;VARIATION SELECTOR-89;Mn;0;NSM;;;;;N;;;;; +E0149;VARIATION SELECTOR-90;Mn;0;NSM;;;;;N;;;;; +E014A;VARIATION SELECTOR-91;Mn;0;NSM;;;;;N;;;;; +E014B;VARIATION SELECTOR-92;Mn;0;NSM;;;;;N;;;;; +E014C;VARIATION SELECTOR-93;Mn;0;NSM;;;;;N;;;;; +E014D;VARIATION SELECTOR-94;Mn;0;NSM;;;;;N;;;;; +E014E;VARIATION SELECTOR-95;Mn;0;NSM;;;;;N;;;;; +E014F;VARIATION SELECTOR-96;Mn;0;NSM;;;;;N;;;;; +E0150;VARIATION SELECTOR-97;Mn;0;NSM;;;;;N;;;;; +E0151;VARIATION SELECTOR-98;Mn;0;NSM;;;;;N;;;;; +E0152;VARIATION SELECTOR-99;Mn;0;NSM;;;;;N;;;;; +E0153;VARIATION SELECTOR-100;Mn;0;NSM;;;;;N;;;;; +E0154;VARIATION SELECTOR-101;Mn;0;NSM;;;;;N;;;;; +E0155;VARIATION SELECTOR-102;Mn;0;NSM;;;;;N;;;;; +E0156;VARIATION SELECTOR-103;Mn;0;NSM;;;;;N;;;;; +E0157;VARIATION SELECTOR-104;Mn;0;NSM;;;;;N;;;;; +E0158;VARIATION SELECTOR-105;Mn;0;NSM;;;;;N;;;;; +E0159;VARIATION SELECTOR-106;Mn;0;NSM;;;;;N;;;;; +E015A;VARIATION SELECTOR-107;Mn;0;NSM;;;;;N;;;;; +E015B;VARIATION SELECTOR-108;Mn;0;NSM;;;;;N;;;;; +E015C;VARIATION SELECTOR-109;Mn;0;NSM;;;;;N;;;;; +E015D;VARIATION SELECTOR-110;Mn;0;NSM;;;;;N;;;;; +E015E;VARIATION SELECTOR-111;Mn;0;NSM;;;;;N;;;;; +E015F;VARIATION SELECTOR-112;Mn;0;NSM;;;;;N;;;;; +E0160;VARIATION SELECTOR-113;Mn;0;NSM;;;;;N;;;;; +E0161;VARIATION SELECTOR-114;Mn;0;NSM;;;;;N;;;;; +E0162;VARIATION SELECTOR-115;Mn;0;NSM;;;;;N;;;;; +E0163;VARIATION SELECTOR-116;Mn;0;NSM;;;;;N;;;;; +E0164;VARIATION SELECTOR-117;Mn;0;NSM;;;;;N;;;;; +E0165;VARIATION SELECTOR-118;Mn;0;NSM;;;;;N;;;;; +E0166;VARIATION SELECTOR-119;Mn;0;NSM;;;;;N;;;;; +E0167;VARIATION SELECTOR-120;Mn;0;NSM;;;;;N;;;;; +E0168;VARIATION SELECTOR-121;Mn;0;NSM;;;;;N;;;;; +E0169;VARIATION SELECTOR-122;Mn;0;NSM;;;;;N;;;;; +E016A;VARIATION SELECTOR-123;Mn;0;NSM;;;;;N;;;;; +E016B;VARIATION SELECTOR-124;Mn;0;NSM;;;;;N;;;;; +E016C;VARIATION SELECTOR-125;Mn;0;NSM;;;;;N;;;;; +E016D;VARIATION SELECTOR-126;Mn;0;NSM;;;;;N;;;;; +E016E;VARIATION SELECTOR-127;Mn;0;NSM;;;;;N;;;;; +E016F;VARIATION SELECTOR-128;Mn;0;NSM;;;;;N;;;;; +E0170;VARIATION SELECTOR-129;Mn;0;NSM;;;;;N;;;;; +E0171;VARIATION SELECTOR-130;Mn;0;NSM;;;;;N;;;;; +E0172;VARIATION SELECTOR-131;Mn;0;NSM;;;;;N;;;;; +E0173;VARIATION SELECTOR-132;Mn;0;NSM;;;;;N;;;;; +E0174;VARIATION SELECTOR-133;Mn;0;NSM;;;;;N;;;;; +E0175;VARIATION SELECTOR-134;Mn;0;NSM;;;;;N;;;;; +E0176;VARIATION SELECTOR-135;Mn;0;NSM;;;;;N;;;;; +E0177;VARIATION SELECTOR-136;Mn;0;NSM;;;;;N;;;;; +E0178;VARIATION SELECTOR-137;Mn;0;NSM;;;;;N;;;;; +E0179;VARIATION SELECTOR-138;Mn;0;NSM;;;;;N;;;;; +E017A;VARIATION SELECTOR-139;Mn;0;NSM;;;;;N;;;;; +E017B;VARIATION SELECTOR-140;Mn;0;NSM;;;;;N;;;;; +E017C;VARIATION SELECTOR-141;Mn;0;NSM;;;;;N;;;;; +E017D;VARIATION SELECTOR-142;Mn;0;NSM;;;;;N;;;;; +E017E;VARIATION SELECTOR-143;Mn;0;NSM;;;;;N;;;;; +E017F;VARIATION SELECTOR-144;Mn;0;NSM;;;;;N;;;;; +E0180;VARIATION SELECTOR-145;Mn;0;NSM;;;;;N;;;;; +E0181;VARIATION SELECTOR-146;Mn;0;NSM;;;;;N;;;;; +E0182;VARIATION SELECTOR-147;Mn;0;NSM;;;;;N;;;;; +E0183;VARIATION SELECTOR-148;Mn;0;NSM;;;;;N;;;;; +E0184;VARIATION SELECTOR-149;Mn;0;NSM;;;;;N;;;;; +E0185;VARIATION SELECTOR-150;Mn;0;NSM;;;;;N;;;;; +E0186;VARIATION SELECTOR-151;Mn;0;NSM;;;;;N;;;;; +E0187;VARIATION SELECTOR-152;Mn;0;NSM;;;;;N;;;;; +E0188;VARIATION SELECTOR-153;Mn;0;NSM;;;;;N;;;;; +E0189;VARIATION SELECTOR-154;Mn;0;NSM;;;;;N;;;;; +E018A;VARIATION SELECTOR-155;Mn;0;NSM;;;;;N;;;;; +E018B;VARIATION SELECTOR-156;Mn;0;NSM;;;;;N;;;;; +E018C;VARIATION SELECTOR-157;Mn;0;NSM;;;;;N;;;;; +E018D;VARIATION SELECTOR-158;Mn;0;NSM;;;;;N;;;;; +E018E;VARIATION SELECTOR-159;Mn;0;NSM;;;;;N;;;;; +E018F;VARIATION SELECTOR-160;Mn;0;NSM;;;;;N;;;;; +E0190;VARIATION SELECTOR-161;Mn;0;NSM;;;;;N;;;;; +E0191;VARIATION SELECTOR-162;Mn;0;NSM;;;;;N;;;;; +E0192;VARIATION SELECTOR-163;Mn;0;NSM;;;;;N;;;;; +E0193;VARIATION SELECTOR-164;Mn;0;NSM;;;;;N;;;;; +E0194;VARIATION SELECTOR-165;Mn;0;NSM;;;;;N;;;;; +E0195;VARIATION SELECTOR-166;Mn;0;NSM;;;;;N;;;;; +E0196;VARIATION SELECTOR-167;Mn;0;NSM;;;;;N;;;;; +E0197;VARIATION SELECTOR-168;Mn;0;NSM;;;;;N;;;;; +E0198;VARIATION SELECTOR-169;Mn;0;NSM;;;;;N;;;;; +E0199;VARIATION SELECTOR-170;Mn;0;NSM;;;;;N;;;;; +E019A;VARIATION SELECTOR-171;Mn;0;NSM;;;;;N;;;;; +E019B;VARIATION SELECTOR-172;Mn;0;NSM;;;;;N;;;;; +E019C;VARIATION SELECTOR-173;Mn;0;NSM;;;;;N;;;;; +E019D;VARIATION SELECTOR-174;Mn;0;NSM;;;;;N;;;;; +E019E;VARIATION SELECTOR-175;Mn;0;NSM;;;;;N;;;;; +E019F;VARIATION SELECTOR-176;Mn;0;NSM;;;;;N;;;;; +E01A0;VARIATION SELECTOR-177;Mn;0;NSM;;;;;N;;;;; +E01A1;VARIATION SELECTOR-178;Mn;0;NSM;;;;;N;;;;; +E01A2;VARIATION SELECTOR-179;Mn;0;NSM;;;;;N;;;;; +E01A3;VARIATION SELECTOR-180;Mn;0;NSM;;;;;N;;;;; +E01A4;VARIATION SELECTOR-181;Mn;0;NSM;;;;;N;;;;; +E01A5;VARIATION SELECTOR-182;Mn;0;NSM;;;;;N;;;;; +E01A6;VARIATION SELECTOR-183;Mn;0;NSM;;;;;N;;;;; +E01A7;VARIATION SELECTOR-184;Mn;0;NSM;;;;;N;;;;; +E01A8;VARIATION SELECTOR-185;Mn;0;NSM;;;;;N;;;;; +E01A9;VARIATION SELECTOR-186;Mn;0;NSM;;;;;N;;;;; +E01AA;VARIATION SELECTOR-187;Mn;0;NSM;;;;;N;;;;; +E01AB;VARIATION SELECTOR-188;Mn;0;NSM;;;;;N;;;;; +E01AC;VARIATION SELECTOR-189;Mn;0;NSM;;;;;N;;;;; +E01AD;VARIATION SELECTOR-190;Mn;0;NSM;;;;;N;;;;; +E01AE;VARIATION SELECTOR-191;Mn;0;NSM;;;;;N;;;;; +E01AF;VARIATION SELECTOR-192;Mn;0;NSM;;;;;N;;;;; +E01B0;VARIATION SELECTOR-193;Mn;0;NSM;;;;;N;;;;; +E01B1;VARIATION SELECTOR-194;Mn;0;NSM;;;;;N;;;;; +E01B2;VARIATION SELECTOR-195;Mn;0;NSM;;;;;N;;;;; +E01B3;VARIATION SELECTOR-196;Mn;0;NSM;;;;;N;;;;; +E01B4;VARIATION SELECTOR-197;Mn;0;NSM;;;;;N;;;;; +E01B5;VARIATION SELECTOR-198;Mn;0;NSM;;;;;N;;;;; +E01B6;VARIATION SELECTOR-199;Mn;0;NSM;;;;;N;;;;; +E01B7;VARIATION SELECTOR-200;Mn;0;NSM;;;;;N;;;;; +E01B8;VARIATION SELECTOR-201;Mn;0;NSM;;;;;N;;;;; +E01B9;VARIATION SELECTOR-202;Mn;0;NSM;;;;;N;;;;; +E01BA;VARIATION SELECTOR-203;Mn;0;NSM;;;;;N;;;;; +E01BB;VARIATION SELECTOR-204;Mn;0;NSM;;;;;N;;;;; +E01BC;VARIATION SELECTOR-205;Mn;0;NSM;;;;;N;;;;; +E01BD;VARIATION SELECTOR-206;Mn;0;NSM;;;;;N;;;;; +E01BE;VARIATION SELECTOR-207;Mn;0;NSM;;;;;N;;;;; +E01BF;VARIATION SELECTOR-208;Mn;0;NSM;;;;;N;;;;; +E01C0;VARIATION SELECTOR-209;Mn;0;NSM;;;;;N;;;;; +E01C1;VARIATION SELECTOR-210;Mn;0;NSM;;;;;N;;;;; +E01C2;VARIATION SELECTOR-211;Mn;0;NSM;;;;;N;;;;; +E01C3;VARIATION SELECTOR-212;Mn;0;NSM;;;;;N;;;;; +E01C4;VARIATION SELECTOR-213;Mn;0;NSM;;;;;N;;;;; +E01C5;VARIATION SELECTOR-214;Mn;0;NSM;;;;;N;;;;; +E01C6;VARIATION SELECTOR-215;Mn;0;NSM;;;;;N;;;;; +E01C7;VARIATION SELECTOR-216;Mn;0;NSM;;;;;N;;;;; +E01C8;VARIATION SELECTOR-217;Mn;0;NSM;;;;;N;;;;; +E01C9;VARIATION SELECTOR-218;Mn;0;NSM;;;;;N;;;;; +E01CA;VARIATION SELECTOR-219;Mn;0;NSM;;;;;N;;;;; +E01CB;VARIATION SELECTOR-220;Mn;0;NSM;;;;;N;;;;; +E01CC;VARIATION SELECTOR-221;Mn;0;NSM;;;;;N;;;;; +E01CD;VARIATION SELECTOR-222;Mn;0;NSM;;;;;N;;;;; +E01CE;VARIATION SELECTOR-223;Mn;0;NSM;;;;;N;;;;; +E01CF;VARIATION SELECTOR-224;Mn;0;NSM;;;;;N;;;;; +E01D0;VARIATION SELECTOR-225;Mn;0;NSM;;;;;N;;;;; +E01D1;VARIATION SELECTOR-226;Mn;0;NSM;;;;;N;;;;; +E01D2;VARIATION SELECTOR-227;Mn;0;NSM;;;;;N;;;;; +E01D3;VARIATION SELECTOR-228;Mn;0;NSM;;;;;N;;;;; +E01D4;VARIATION SELECTOR-229;Mn;0;NSM;;;;;N;;;;; +E01D5;VARIATION SELECTOR-230;Mn;0;NSM;;;;;N;;;;; +E01D6;VARIATION SELECTOR-231;Mn;0;NSM;;;;;N;;;;; +E01D7;VARIATION SELECTOR-232;Mn;0;NSM;;;;;N;;;;; +E01D8;VARIATION SELECTOR-233;Mn;0;NSM;;;;;N;;;;; +E01D9;VARIATION SELECTOR-234;Mn;0;NSM;;;;;N;;;;; +E01DA;VARIATION SELECTOR-235;Mn;0;NSM;;;;;N;;;;; +E01DB;VARIATION SELECTOR-236;Mn;0;NSM;;;;;N;;;;; +E01DC;VARIATION SELECTOR-237;Mn;0;NSM;;;;;N;;;;; +E01DD;VARIATION SELECTOR-238;Mn;0;NSM;;;;;N;;;;; +E01DE;VARIATION SELECTOR-239;Mn;0;NSM;;;;;N;;;;; +E01DF;VARIATION SELECTOR-240;Mn;0;NSM;;;;;N;;;;; +E01E0;VARIATION SELECTOR-241;Mn;0;NSM;;;;;N;;;;; +E01E1;VARIATION SELECTOR-242;Mn;0;NSM;;;;;N;;;;; +E01E2;VARIATION SELECTOR-243;Mn;0;NSM;;;;;N;;;;; +E01E3;VARIATION SELECTOR-244;Mn;0;NSM;;;;;N;;;;; +E01E4;VARIATION SELECTOR-245;Mn;0;NSM;;;;;N;;;;; +E01E5;VARIATION SELECTOR-246;Mn;0;NSM;;;;;N;;;;; +E01E6;VARIATION SELECTOR-247;Mn;0;NSM;;;;;N;;;;; +E01E7;VARIATION SELECTOR-248;Mn;0;NSM;;;;;N;;;;; +E01E8;VARIATION SELECTOR-249;Mn;0;NSM;;;;;N;;;;; +E01E9;VARIATION SELECTOR-250;Mn;0;NSM;;;;;N;;;;; +E01EA;VARIATION SELECTOR-251;Mn;0;NSM;;;;;N;;;;; +E01EB;VARIATION SELECTOR-252;Mn;0;NSM;;;;;N;;;;; +E01EC;VARIATION SELECTOR-253;Mn;0;NSM;;;;;N;;;;; +E01ED;VARIATION SELECTOR-254;Mn;0;NSM;;;;;N;;;;; +E01EE;VARIATION SELECTOR-255;Mn;0;NSM;;;;;N;;;;; +E01EF;VARIATION SELECTOR-256;Mn;0;NSM;;;;;N;;;;; +F0000;<Plane 15 Private Use, First>;Co;0;L;;;;;N;;;;; +FFFFD;<Plane 15 Private Use, Last>;Co;0;L;;;;;N;;;;; +100000;<Plane 16 Private Use, First>;Co;0;L;;;;;N;;;;; +10FFFD;<Plane 16 Private Use, Last>;Co;0;L;;;;;N;;;;; diff --git a/doc/vmintegration.texinfo b/doc/vmintegration.texinfo index fa5f747ff..e9f104601 100644 --- a/doc/vmintegration.texinfo +++ b/doc/vmintegration.texinfo @@ -227,6 +227,7 @@ become operable. * java.lang.VMString:: * java.lang.VMThread:: * java.lang.VMInstrumentationImpl:: +* java.lang.VMMath:: @end menu @node java.lang.VMClass, java.lang.VMObject ,java.lang,java.lang @@ -684,17 +685,18 @@ having returned true, and is thus deprecated as a result. @end itemize @end itemize -@node java.lang.VMInstrumentationImpl,, java.lang.VMThread, java.lang +@node java.lang.VMInstrumentationImpl, java.lang.VMMath, java.lang.VMThread, java.lang @subsection @code{java.lang.VMInstrumentationImpl} The @code{java.lang.VMInstrumentationImpl} and -@code{java.lang.InstrumentationImpl} provides an implementation of the +@code{java.lang.InstrumentationImpl} classes provide an implementation of the @code{java.lang.instrument.Instrument} interface. This interface is for java 1.5 and is only in the generics branch. -A @code{InstrumentationImpl} object should be given to any agent -given in the command line (see the @code{java.lang.instrument} package -documentation). A VM has to implement the static native methods of the -@code{VMInstrumentationImpl} class. +A @code{InstrumentationImpl} object should be created by the VM when agents +are given in the command line (see the @code{java.lang.instrument} package +documentation). The VM has to set the static field +@code{VMClassLoader.instrumenter} to this object. The VM should implement the +static native methods of the @code{VMInstrumentationImpl} class. @itemize @bullet @item @code{isRedefineClassesSupported()} -- Returns true if the JVM supports @@ -707,21 +709,72 @@ by a specific class loader. @item @code{getObjectSize()} -- Gives the size of an object. @end itemize -When agents are defined, the VM has to call transformers of the -@code{InstrumentImpl} object each time a class is loaded, eg a call to -@code{VMClassLoader.defineClass}. The @code{InstrumentationImpl} class defines -a method that has to be called before reading a class file in the VM. +Instrumentation allows to modify the bytecode of a class before it gets read +by the VM. In GNU Classpath, the @code{ClassLoader.defineClass} method calls +the @code{VMClassLoader.defineClassWithTransformers} method which first checks +if @code{VMClassLoader.instrumenter} is @code{null}. If it's the case, it +directly calls @code{VMClassLoader.defineClass}. If it's not the case, the +method calls at first the @code{InstrumentationImpl.callTransformers} method, +which calls each transformer registered to the @code{InstrumentationImpl} +object and returns a new bytecode array. Then, it calls the +@code{VMClassLoader.defineClass} method with this new bytecode array. + +The second use of instrumentation is to redefine a class after it has been +loaded by the VM. This is done in the Java application by calling the +@code{Instrumentation.redefineClasses} method of the standard interface on +a @code{Instrumentation} object. The @code{InstrumentationImpl.redefineClasses} +method calls the @code{VMInstrumentationImpl.redefineClasses} native method +which must be implemented by the VM. The implementation should call the +@code{InstrumentationImpl.callTransformers} method. + +@node java.lang.VMMath, , java.lang.VMInstrumentationImpl, java.lang +@subsection @code{java.lang.VMMath} + +The @code{VMMath} class provides a series of native methods +for some of the mathematical functions present in @code{java.lang.Math}. +Classpath provides a default implementation of these which maps the +functions to those provided by @code{fdlibm}. VM implementors are welcome +to replace this with more efficent implementations, as long as the accuracy +contract of these methods, specified in @code{java.lang.Math}, is maintained. @itemize @bullet -@item @code{callTransformers} -- Calls each transformer registered to -the @code{InstrumentationImpl} object and returns a new bytecode file. +@item 1.0 +@itemize @bullet +@item @code{sin(double)} -- Returns the sine value for the given angle. +@item @code{cos(double)} -- Returns the cosine value for the given angle. +@item @code{tan(double)} -- Returns the tangent value for the given angle. +@item @code{asin(double)} -- Returns the arc sine value for the given angle. +@item @code{acos(double)} -- Returns the arc cosine value for the given angle. +@item @code{atan(double)} -- Returns the arc tangent value for the given angle. +@item @code{atan2(double,double)} -- Returns the arc tangent of the ratio of +the two arguments. +@item @code{exp(double)} -- Returns the exponent raised to the given power. +@item @code{log(double)} -- Returns the natural logarithm for the given value. +@item @code{sqrt(double)} -- Returns the square root of the value. +@item @code{pow(double,double)} -- Returns x to the power of y. +@item @code{IEEEremainder(double,double)} -- Returns the IEEE 754 remainder +for the two values. +@item @code{ceil(double)} -- Returns the nearest integer >= the value. +@item @code{floor(double)} -- Returns the nearest integer <= the value. +@item @code{rint(double)} -- Returns the nearest integer or the even one +if the distance between the two is equal. +@end itemize +@item 1.5 +@itemize @bullet +@item @code{cbrt(double)} -- Returns the cube root of the value. +@item @code{cosh(double)} -- Returns the hyperbolic cosine value for the given +angle. +@item @code{expm1(double)} -- Returns the exponent of the value minus one. +@item @code{hypot(double,double)} -- Returns the hypotenuse corresponding to +x and y. +@item @code{log10(double)} -- Returns the base 10 logarithm of the given value. +@item @code{log1p(double)} -- Returns the natural logarithm of the value plus +one. +@item @code{sinh(double)} -- Returns the hyperbolic sine value for the given +angle. +@item @code{tanh(double)} -- Returns the hyperbolic tangent value for the given angle. +@end itemize @end itemize - -No default implementation is provided in gnu classpath for the -@code{VMInstrumentationImpl} methods. A default implementation will perhaps -be written, but it might break the @code{ClassLoader/VMClassLoader} interface -for calling the @code{InstrumentationImpl.callTransformers} when a class byte -code is defined with @code{ClassLoader.defineClass}. @node gnu.classpath, java.util, java.lang, Classpath Hooks @section @code{gnu.classpath} diff --git a/doc/www.gnu.org/announce/20060113.wml b/doc/www.gnu.org/announce/20060113.wml new file mode 100644 index 000000000..054185d87 --- /dev/null +++ b/doc/www.gnu.org/announce/20060113.wml @@ -0,0 +1,289 @@ +#!wml --include=.. + +#use wml::std::page +#use wml::std::lang +#use wml::fmt::isolatin +#use wml::std::case global=upper + +<lang:star:slice:> + +<set-var last-modified-author="mjw"> + +#include <include/macros.wml> + +<header title="GNU Classpath 0.20 Announcement (2006-01-13)"> +<pre> +GNU Classpath 0.20 released + +GNU Classpath, essential libraries for java, is a project to create +free core class libraries for use with runtimes, compilers and tools +for the java programming language. + +The GNU Classpath developer snapshot releases are not directly aimed +at the end user but are meant to be integrated into larger development +platforms. For example the GCC (gcj) and Kaffe projects will use the +developer snapshots as a base for future versions. More projects based +on GNU Classpath: http://www.gnu.org/software/classpath/stories.html + +Some highlights of changes in this release (more extensive list below): + + New StAX pull parser and SAX-over-StAX driver. Full XMLEncoder + implementation. The packages javax.sound.sampled, javax.print.attribute + and javax.print.event have been implemented. Lots of new datatransfer, + print, swing and swing.text work. Performance improvements in the + painting/layout mechanism. Additional 1.5 support, including (separate) + generic branch release. SecurityManager cleanups and start of review + of all Permission checks. Buildable on cygwin. Fully buildable as + "in-workspace" library-plus-vm inside (native) Eclipse. Real world + Free Swing and CORBA example added. + +GNU Classpath 0.20 also comes in a "generic" version. +classpath-0.20-generics contains a version of the core library +that uses the new 1.5 language features such as generics and +enumerations. ECJ, JamVM, IKVM and Cacao are known to support the +generics release (*). And you should be able to run Eclipse 3.1 with +it to develop programs that use the new 1.5 language and core library +additions. classpath-generics is a work in progress and not as +extensively tested as our regular releases. But please try it out if +you want to help us test the new 1.5 support of the core libraries. + +(*) There is one additional VM interface needed for the VMClassLoader + static final Class defineClassWithTransformers(ClassLoader loader, + String name, byte[] data, int offset, int len, ProtectionDomain pd) + Which is used for the new java.management.instrumentation support. + See the VM Integration Guide for more details: + http://www.gnu.org/software/classpath/docs/vmintegration.html + +Thanks to a donation of Berkeley Signal Inc GNU Classpath now has an +official autobuilder machine which is used for quality assurance, +regression testing, conformance reports and for publishing continous +snapshots. The machine can be reached as http://builder.classpath.org/ + +40 people actively contributed to this release and made +605 CVS commits during the last two months of development +(excluding the generics branch work). diffstat since 0.19: + 617 files changed, 89622 insertions(+), 37478 deletions(-) + +More details about the various changes and contributions below. + +A full list of bug reports fixed for this release can be found at: +http://gcc.gnu.org/bugzilla/buglist.cgi?product=classpath&target_milestone=0.20 + +The GNU Classpath developers site http://developer.classpath.org/ +provides detailed information on how to start with helping the GNU +Classpath project and gives an overview of the core class library +packages currently provided. For each snapshot release generated +documentation is provided through the GNU Classpath Tools gjdoc +project. A documentation generation framework for java source +files used by the GNU project. Full documentation on the currently +implementated packages and classes can be found at: +http://developer.classpath.org/doc/ + +For more information about the project see also: + +- GNU Classpath home page: + http://www.gnu.org/software/classpath/ + +- Developer information (wiki): + http://developer.classpath.org/ + +- Full class documentation + http://developer.classpath.org/doc/ + +- GNU Classpath hackers: + http://planet.classpath.org/ + +- Autobuilder, current build status, build snapshots: + http://builder.classpath.org/ + +- Application test pages (wiki) + http://developer.classpath.org/mediation/FreeAWTTestApps + http://developer.classpath.org/mediation/FreeSwingTestApps + http://developer.classpath.org/mediation/FreeSWTTestApps + +- GNU Classpath hacking with Eclipse (wiki) + http://developer.classpath.org/mediation/ClasspathHackingWithEclipse + +- GNU Classpath promotion banners: + http://developer.classpath.org/mediation/ClasspathBanners + +- GNU Classpath and Friends meeting (Feb 25/26, Brussels, Fosdem): + http://www.gnu.org/software/classpath/events/fosdem06.html + +This release depends on gtk+ 2.4 for AWT support. But gtk+ 2.6 or +higher is recommended. Included, but not activated by default in this +release is a Graphics2D implementation based on the Cairo Graphics +framework (http://www.cairographics.org). Enabling this makes programs +like JFreeChart and JEdit start up on GNU Classpath based runtimes. +To enable this support install the cairo 0.5.x snapshot, configure GNU +Classpath with --enable-gtk-cairo. + +One of the major focuses of the GNU Classpath project is expanding and +using the Mauve test suite for Compatibility, Completeness and +Correctness checking. Various groups around GNU Classpath collaborate +on the free software Mauve test suite which contains around 36.000 +core library tests. Mauve has various modules for testing core class +library implementations, byte code verifiers, source to byte code and +native code compiler tests. Mauve also contains the Wonka visual test +suite and the Jacks Compiler Killer Suite. +See for more information: http://www.sourceware.org/mauve/ +This release passes 35534 out of 36255 Mauve core library tests. + +Conformance reports for the included jaxp support can be found in the +doc/README.jaxp file. + +GNU Classpath 0.20 can be downloaded from +ftp://ftp.gnu.org/pub/gnu/classpath/ +or one of the ftp.gnu.org mirrors +http://www.gnu.org/order/ftp.html + +File: classpath-0.20.tar.gz +MD5sum: 21e34b8e8acb4f7b31296bfaf4ad560a +SHA1sum: c1a38c6c6b67d8c8092cc6af6d86d8c99dad272a + +File: classpath-0.20-generics.tar.gz (EXPERIMENTAL) +MD5sum: db3c235b1ea497d7d2e5852f167d2b31 +SHA1sum: 3d5f5cdd3dc51651f8b2c3765e30454931f45419 + +New in release 0.20 (Jan 13, 2006) +(See the ChangeLog file for a full list of changes.) + +* New StAX pull parser and SAX-over-StAX driver. Lots of DOM, SAX/StAX, + XPath and XSLT improvements. Support for XInclude and XML Base added. + Conformance is now regularly tested against various test-suites at + http://builder.classpath.org/xml/ See also doc/README.jaxp. + +* Full beans XMLEncoder implementation. + +* javax.sound.sampled implementation. + +* javax.print.attribute and javax.print.event implementated. + +* Lots of new datatransfer, print swing and swing.text work and optimization. + +* Additional 1.5 support. Including new (separate) generic branch release. + +* SecurityManager cleanups and start of review of all Permission checks + (includes adding lots of new checks to the Mauve test-suite). + +* Buildable on cygwin. + +* Fully buildable as "in-workspace" library-plus-vm inside (native) Eclipse + see http://developer.classpath.org/mediation/ClasspathHackingWithEclipse + +* Full example that shows a real world CORBA and Free Swing implementation. + See examples/gnu/classpath/examples/CORBA/swing/README.html + +Runtime interface changes: + +* New method VMStackWalker.getClassLoader() was added to avoid an infinite + loop between getCallingClassLoader() and Class.getClassLoader(). + +* The included fdlibm implementation has seen several cleanups to handle + new architectures and namespacing issues (in particular for ppc, darwin + and non-C99 compilers). Please double check any arithmetic test against + new platforms/runtimes. + +* The gnu.java.net.Plain[Datagram]Socket implementations have been + turned into VM reference classes with JNI/Posix implementations. + +New/Untested/Disabled Features: + + The following new features are included, but not ready for + production yet. They are explicitly disabled and not supported. But + if you want to help with the development of these new features we + are interested in feedback. You will have to explicitly enable them + to try them out (and they will most likely contain bugs). If you are + interested in any of these then please join the mailing-list and + follow development in CVS. + +* Cairo Gtk+ Graphics2D support, enabled by giving configure + --enable-gtk-cairo. +* QT4 AWT peers, enable by giving configure --enable-qt-peer. + +The following people helped with this release: + +Andreas Tobler + Qt-4.1 support +Andrew Haley + Jar work and Jonas fixes +Andrew John Hughes + 1.5 generics language work +Anthony Balkissoon + Free Swing work +Anthony Green + Socket work +Archie Cobbs + New VMStackWalker work and JCVM integration +Audrius Meskauskas + Free CORBA work and various Free Swing fixes +Bryce McKinlay + Jar fixes +Caolan McNamara + Dom fixes and OpenOffice fixes +Casey Marshall + Crypto work +Chris Burdess + XML GNU JAXP work +Christian Thalinger + Various fixes, 64bit work and Cacao integration +Dalibor Topic + Build cleanups and Kaffe integration +David Daney + libgcj integration +David Gilbert + Free Swing work +Freebeans + Mysaifu Windows CE port and bug reports +Fridjof Siebert + Hashtable work +Gary Benson + Securitymanager and Permission work +Guilhem Lavaux + fdlibm cleanups, performance work and Kaffe integration +Ingo Proetel + Various fixes +Ito Kazumitsu + Regex, text and character conversion support +Jan Roehrich + Datatransfer work +Jeroen Frijters + SecurityManager, collections and IKVM integration +Joao Victor + Free Swing Timer work +John Zigman + SocketChannel testing +Keith Seitz + JDWP work +Lillian Angel + Free Swing work +Mark Wielaard + Bug fixes, packaging and release management +Nicolas Geoffray + 1.5 Class Instrumentation work +Paul Jenner + Installation and cygwin work +Petteri Raty + Configuration and Gentoo integration work +Raif S. Naffah + Security work and Eclipse integration +Riccardo Mottola + Powerpc work +Robert Schuster + XMLEncoder and beans work +Roman Kennke + Free Swing and AWT work, VM interface +Roman Schnider + AWT work +Sven de Marothy + Print and GTK+ work +Thomas Fitzsimmons + Free Swing and AWT work +Tom Tromey + Eclipse, gcj and gcjx integration +Wolfgang Baer + javax.print and friends + +We would also like to thank the numerous bug reporters and testers! +</pre> +<footer> diff --git a/doc/www.gnu.org/downloads/downloads.wml b/doc/www.gnu.org/downloads/downloads.wml index 96018f603..3f0180d2e 100644 --- a/doc/www.gnu.org/downloads/downloads.wml +++ b/doc/www.gnu.org/downloads/downloads.wml @@ -77,10 +77,10 @@ sub mylink { <download-block> <download - date="02 November 2005" - version="0.19" - url="ftp://ftp.gnu.org/gnu/classpath/classpath-0.19.tar.gz" - notes="http://www.gnu.org/software/classpath/announce/20051102.html" + date="13 January 2006" + version="0.20" + url="ftp://ftp.gnu.org/gnu/classpath/classpath-0.20.tar.gz" + notes="http://www.gnu.org/software/classpath/announce/20060113.html" > <!-- download @@ -99,6 +99,12 @@ sub mylink { <boxitem> <download-block> +<download + date="02 November 2005" + version="0.19" + url="ftp://ftp.gnu.org/gnu/classpath/classpath-0.19.tar.gz" + notes="http://www.gnu.org/software/classpath/announce/20051102.html" +> <download date="06 September 2005" version="0.18" diff --git a/doc/www.gnu.org/newsitems.txt b/doc/www.gnu.org/newsitems.txt index 97c14244e..08eb0f1fd 100644 --- a/doc/www.gnu.org/newsitems.txt +++ b/doc/www.gnu.org/newsitems.txt @@ -3,6 +3,11 @@ url="events/fosdem06.html"> </newsitem> +<newsitem date="13 Jan 2006"> +<createlink name="GNU Classpath 0.20" + url="announce/20060113.html"> +</newsitem> + <newsitem date="02 Nov 2005"> <createlink name="GNU Classpath 0.19" url="announce/20051102.html"> diff --git a/examples/Makefile.am b/examples/Makefile.am index 8b7f9b2c6..08bfdb4b6 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -95,7 +95,10 @@ $(EXAMPLE_ZIP): $(EXAMPLE_JAVA_FILES) mkdir -p classes/gnu/classpath/examples/icons cp $(EXAMPLE_ICONS) classes/gnu/classpath/examples/icons $(JCOMPILER) -d classes $(EXAMPLE_JAVA_FILES) - cd classes; $(ZIP) -r ../$(EXAMPLE_ZIP) .; cd .. + (cd classes; \ + if test "$(ZIP)" != ""; then $(ZIP) -r ../$(EXAMPLE_ZIP) .; fi; \ + if test "$(FASTJAR)" != ""; then $(FASTJAR) cf ../$(EXAMPLE_ZIP) .; fi; \ + cd ..) rm -rf classes # Zip file be gone! (and make sure the classes are gone too) diff --git a/examples/gnu/classpath/examples/CORBA/swing/x5/PlayingDesk.java b/examples/gnu/classpath/examples/CORBA/swing/x5/PlayingDesk.java index 83178f936..fa8966f26 100644 --- a/examples/gnu/classpath/examples/CORBA/swing/x5/PlayingDesk.java +++ b/examples/gnu/classpath/examples/CORBA/swing/x5/PlayingDesk.java @@ -433,7 +433,6 @@ public class PlayingDesk else { blacks.add(new Point(x, y)); - repaint(); if (victory != null) { @@ -447,7 +446,8 @@ public class PlayingDesk frame.talk(Color.black, "Partner goes " + x + "-" + y + ". Your move?"); player.set_current_state(I_THINK); - } + } + repaint(); } } catch (RemoteException rex) diff --git a/examples/gnu/classpath/examples/CORBA/swing/x5/_GameManagerImpl_Tie.java b/examples/gnu/classpath/examples/CORBA/swing/x5/_GameManagerImpl_Tie.java index 17a62600c..a0c33df34 100644 --- a/examples/gnu/classpath/examples/CORBA/swing/x5/_GameManagerImpl_Tie.java +++ b/examples/gnu/classpath/examples/CORBA/swing/x5/_GameManagerImpl_Tie.java @@ -57,13 +57,8 @@ import org.omg.PortableServer.Servant; * Tie on the client side. The Game Manager methods contain the code for remote * invocation. * - * This class is normally generated with rmic from the {@link GameManagerImpl}: - * - * <pre> - * rmic -iiop -poa -keep gnu.classpath.examples.CORBA.swing.x5.GameManagerImpl - * </pre> - * - * (the compiled package must be present in the current folder). + * This class is normally generated with rmic or grmic from the + * {@link GameManagerImpl}. See tools/gnu/classpath/tools/giop/README. * * In this example the class was manually edited and commented for better * understanding of functionality. diff --git a/examples/gnu/classpath/examples/CORBA/swing/x5/_PlayerImpl_Tie.java b/examples/gnu/classpath/examples/CORBA/swing/x5/_PlayerImpl_Tie.java index 730c6f469..f6c5f4765 100644 --- a/examples/gnu/classpath/examples/CORBA/swing/x5/_PlayerImpl_Tie.java +++ b/examples/gnu/classpath/examples/CORBA/swing/x5/_PlayerImpl_Tie.java @@ -58,11 +58,8 @@ import org.omg.PortableServer.Servant; * rmic -iiop -poa -keep gnu.classpath.examples.CORBA.swing.x5.PlayerImpl * (the compiled package must be present in the current folder). * - * This class is normally generated with rmic from the {@link PlayerImpl}: - * <pre> - * rmic -iiop -poa -keep gnu.classpath.examples.CORBA.swing.x5.PlayerImpl - * </pre> - * (the compiled package must be present in the current folder). + * This class is normally generated with rmic or grmic from the + * {@link PlayerImpl}. See tools/gnu/classpath/tools/giop/README. * * In this example the class was manually edited and commented for better * understanding of functionality. diff --git a/examples/gnu/classpath/examples/swing/ButtonDemo.java b/examples/gnu/classpath/examples/swing/ButtonDemo.java index b53ba3b5c..856917fa9 100644 --- a/examples/gnu/classpath/examples/swing/ButtonDemo.java +++ b/examples/gnu/classpath/examples/swing/ButtonDemo.java @@ -1,5 +1,5 @@ /* ButtonDemo.java -- An example showing various buttons in Swing. - Copyright (C) 2005, Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath examples. @@ -46,6 +46,8 @@ public class ButtonDemo implements ActionListener { + private JPanel content; + private JCheckBox buttonState; private JButton button1; private JButton button2; @@ -77,6 +79,19 @@ public class ButtonDemo { super(title); JPanel content = createContent(); + // initFrameContent() is only called (from main) when running this app + // standalone + } + + /** + * When the demo is run independently, the frame is displayed, so we should + * initialise the content panel (including the demo content and a close + * button). But when the demo is run as part of the Swing activity board, + * only the demo content panel is used, the frame itself is never displayed, + * so we can avoid this step. + */ + public void initFrameContent() + { JPanel closePanel = new JPanel(); JButton closeButton = new JButton("Close"); closeButton.setActionCommand("CLOSE"); @@ -95,13 +110,16 @@ public class ButtonDemo */ JPanel createContent() { - JPanel content = new JPanel(new BorderLayout()); - JPanel panel = new JPanel(new GridLayout(4, 1)); - panel.add(createButtonPanel()); - panel.add(createTogglePanel()); - panel.add(createCheckBoxPanel()); - panel.add(createRadioPanel()); - content.add(panel); + if (content == null) + { + content = new JPanel(new BorderLayout()); + JPanel panel = new JPanel(new GridLayout(4, 1)); + panel.add(createButtonPanel()); + panel.add(createTogglePanel()); + panel.add(createCheckBoxPanel()); + panel.add(createRadioPanel()); + content.add(panel); + } return content; } @@ -277,6 +295,7 @@ public class ButtonDemo public static void main(String[] args) { ButtonDemo app = new ButtonDemo("Button Demo"); + app.initFrameContent(); app.pack(); app.setVisible(true); } diff --git a/examples/gnu/classpath/examples/swing/ComboBoxDemo.java b/examples/gnu/classpath/examples/swing/ComboBoxDemo.java index 52431cb5d..2af619ca8 100644 --- a/examples/gnu/classpath/examples/swing/ComboBoxDemo.java +++ b/examples/gnu/classpath/examples/swing/ComboBoxDemo.java @@ -1,5 +1,5 @@ /* ComboBoxDemo.java -- An example showing various combo boxes in Swing. - Copyright (C) 2005, Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath examples. @@ -69,6 +69,7 @@ public class ComboBoxDemo } } + private JPanel content; private JCheckBox comboState1; private JComboBox combo1; private JComboBox combo2; @@ -102,6 +103,19 @@ public class ComboBoxDemo { super(title); JPanel content = createContent(); + // initFrameContent() is only called (from main) when running this app + // standalone + } + + /** + * When the demo is run independently, the frame is displayed, so we should + * initialise the content panel (including the demo content and a close + * button). But when the demo is run as part of the Swing activity board, + * only the demo content panel is used, the frame itself is never displayed, + * so we can avoid this step. + */ + public void initFrameContent() + { JPanel closePanel = new JPanel(); JButton closeButton = new JButton("Close"); closeButton.setActionCommand("CLOSE"); @@ -120,15 +134,18 @@ public class ComboBoxDemo */ JPanel createContent() { - JPanel content = new JPanel(new BorderLayout()); - JPanel panel = new JPanel(new GridLayout(6, 1)); - panel.add(createPanel1()); - panel.add(createPanel2()); - panel.add(createPanel3()); - panel.add(createPanel4()); - panel.add(createPanel5()); - panel.add(createPanel6()); - content.add(panel); + if (content == null) + { + content = new JPanel(new BorderLayout()); + JPanel panel = new JPanel(new GridLayout(6, 1)); + panel.add(createPanel1()); + panel.add(createPanel2()); + panel.add(createPanel3()); + panel.add(createPanel4()); + panel.add(createPanel5()); + panel.add(createPanel6()); + content.add(panel); + } return content; } @@ -353,6 +370,7 @@ public class ComboBoxDemo e.printStackTrace(); } ComboBoxDemo app = new ComboBoxDemo("ComboBox Demo"); + app.initFrameContent(); app.pack(); app.setVisible(true); } diff --git a/examples/gnu/classpath/examples/swing/Demo.java b/examples/gnu/classpath/examples/swing/Demo.java index 549a42e4b..977e364db 100644 --- a/examples/gnu/classpath/examples/swing/Demo.java +++ b/examples/gnu/classpath/examples/swing/Demo.java @@ -1,5 +1,5 @@ /* SwingDemo.java -- An example of using the javax.swing UI. - Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath examples. @@ -715,6 +715,7 @@ public class Demo main.add(mkButtonBar()); component.add(main, BorderLayout.CENTER); frame.pack(); + frame.setSize(800, 600); frame.show(); } @@ -947,37 +948,16 @@ public class Demo return editorPane; } - private static JTree mkTree() + /** + * Create the tree. + * + * @return thr scroll pane, containing the tree. + */ + private static JComponent mkTree() { DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root node"); - DefaultMutableTreeNode child1 = new DefaultMutableTreeNode("Child node 1"); - DefaultMutableTreeNode child11 = - new DefaultMutableTreeNode("Child node 1.1"); - DefaultMutableTreeNode child12 = - new DefaultMutableTreeNode("Child node 1.2"); - DefaultMutableTreeNode child13 = - new DefaultMutableTreeNode("Child node 1.3"); - DefaultMutableTreeNode child2 = new DefaultMutableTreeNode("Child node 2"); - DefaultMutableTreeNode child21 = - new DefaultMutableTreeNode("Child node 2.1"); - DefaultMutableTreeNode child22 = - new DefaultMutableTreeNode("Child node 2.2"); - DefaultMutableTreeNode child23 = - new DefaultMutableTreeNode("Child node 2.3"); - DefaultMutableTreeNode child24 = - new DefaultMutableTreeNode("Child node 2.4"); - - DefaultMutableTreeNode child3 = new DefaultMutableTreeNode("Child node 3"); - root.add(child1); - root.add(child2); - root.add(child3); - child1.add(child11); - child1.add(child12); - child1.add(child13); - child2.add(child21); - child2.add(child22); - child2.add(child23); - child2.add(child24); + + addChildren("Node", root, 12); JTree tree = new JTree(root); tree.setLargeModel(true); @@ -985,60 +965,70 @@ public class Demo dtsm.setSelectionMode(DefaultTreeSelectionModel.SINGLE_TREE_SELECTION); tree.setSelectionModel(dtsm); - return tree; + // Make it editable. + tree.setEditable(true); + + JComponent t = mkScrollPane(tree); + t.setPreferredSize(new Dimension(200,200)); + return t; } - - private static JTable mkTable() + + /** + * Add the specified number of children to this parent node. For each + * child, the method is called recursively adding the nChildren-3 number of + * grandchildren. + * + * @param parent the parent node + * @param nChildren the number of children + */ + private static void addChildren(String name, DefaultMutableTreeNode parent, + int nChildren) { - Object[][] tableData = new Object[][] { - { - "Field 1", "Field 2" , "Field 3" - }, - { - "Field 4", "Field 5" , "Field 6" - }, + for (int i = 0; i < nChildren; i++) { - "Field 7", "Field 8" , "Field 9" - }, - { - "Field 10", "Field 11" , "Field 12" + String child_name = parent+"."+i; + DefaultMutableTreeNode child = new DefaultMutableTreeNode + (child_name); + parent.add(child); + addChildren(child_name, child, nChildren-3); } - }; - Object[] columnNames = new Object[] {"Column 1", "Column 2", "Column 3"}; - - JTable table = new JTable(tableData, columnNames); - return table; + } + + /** + * Make a sample table component. + */ + private static JPanel mkTable() + { + return new TableDemo("Table demo, double click to edit") + .createContent(); } private JPanel mkButtonBar() { - JPanel panel = new JPanel (new GridLayout(2, 1)); - JPanel panelA = new JPanel(new FlowLayout()); - JPanel panelB = new JPanel(new FlowLayout()); - + JPanel panel = new JPanel(new FlowLayout()); new PopUpAction("Buttons", (new ButtonDemo("Button Demo")).createContent(), - panelA); + panel); new PopUpAction("Toggles", mkToggle("cool and refreshing"), - panelA); + panel); new PopUpAction("Checkbox", mkCheckbox("ice cold"), - panelA); + panel); new PopUpAction("Radio", mkRadio("delicious"), - panelA); + panel); new PopUpAction("Slider", (new SliderDemo("Slider Demo")).createContent(), - panelA); + panel); new PopUpAction("ProgressBar", ProgressBarDemo.createContent(), - panelA); + panel); new PopUpAction("List", @@ -1050,60 +1040,60 @@ public class Demo "that", "wraps", "over"}), - panelA); + panel); new PopUpAction("Scrollbar", (new ScrollBarDemo("ScrollBar Demo")).createContent(), - panelA); + panel); new PopUpAction("Viewport", mkViewportBox(mkBigButton("View Me!")), - panelA); + panel); new PopUpAction("ScrollPane", mkScrollPane(mkBigButton("Scroll Me!")), - panelA); + panel); new PopUpAction("TabPane", mkTabs(new String[] {"happy", "sad", "indifferent"}), - panelB); + panel); new PopUpAction("Spinner", mkSpinner(), - panelB); + panel); new PopUpAction("TextField", (new TextFieldDemo("TextField Demo")).createContent(), - panelB); + panel); new PopUpAction("FileChooser", (new FileChooserDemo("FileChooser Demo")).createContent(), - panelB); + panel); new PopUpAction("ColorChooser", mkColorChooser(), - panelB); + panel); new PopUpAction("ComboBox", (new ComboBoxDemo("ComboBox Demo")).createContent(), - panelB); + panel); new PopUpAction("Editor", mkEditorPane(), - panelB); + panel); new PopUpAction("Tree", mkTree(), - panelB); + panel); new PopUpAction("Table", mkTable(), - panelB); + panel); JButton exitDisposer = mkDisposerButton(frame); - panelB.add(exitDisposer); + panel.add(exitDisposer); exitDisposer.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) @@ -1111,8 +1101,6 @@ public class Demo System.exit(1); } }); - panel.add(panelA); - panel.add(panelB); return panel; } } diff --git a/examples/gnu/classpath/examples/swing/FileChooserDemo.java b/examples/gnu/classpath/examples/swing/FileChooserDemo.java index 70bb56d66..de86d2337 100644 --- a/examples/gnu/classpath/examples/swing/FileChooserDemo.java +++ b/examples/gnu/classpath/examples/swing/FileChooserDemo.java @@ -1,5 +1,5 @@ /* FileChooserDemo.java -- An example showing file choosers in Swing. - Copyright (C) 2005, Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath examples. @@ -63,7 +63,9 @@ public class FileChooserDemo extends JFrame implements ActionListener return false; } } - + + private JPanel content; + /** A label to display the selected file. */ JLabel selectedFileLabel; @@ -85,6 +87,19 @@ public class FileChooserDemo extends JFrame implements ActionListener { super(frameTitle); JPanel content = createContent(); + // initFrameContent() is only called (from main) when running this app + // standalone + } + + /** + * When the demo is run independently, the frame is displayed, so we should + * initialise the content panel (including the demo content and a close + * button). But when the demo is run as part of the Swing activity board, + * only the demo content panel is used, the frame itself is never displayed, + * so we can avoid this step. + */ + public void initFrameContent() + { JPanel closePanel = new JPanel(); JButton closeButton = new JButton("Close"); closeButton.setActionCommand("CLOSE"); @@ -102,52 +117,56 @@ public class FileChooserDemo extends JFrame implements ActionListener * added if this demo is being run as a standalone demo). */ JPanel createContent() - { - JPanel panel = new JPanel(new BorderLayout()); - - // create a panel of buttons to select the different styles of file - // chooser... - JPanel buttonPanel = new JPanel(new GridLayout(5, 1)); - JButton openButton = new JButton("Open..."); - openButton.setActionCommand("OPEN"); - openButton.addActionListener(this); - buttonPanel.add(openButton); - JButton saveButton = new JButton("Save..."); - saveButton.setActionCommand("SAVE"); - saveButton.addActionListener(this); - buttonPanel.add(saveButton); - JButton queryButton = new JButton("Select Directory..."); - queryButton.setActionCommand("SELECT_DIRECTORY"); - queryButton.addActionListener(this); - buttonPanel.add(queryButton); - JButton openJavaButton = new JButton("Open Java file..."); - openJavaButton.setActionCommand("OPEN_JAVA"); - openJavaButton.addActionListener(this); - buttonPanel.add(openJavaButton); - JButton openMultiButton = new JButton("Open multiple files..."); - openMultiButton.setActionCommand("OPEN_MULTI"); - openMultiButton.addActionListener(this); - buttonPanel.add(openMultiButton); - panel.add(buttonPanel, BorderLayout.WEST); - - // create a panel to display the selected file(s) and the return code - JPanel displayPanel = new JPanel(new BorderLayout()); - - selectedFileLabel = new JLabel("-"); - selectedFileLabel.setBorder(BorderFactory.createTitledBorder("Selected File/Directory: ")); - displayPanel.add(selectedFileLabel, BorderLayout.NORTH); + { + if (content == null) + { + JPanel panel = new JPanel(new BorderLayout()); - selectedFilesList = new JList(); - JScrollPane sp = new JScrollPane(selectedFilesList); - sp.setBorder(BorderFactory.createTitledBorder("Selected Files: ")); - displayPanel.add(sp); - - returnCodeLabel = new JLabel("0"); - returnCodeLabel.setBorder(BorderFactory.createTitledBorder("Return Code:")); - displayPanel.add(returnCodeLabel, BorderLayout.SOUTH); + // create a panel of buttons to select the different styles of file + // chooser... + JPanel buttonPanel = new JPanel(new GridLayout(5, 1)); + JButton openButton = new JButton("Open..."); + openButton.setActionCommand("OPEN"); + openButton.addActionListener(this); + buttonPanel.add(openButton); + JButton saveButton = new JButton("Save..."); + saveButton.setActionCommand("SAVE"); + saveButton.addActionListener(this); + buttonPanel.add(saveButton); + JButton queryButton = new JButton("Select Directory..."); + queryButton.setActionCommand("SELECT_DIRECTORY"); + queryButton.addActionListener(this); + buttonPanel.add(queryButton); + JButton openJavaButton = new JButton("Open Java file..."); + openJavaButton.setActionCommand("OPEN_JAVA"); + openJavaButton.addActionListener(this); + buttonPanel.add(openJavaButton); + JButton openMultiButton = new JButton("Open multiple files..."); + openMultiButton.setActionCommand("OPEN_MULTI"); + openMultiButton.addActionListener(this); + buttonPanel.add(openMultiButton); + panel.add(buttonPanel, BorderLayout.WEST); + + // create a panel to display the selected file(s) and the return code + JPanel displayPanel = new JPanel(new BorderLayout()); - panel.add(displayPanel); - return panel; + selectedFileLabel = new JLabel("-"); + selectedFileLabel.setBorder(BorderFactory.createTitledBorder("Selected File/Directory: ")); + displayPanel.add(selectedFileLabel, BorderLayout.NORTH); + + selectedFilesList = new JList(); + JScrollPane sp = new JScrollPane(selectedFilesList); + sp.setBorder(BorderFactory.createTitledBorder("Selected Files: ")); + displayPanel.add(sp); + + returnCodeLabel = new JLabel("0"); + returnCodeLabel.setBorder(BorderFactory.createTitledBorder("Return Code:")); + displayPanel.add(returnCodeLabel, BorderLayout.SOUTH); + + panel.add(displayPanel); + content = panel; + } + return content; } /** @@ -221,6 +240,7 @@ public class FileChooserDemo extends JFrame implements ActionListener public static void main(String[] args) { FileChooserDemo app = new FileChooserDemo("File Chooser Demo"); + app.initFrameContent(); app.pack(); app.setVisible(true); } diff --git a/examples/gnu/classpath/examples/swing/MiniDemo.java b/examples/gnu/classpath/examples/swing/MiniDemo.java new file mode 100644 index 000000000..aa8424804 --- /dev/null +++ b/examples/gnu/classpath/examples/swing/MiniDemo.java @@ -0,0 +1,233 @@ +/* MiniDemo.java -- A Swing demo suitable for embedded environments + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.classpath.examples.swing; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.plaf.metal.DefaultMetalTheme; +import javax.swing.plaf.metal.MetalIconFactory; +import javax.swing.plaf.metal.MetalLookAndFeel; + +/** + * A Swing demo suitable for embedded environments (e.g. small display, + * b/w graphics etc). + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class MiniDemo extends JFrame +{ + + /** + * Creates a new MiniDemo instance. + */ + MiniDemo() + { + createGUI(); + } + + private void createGUI() + { + JTabbedPane tabPane = new JTabbedPane(JTabbedPane.TOP, + JTabbedPane.SCROLL_TAB_LAYOUT); + + // Setup scrolling list in first tab. + Object[] listData = new Object[]{"Milk", "Beer", "Wine", "Water", + "Orange juice", "Tea", "Coffee", "Whiskey", + "Lemonade", "Apple juice", "Gin Tonic", + "Pangalactic Garleblaster", "Coke"}; + JList list = new JList(listData); + JScrollPane sp = new JScrollPane(list); + tabPane.addTab("List", sp); + + // Setup some buttons in the second tab. + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new GridLayout(4, 1)); + // JButtons + JPanel jButtonPanel = new JPanel(); + jButtonPanel.setLayout(new BorderLayout()); + final JCheckBox buttonState1 = new JCheckBox("Enabled", true); + jButtonPanel.add(buttonState1, BorderLayout.EAST); + JPanel jButtonContainer = new JPanel(); + final JButton jButton1 = new JButton("JButton"); + final JButton jButton2 = + new JButton(MetalIconFactory.getInternalFrameDefaultMenuIcon()); + jButtonContainer.add(jButton1); + jButtonContainer.add(jButton2); + jButtonPanel.add(jButtonContainer, BorderLayout.CENTER); + buttonState1.addActionListener( + new ActionListener() + { + public void actionPerformed(ActionEvent ev) + { + boolean enabled = buttonState1.isSelected(); + jButton1.setEnabled(enabled); + jButton2.setEnabled(enabled); + } + }); + buttonPanel.add(jButtonPanel); + // JToggleButtons + JPanel jToggleButtonPanel = new JPanel(); + jToggleButtonPanel.setLayout(new BorderLayout()); + final JCheckBox buttonState2 = new JCheckBox("Enabled", true); + jToggleButtonPanel.add(buttonState2, BorderLayout.EAST); + JPanel jToggleButtonContainer = new JPanel(); + final JButton jToggleButton1 = new JButton("JToggleButton"); + final JButton jToggleButton2 = + new JButton(MetalIconFactory.getInternalFrameDefaultMenuIcon()); + jToggleButtonContainer.add(jToggleButton1); + jToggleButtonContainer.add(jToggleButton2); + jToggleButtonPanel.add(jToggleButtonContainer, BorderLayout.CENTER); + buttonState2.addActionListener( + new ActionListener() + { + public void actionPerformed(ActionEvent ev) + { + boolean enabled = buttonState2.isSelected(); + jToggleButton1.setEnabled(enabled); + jToggleButton2.setEnabled(enabled); + } + }); + buttonPanel.add(jToggleButtonPanel); + tabPane.addTab("Buttons", buttonPanel); + + // ComboBoxes + JPanel comboBoxPanel = new JPanel(); + JComboBox comboBox = new JComboBox(listData); + comboBoxPanel.add(comboBox); + tabPane.add("ComboBox", comboBoxPanel); + + // TextFields + JPanel textFieldPanel = new JPanel(); + textFieldPanel.setLayout(new BoxLayout(textFieldPanel, BoxLayout.Y_AXIS)); + textFieldPanel.add(Box.createVerticalStrut(70)); + JPanel leftAlignedPanel = new JPanel(new BorderLayout()); + JPanel textFieldPanel1 = new JPanel(); + textFieldPanel1.setLayout(new BoxLayout(textFieldPanel1, + BoxLayout.X_AXIS)); + final JTextField textfield1 = new JTextField("Hello World!"); + textfield1.setHorizontalAlignment(JTextField.LEFT); + textfield1.setFont(new Font("Dialog", Font.PLAIN, 8)); + textFieldPanel1.add(textfield1); + final JTextField textfield2 = new JTextField("Hello World!"); + textfield2.setHorizontalAlignment(JTextField.LEFT); + textfield2.setFont(new Font("Dialog", Font.ITALIC, 12)); + textFieldPanel1.add(textfield2); + final JTextField textfield3 = new JTextField("Hello World!"); + textfield3.setHorizontalAlignment(JTextField.LEFT); + textfield3.setFont(new Font("Dialog", Font.BOLD, 14)); + textFieldPanel1.add(textfield3); + leftAlignedPanel.add(textFieldPanel1); + JPanel statePanel = new JPanel(); + statePanel.setLayout(new BoxLayout(statePanel, BoxLayout.Y_AXIS)); + statePanel.add(Box.createVerticalGlue()); + final JCheckBox enabled1 = new JCheckBox("enabled"); + enabled1.setSelected(true); + enabled1.addActionListener( + new ActionListener() + { + public void actionPerformed(ActionEvent ev) + { + boolean enabled = enabled1.isSelected(); + textfield1.setEnabled(enabled); + textfield2.setEnabled(enabled); + textfield3.setEnabled(enabled); + } + }); + statePanel.add(enabled1); + final JCheckBox editable1 = new JCheckBox("editable"); + editable1.setSelected(true); + editable1.addActionListener( + new ActionListener() + { + public void actionPerformed(ActionEvent ev) + { + boolean editable = editable1.isSelected(); + textfield1.setEditable(editable); + textfield2.setEditable(editable); + textfield3.setEditable(editable); + } + }); + statePanel.add(editable1); + statePanel.add(Box.createVerticalGlue()); + leftAlignedPanel.add(statePanel, BorderLayout.EAST); + textFieldPanel.add(leftAlignedPanel); + System.err.println(leftAlignedPanel.getPreferredSize()); + textFieldPanel.add(Box.createVerticalStrut(70)); + //panel.add(rightAlignedPanel); + tabPane.add("TextField", textFieldPanel); + setContentPane(tabPane); + } + + /** + * Starts the demo application. + * + * @param args the command line arguments (ignored) + */ + public static void main(String[] args) + { + SwingUtilities.invokeLater(new Runnable() { + public void run() + { + MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme()); + MiniDemo demo = new MiniDemo(); + demo.setSize(320, 200); + demo.setUndecorated(true); + demo.setVisible(true); + demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + }); + } + +} diff --git a/examples/gnu/classpath/examples/swing/ScrollBarDemo.java b/examples/gnu/classpath/examples/swing/ScrollBarDemo.java index fce137301..f90ffd4ce 100644 --- a/examples/gnu/classpath/examples/swing/ScrollBarDemo.java +++ b/examples/gnu/classpath/examples/swing/ScrollBarDemo.java @@ -1,5 +1,5 @@ /* ScrollBarDemo.java -- An example showing scroll bars in Swing. - Copyright (C) 2005, Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath examples. @@ -40,6 +40,8 @@ public class ScrollBarDemo implements ActionListener { + private JPanel content; + /** * Creates a new demo instance. * @@ -49,6 +51,19 @@ public class ScrollBarDemo { super(title); JPanel content = createContent(); + // initFrameContent() is only called (from main) when running this app + // standalone + } + + /** + * When the demo is run independently, the frame is displayed, so we should + * initialise the content panel (including the demo content and a close + * button). But when the demo is run as part of the Swing activity board, + * only the demo content panel is used, the frame itself is never displayed, + * so we can avoid this step. + */ + public void initFrameContent() + { JPanel closePanel = new JPanel(); JButton closeButton = new JButton("Close"); closeButton.setActionCommand("CLOSE"); @@ -67,9 +82,12 @@ public class ScrollBarDemo */ JPanel createContent() { - JPanel content = new JPanel(new BorderLayout()); - JPanel panel = createScrollBarPanel(); - content.add(panel); + if (content == null) + { + content = new JPanel(new BorderLayout()); + JPanel panel = createScrollBarPanel(); + content.add(panel); + } return content; } @@ -134,6 +152,7 @@ public class ScrollBarDemo public static void main(String[] args) { ScrollBarDemo app = new ScrollBarDemo("ScrollBar Demo"); + app.initFrameContent(); app.pack(); app.setVisible(true); } diff --git a/examples/gnu/classpath/examples/swing/SliderDemo.java b/examples/gnu/classpath/examples/swing/SliderDemo.java index 736024c48..2bc510788 100644 --- a/examples/gnu/classpath/examples/swing/SliderDemo.java +++ b/examples/gnu/classpath/examples/swing/SliderDemo.java @@ -1,5 +1,5 @@ /* SliderDemo.java -- An example showing JSlider in various configurations. - Copyright (C) 2005, Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath examples. @@ -35,7 +35,9 @@ import javax.swing.JSlider; public class SliderDemo extends JFrame implements ActionListener { - + + private JPanel content; + JSlider hslider1; JSlider hslider2; JSlider hslider3; @@ -59,7 +61,20 @@ public class SliderDemo extends JFrame implements ActionListener public SliderDemo(String frameTitle) { super(frameTitle); - JPanel content = createContent(); + content = createContent(); + // initFrameContent() is only called (from main) when running this app + // standalone + } + + /** + * When the demo is run independently, the frame is displayed, so we should + * initialise the content panel (including the demo content and a close + * button). But when the demo is run as part of the Swing activity board, + * only the demo content panel is used, the frame itself is never displayed, + * so we can avoid this step. + */ + public void initFrameContent() + { JPanel closePanel = new JPanel(); JButton closeButton = new JButton("Close"); closeButton.setActionCommand("CLOSE"); @@ -78,20 +93,23 @@ public class SliderDemo extends JFrame implements ActionListener */ JPanel createContent() { - JPanel content = new JPanel(new BorderLayout()); - JPanel panel = new JPanel(new GridLayout(1, 2)); - panel.add(createHorizontalPanel()); - panel.add(createVerticalPanel()); - enabledCheckBox = new JCheckBox("Enabled"); - enabledCheckBox.setSelected(true); - enabledCheckBox.setActionCommand("TOGGLE_ENABLED"); - enabledCheckBox.addActionListener(this); - JPanel checkBoxPanel = new JPanel(); - checkBoxPanel.add(enabledCheckBox); - JPanel panel2 = new JPanel(new BorderLayout()); - panel2.add(panel); - panel2.add(checkBoxPanel, BorderLayout.SOUTH); - content.add(panel2); + if (content == null) + { + content = new JPanel(new BorderLayout()); + JPanel panel = new JPanel(new GridLayout(1, 2)); + panel.add(createHorizontalPanel()); + panel.add(createVerticalPanel()); + enabledCheckBox = new JCheckBox("Enabled"); + enabledCheckBox.setSelected(true); + enabledCheckBox.setActionCommand("TOGGLE_ENABLED"); + enabledCheckBox.addActionListener(this); + JPanel checkBoxPanel = new JPanel(); + checkBoxPanel.add(enabledCheckBox); + JPanel panel2 = new JPanel(new BorderLayout()); + panel2.add(panel); + panel2.add(checkBoxPanel, BorderLayout.SOUTH); + content.add(panel2); + } return content; } @@ -242,6 +260,7 @@ public class SliderDemo extends JFrame implements ActionListener public static void main(String[] args) { SliderDemo app = new SliderDemo("Slider Demo"); + app.initFrameContent(); app.pack(); app.setVisible(true); } diff --git a/examples/gnu/classpath/examples/swing/SpinnerDemo.java b/examples/gnu/classpath/examples/swing/SpinnerDemo.java new file mode 100644 index 000000000..4a05bc482 --- /dev/null +++ b/examples/gnu/classpath/examples/swing/SpinnerDemo.java @@ -0,0 +1,230 @@ +/* SpinnerDemo.java -- An example showing various spinners in Swing. + Copyright (C) 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath examples. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. +*/ + + +package gnu.classpath.examples.swing; + +import java.awt.BorderLayout; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Calendar; +import java.util.Date; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerDateModel; +import javax.swing.SpinnerListModel; +import javax.swing.SpinnerNumberModel; +import javax.swing.UIManager; +import javax.swing.plaf.metal.DefaultMetalTheme; +import javax.swing.plaf.metal.MetalLookAndFeel; + +/** + * A simple demo showing various spinners in different states. + */ +public class SpinnerDemo + extends JFrame + implements ActionListener +{ + private JPanel content; + private JCheckBox spinnerState1; + private JSpinner spinner1; + private JSpinner spinner2; + + private JCheckBox spinnerState2; + private JSpinner spinner3; + private JSpinner spinner4; + + private JCheckBox spinnerState3; + private JSpinner spinner5; + private JSpinner spinner6; + + /** + * Creates a new demo instance. + * + * @param title the frame title. + */ + public SpinnerDemo(String title) + { + super(title); + JPanel content = createContent(); + // initFrameContent() is only called (from main) when running this app + // standalone + } + + /** + * When the demo is run independently, the frame is displayed, so we should + * initialise the content panel (including the demo content and a close + * button). But when the demo is run as part of the Swing activity board, + * only the demo content panel is used, the frame itself is never displayed, + * so we can avoid this step. + */ + public void initFrameContent() + { + JPanel closePanel = new JPanel(); + JButton closeButton = new JButton("Close"); + closeButton.setActionCommand("CLOSE"); + closeButton.addActionListener(this); + closePanel.add(closeButton); + content.add(closePanel, BorderLayout.SOUTH); + getContentPane().add(content); + } + + /** + * Returns a panel with the demo content. The panel + * uses a BorderLayout(), and the BorderLayout.SOUTH area + * is empty, to allow callers to add controls to the + * bottom of the panel if they want to (a close button is + * added if this demo is being run as a standalone demo). + */ + JPanel createContent() + { + if (content == null) + { + content = new JPanel(new BorderLayout()); + JPanel panel = new JPanel(new GridLayout(3, 1)); + panel.add(createPanel1()); + panel.add(createPanel2()); + panel.add(createPanel3()); + content.add(panel); + } + return content; + } + + private JPanel createPanel1() + { + JPanel panel = new JPanel(new BorderLayout()); + this.spinnerState1 = new JCheckBox("Enabled", true); + this.spinnerState1.setActionCommand("COMBO_STATE1"); + this.spinnerState1.addActionListener(this); + panel.add(this.spinnerState1, BorderLayout.EAST); + + JPanel controlPanel = new JPanel(); + controlPanel.setBorder(BorderFactory.createTitledBorder( + "Number Spinner: ")); + this.spinner1 = new JSpinner(new SpinnerNumberModel(5.0, 0.0, 10.0, 0.5)); + this.spinner2 = new JSpinner(new SpinnerNumberModel(50, 0, 100, 5)); + this.spinner2.setFont(new Font("Dialog", Font.PLAIN, 20)); + controlPanel.add(this.spinner1); + controlPanel.add(this.spinner2); + + panel.add(controlPanel); + + return panel; + } + + private JPanel createPanel2() + { + JPanel panel = new JPanel(new BorderLayout()); + this.spinnerState2 = new JCheckBox("Enabled", true); + this.spinnerState2.setActionCommand("COMBO_STATE2"); + this.spinnerState2.addActionListener(this); + panel.add(this.spinnerState2, BorderLayout.EAST); + + JPanel controlPanel = new JPanel(); + controlPanel.setBorder(BorderFactory.createTitledBorder("Date Spinner: ")); + this.spinner3 = new JSpinner(new SpinnerDateModel(new Date(), null, null, + Calendar.DATE)); + + this.spinner4 = new JSpinner(new SpinnerDateModel(new Date(), null, null, + Calendar.YEAR)); + this.spinner4.setFont(new Font("Dialog", Font.PLAIN, 20)); + + controlPanel.add(this.spinner3); + controlPanel.add(this.spinner4); + + panel.add(controlPanel); + + return panel; + } + + private JPanel createPanel3() + { + JPanel panel = new JPanel(new BorderLayout()); + this.spinnerState3 = new JCheckBox("Enabled", true); + this.spinnerState3.setActionCommand("COMBO_STATE3"); + this.spinnerState3.addActionListener(this); + panel.add(this.spinnerState3, BorderLayout.EAST); + + JPanel controlPanel = new JPanel(); + controlPanel.setBorder(BorderFactory.createTitledBorder("List Spinner: ")); + this.spinner5 = new JSpinner(new SpinnerListModel(new Object[] {"Red", + "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet"})); + + this.spinner6 = new JSpinner(new SpinnerListModel(new Object[] {"Red", + "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet"})); + this.spinner6.setValue("Yellow"); + this.spinner6.setFont(new Font("Dialog", Font.PLAIN, 20)); + + controlPanel.add(this.spinner5); + controlPanel.add(this.spinner6); + + panel.add(controlPanel); + + return panel; + } + + public void actionPerformed(ActionEvent e) + { + if (e.getActionCommand().equals("COMBO_STATE1")) + { + spinner1.setEnabled(spinnerState1.isSelected()); + spinner2.setEnabled(spinnerState1.isSelected()); + } + else if (e.getActionCommand().equals("COMBO_STATE2")) + { + spinner3.setEnabled(spinnerState2.isSelected()); + spinner4.setEnabled(spinnerState2.isSelected()); + } + else if (e.getActionCommand().equals("COMBO_STATE3")) + { + spinner5.setEnabled(spinnerState3.isSelected()); + spinner6.setEnabled(spinnerState3.isSelected()); + } + else if (e.getActionCommand().equals("CLOSE")) + { + System.exit(0); + } + } + + public static void main(String[] args) + { + try + { + MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme()); + UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel()); + } + catch (Exception e) { + e.printStackTrace(); + } + SpinnerDemo app = new SpinnerDemo("Spinner Demo"); + app.initFrameContent(); + app.pack(); + app.setVisible(true); + } + +} diff --git a/examples/gnu/classpath/examples/swing/TableDemo.java b/examples/gnu/classpath/examples/swing/TableDemo.java new file mode 100644 index 000000000..1fbf2de53 --- /dev/null +++ b/examples/gnu/classpath/examples/swing/TableDemo.java @@ -0,0 +1,236 @@ +/* TableDemo.java -- Demonstrates the use of JTable. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.classpath.examples.swing; + +import java.awt.BorderLayout; +import java.awt.Dimension; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.DefaultTableColumnModel; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumn; + +/** + * Displays the editable table. The first column consists of check boxes. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class TableDemo extends JFrame +{ + /** + * The initial row count for this table. + */ + static int rows = 32; + + /** + * The initial column count for this table. + */ + static int cols = 7; + + + /** + * The table model. + */ + class TModel extends DefaultTableModel + { + + /** + * Return true if the cell is editable. All cells are editable. + */ + public boolean isCellEditable(int parm1, int parm2) + { + return true; + } + + /** + * Get the number of the table rows. + */ + public int getRowCount() + { + return rows; + } + + /** + * Get the number of the table columns. + */ + public int getColumnCount() + { + return cols; + } + + /** + * Set the value at the given position + */ + public void setValueAt(Object aValue, int aRow, int aColumn) + { + values[aRow][aColumn] = aValue; + } + + /** + * Get the value at the given position. + */ + public Object getValueAt(int aRow, int aColumn) + { + return values[aRow][aColumn]; + } + + /** + * The column name, as suggested by model. This header should not be + * visible, as it is overridden by setting the header name with + * {@link TableColumn#setHeaderValue} in {@link TableDemo#createContent}. + */ + public String getColumnName(int column) + { + return "Error "+column; + } + + /** + * The first column contains booleans, others - default class. + */ + public Class getColumnClass(int column) + { + if (column == 0) + return Boolean.class; + else + return super.getColumnClass(column); + } + } + + private JPanel content; + + /** + * The table being displayed. + */ + JTable table = new JTable(); + + /** + * The table model. + */ + TModel model = new TModel(); + + /** + * The table value array. + */ + Object[][] values; + + /** + * Create the table demo with the given titel. + * + * @param title the frame title. + */ + public TableDemo(String title) + { + super(title); + getContentPane().add(createContent(), BorderLayout.CENTER); + } + + /** + * Returns a panel with the demo content. The panel uses a BorderLayout(), and + * the BorderLayout.SOUTH area is empty, to allow callers to add controls to + * the bottom of the panel if they want to (a close button is added if this + * demo is being run as a standalone demo). + */ + JPanel createContent() + { + if (content == null) + { + JPanel p = new JPanel(); + p.setLayout(new BorderLayout()); + values = new Object[rows][]; + for (int i = 0; i < values.length; i++) + { + values[i] = new Object[cols]; + for (int j = 1; j < cols; j++) + { + values[i][j] = "" + ((char) ('a' + j)) + i; + } + values [i][0] = i % 2 == 0? Boolean.TRUE : Boolean.FALSE; + } + + table.setModel(model); + + // Make the columns with gradually increasing width: + DefaultTableColumnModel cm = new DefaultTableColumnModel(); + for (int i = 0; i < cols; i++) + { + TableColumn column = new TableColumn(i); + + // Showing the variable width columns. + int width = 100+20*i; + column.setPreferredWidth(width); + + // If we do not set the header value here, the value, returned + // by model, is used. + column.setHeaderValue("Width +"+(20*i)); + + cm.addColumn(column); + } + + table.setColumnModel(cm); + + // Create the table, place it into scroll pane and place + // the pane into this frame. + JScrollPane scroll = new JScrollPane(); + + // The horizontal scroll bar is never needed. + scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scroll.getViewport().add(table); + p.add(scroll, BorderLayout.CENTER); + content = p; + } + return content; + } + + /** + * The executable method to display the editable table. + * + * @param args + * unused. + */ + public static void main(String[] args) + { + TableDemo frame = new TableDemo("Table double click on the cell to edit."); + frame.setSize(new Dimension(640, 100)); + frame.validate(); + frame.setVisible(true); + } +} diff --git a/examples/gnu/classpath/examples/swing/TextFieldDemo.java b/examples/gnu/classpath/examples/swing/TextFieldDemo.java index 5ddf11680..6eda46905 100644 --- a/examples/gnu/classpath/examples/swing/TextFieldDemo.java +++ b/examples/gnu/classpath/examples/swing/TextFieldDemo.java @@ -1,5 +1,5 @@ /* TextFieldDemo.java -- An example showing various textfields in Swing. - Copyright (C) 2005, Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath examples. @@ -107,6 +107,8 @@ public class TextFieldDemo } } + private JPanel content; + /** * The left aligned textfields and state buttons. */ @@ -115,7 +117,7 @@ public class TextFieldDemo JTextField textfield3; JCheckBox enabled1; JCheckBox editable1; -JPanel textFieldPanel1; + JPanel textFieldPanel1; /** * The right aligned textfields and state buttons. */ @@ -162,6 +164,19 @@ JPanel textFieldPanel1; { super(title); JPanel content = createContent(); + // initFrameContent() is only called (from main) when running this app + // standalone + } + + /** + * When the demo is run independently, the frame is displayed, so we should + * initialise the content panel (including the demo content and a close + * button). But when the demo is run as part of the Swing activity board, + * only the demo content panel is used, the frame itself is never displayed, + * so we can avoid this step. + */ + public void initFrameContent() + { JPanel closePanel = new JPanel(); JButton closeButton = new JButton("Close"); closeButton.setActionCommand("CLOSE"); @@ -180,15 +195,18 @@ JPanel textFieldPanel1; */ JPanel createContent() { - JPanel content = new JPanel(new BorderLayout()); - JPanel panel = new JPanel(new GridLayout(5, 1)); - panel.add(createLeftAlignedPanel()); - panel.add(createRightAlignedPanel()); - panel.add(createCenteredPanel()); - panel.add(createCustomColoredPanel()); - panel.add(createMiscPanel()); - content.add(panel); - //content.setPreferredSize(new Dimension(400, 300)); + if (content == null) + { + content = new JPanel(new BorderLayout()); + JPanel panel = new JPanel(new GridLayout(5, 1)); + panel.add(createLeftAlignedPanel()); + panel.add(createRightAlignedPanel()); + panel.add(createCenteredPanel()); + panel.add(createCustomColoredPanel()); + panel.add(createMiscPanel()); + content.add(panel); + //content.setPreferredSize(new Dimension(400, 300)); + } return content; } @@ -481,6 +499,7 @@ JPanel textFieldPanel1; public static void main(String[] args) { TextFieldDemo app = new TextFieldDemo("TextField Demo"); + app.initFrameContent(); app.pack(); app.setVisible(true); } diff --git a/external/Makefile.am b/external/Makefile.am index 9f7b5fad5..7f6273373 100644 --- a/external/Makefile.am +++ b/external/Makefile.am @@ -1,5 +1,5 @@ ## Input file for automake to generate the Makefile.in used by configure -SUBDIRS = sax w3c_dom +SUBDIRS = sax w3c_dom relaxngDatatype EXTRA_DIST = README diff --git a/external/relaxngDatatype/.cvsignore b/external/relaxngDatatype/.cvsignore new file mode 100644 index 000000000..282522db0 --- /dev/null +++ b/external/relaxngDatatype/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/external/relaxngDatatype/Makefile.am b/external/relaxngDatatype/Makefile.am new file mode 100644 index 000000000..8afce6597 --- /dev/null +++ b/external/relaxngDatatype/Makefile.am @@ -0,0 +1,14 @@ +## Input file for automake to generate the Makefile.in used by configure + +EXTRA_DIST = README.txt \ +copying.txt \ +org/relaxng/datatype/Datatype.java \ +org/relaxng/datatype/DatatypeBuilder.java \ +org/relaxng/datatype/DatatypeException.java \ +org/relaxng/datatype/DatatypeLibrary.java \ +org/relaxng/datatype/DatatypeLibraryFactory.java \ +org/relaxng/datatype/DatatypeStreamingValidator.java \ +org/relaxng/datatype/ValidationContext.java \ +org/relaxng/datatype/helpers/DatatypeLibraryLoader.java \ +org/relaxng/datatype/helpers/ParameterlessDatatypeBuilder.java \ +org/relaxng/datatype/helpers/StreamingValidatorImpl.java diff --git a/external/relaxngDatatype/README.txt b/external/relaxngDatatype/README.txt new file mode 100755 index 000000000..70d49b5fa --- /dev/null +++ b/external/relaxngDatatype/README.txt @@ -0,0 +1,54 @@ +====================================================================== + README FILE FOR DATATYPE INTERFACES FOR RELAX NG +====================================================================== + + + +RELAX NG supports multiple datatype vocabularies. To achive this, an +interface between datatype vocabularies and schema processors is +necessary. This interface is intended to be a standard Java interface +for this purpose. + + +---------------------------------------------------------------------- +LICENSE +---------------------------------------------------------------------- + +See copying.txt. + +Note: this license is the BSD license. + + + +---------------------------------------------------------------------- +FOR DEVELOPER +---------------------------------------------------------------------- + +If you are planning to implement a datatype library, A sample datatype +library implementation by James Clark is available at [1], which +comes with documentation and source code. + +If you are planning to implement a schema processor, then don't forget +to check out org.relaxng.datatype.helpers.DatatypeLibraryLoader, as +this allows you to dynamically locate datatype implementations. + + +---------------------------------------------------------------------- +LINKS +---------------------------------------------------------------------- + +* OASIS RELAX NG TC + http://www.oasis-open.org/committees/relax-ng/ +* RELAX home page + http://www.xml.gr.jp/relax/ + + +---------------------------------------------------------------------- +REFERENCES +---------------------------------------------------------------------- +[1] Sample datatype library implementation by James Clark + http://www.thaiopensource.com/relaxng/datatype-sample.zip + +Document written by Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) +====================================================================== +END OF README diff --git a/external/relaxngDatatype/copying.txt b/external/relaxngDatatype/copying.txt new file mode 100755 index 000000000..1b86eab60 --- /dev/null +++ b/external/relaxngDatatype/copying.txt @@ -0,0 +1,30 @@ +Copyright (c) 2001, Thai Open Source Software Center Ltd, Sun Microsystems. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + Neither the names of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/external/relaxngDatatype/org/relaxng/datatype/Datatype.java b/external/relaxngDatatype/org/relaxng/datatype/Datatype.java new file mode 100755 index 000000000..cf2dac134 --- /dev/null +++ b/external/relaxngDatatype/org/relaxng/datatype/Datatype.java @@ -0,0 +1,237 @@ +package org.relaxng.datatype; + +/** + * Datatype object. + * + * This object has the following functionality: + * + * <ol> + * <li> functionality to identify a class of character sequences. This is + * done through the isValid method. + * + * <li> functionality to produce a "value object" from a character sequence and + * context information. + * + * <li> functionality to test the equality of two value objects. + * </ol> + * + * This interface also defines the createStreamingValidator method, + * which is intended to efficiently support the validation of + * large character sequences. + * + * @author <a href="mailto:jjc@jclark.com">James Clark</a> + * @author <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> + */ +public interface Datatype { + + /** + * Checks if the specified 'literal' matches this Datatype + * with respect to the current context. + * + * @param literal + * the lexical representation to be checked. + * @param context + * If this datatype is context-dependent + * (i.e. the {@link #isContextDependent} method returns true), + * then the caller must provide a non-null valid context object. + * Otherwise, the caller can pass null. + * + * @return + * true if the 'literal' is a member of this Datatype; + * false if it's not a member of this Datatype. + */ + boolean isValid( String literal, ValidationContext context ); + + /** + * Similar to the isValid method but throws an exception with diagnosis + * in case of errors. + * + * <p> + * If the specified 'literal' is a valid lexical representation for this + * datatype, then this method must return without throwing any exception. + * If not, the callee must throw an exception (with diagnosis message, + * if possible.) + * + * <p> + * The application can use this method to provide detailed error message + * to users. This method is kept separate from the isValid method to + * achieve higher performance during normal validation. + * + * @exception DatatypeException + * If the given literal is invalid, then this exception is thrown. + * If the callee supports error diagnosis, then the exception should + * contain a diagnosis message. + */ + void checkValid( String literal, ValidationContext context ) + throws DatatypeException; + + /** + * Creates an instance of a streaming validator for this type. + * + * <p> + * By using streaming validators instead of the isValid method, + * the caller can avoid keeping the entire string, which is + * sometimes quite big, in memory. + * + * @param context + * If this datatype is context-dependent + * (i.e. the {@link #isContextDependent} method returns true), + * then the caller must provide a non-null valid context object. + * Otherwise, the caller can pass null. + * The callee may keep a reference to this context object + * only while the returned streaming validator is being used. + */ + DatatypeStreamingValidator createStreamingValidator( ValidationContext context ); + + /** + * Converts lexcial value and the current context to the corresponding + * value object. + * + * <p> + * The caller cannot generally assume that the value object is + * a meaningful Java object. For example, the caller cannot expect + * this method to return <code>java.lang.Number</code> type for + * the "integer" type of XML Schema Part 2. + * + * <p> + * Also, the caller cannot assume that the equals method and + * the hashCode method of the value object are consistent with + * the semantics of the datatype. For that purpose, the sameValue + * method and the valueHashCode method have to be used. Note that + * this means you cannot use classes like + * <code>java.util.Hashtable</code> to store the value objects. + * + * <p> + * The returned value object should be used solely for the sameValue + * and valueHashCode methods. + * + * @param context + * If this datatype is context-dependent + * (when the {@link #isContextDependent} method returns true), + * then the caller must provide a non-null valid context object. + * Otherwise, the caller can pass null. + * + * @return null + * when the given lexical value is not a valid lexical + * value for this type. + */ + Object createValue( String literal, ValidationContext context ); + + /** + * Tests the equality of two value objects which were originally + * created by the createValue method of this object. + * + * The behavior is undefined if objects not created by this type + * are passed. It is the caller's responsibility to ensure that + * value objects belong to this type. + * + * @return + * true if two value objects are considered equal according to + * the definition of this datatype; false if otherwise. + */ + boolean sameValue( Object value1, Object value2 ); + + + /** + * Computes the hash code for a value object, + * which is consistent with the sameValue method. + * + * @return + * hash code for the specified value object. + */ + int valueHashCode( Object value ); + + + + + /** + * Indicates that the datatype doesn't have ID/IDREF semantics. + * + * This value is one of the possible return values of the + * {@link #getIdType} method. + */ + public static final int ID_TYPE_NULL = 0; + + /** + * Indicates that RELAX NG compatibility processors should + * treat this datatype as having ID semantics. + * + * This value is one of the possible return values of the + * {@link #getIdType} method. + */ + public static final int ID_TYPE_ID = 1; + + /** + * Indicates that RELAX NG compatibility processors should + * treat this datatype as having IDREF semantics. + * + * This value is one of the possible return values of the + * {@link #getIdType} method. + */ + public static final int ID_TYPE_IDREF = 2; + + /** + * Indicates that RELAX NG compatibility processors should + * treat this datatype as having IDREFS semantics. + * + * This value is one of the possible return values of the + * {@link #getIdType} method. + */ + public static final int ID_TYPE_IDREFS = 3; + + /** + * Checks if the ID/IDREF semantics is associated with this + * datatype. + * + * <p> + * This method is introduced to support the RELAX NG DTD + * compatibility spec. (Of course it's always free to use + * this method for other purposes.) + * + * <p> + * If you are implementing a datatype library and have no idea about + * the "RELAX NG DTD compatibility" thing, just return + * <code>ID_TYPE_NULL</code> is fine. + * + * @return + * If this datatype doesn't have any ID/IDREF semantics, + * it returns {@link #ID_TYPE_NULL}. If it has such a semantics + * (for example, XSD:ID, XSD:IDREF and comp:ID type), then + * it returns {@link #ID_TYPE_ID}, {@link #ID_TYPE_IDREF} or + * {@link #ID_TYPE_IDREFS}. + */ + public int getIdType(); + + + /** + * Checks if this datatype may need a context object for + * the validation. + * + * <p> + * The callee must return true even when the context + * is not always necessary. (For example, the "QName" type + * doesn't need a context object when validating unprefixed + * string. But nonetheless QName must return true.) + * + * <p> + * XSD's <code>string</code> and <code>short</code> types + * are examples of context-independent datatypes. + * Its <code>QName</code> and <code>ENTITY</code> types + * are examples of context-dependent datatypes. + * + * <p> + * When a datatype is context-independent, then + * the {@link #isValid} method, the {@link #checkValid} method, + * the {@link #createStreamingValidator} method and + * the {@link #createValue} method can be called without + * providing a context object. + * + * @return + * <b>true</b> if this datatype is context-dependent + * (it needs a context object sometimes); + * + * <b>false</b> if this datatype is context-<b>in</b>dependent + * (it never needs a context object). + */ + public boolean isContextDependent(); +} diff --git a/external/relaxngDatatype/org/relaxng/datatype/DatatypeBuilder.java b/external/relaxngDatatype/org/relaxng/datatype/DatatypeBuilder.java new file mode 100755 index 000000000..75530de3c --- /dev/null +++ b/external/relaxngDatatype/org/relaxng/datatype/DatatypeBuilder.java @@ -0,0 +1,45 @@ +package org.relaxng.datatype; + +/** + * Creates a user-defined type by adding parameters to + * the pre-defined type. + * + * @author <a href="mailto:jjc@jclark.com">James Clark</a> + * @author <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> + */ +public interface DatatypeBuilder { + + /** + * Adds a new parameter. + * + * @param name + * The name of the parameter to be added. + * @param strValue + * The raw value of the parameter. Caller may not normalize + * this value because any white space is potentially significant. + * @param context + * The context information which can be used by the callee to + * acquire additional information. This context object is + * valid only during this method call. The callee may not + * keep a reference to this object. + * @exception DatatypeException + * When the given parameter is inappropriate for some reason. + * The callee is responsible to recover from this error. + * That is, the object should behave as if no such error + * was occured. + */ + void addParameter( String name, String strValue, ValidationContext context ) + throws DatatypeException; + + /** + * Derives a new Datatype from a Datatype by parameters that + * were already set through the addParameter method. + * + * @exception DatatypeException + * DatatypeException must be thrown if the derivation is + * somehow invalid. For example, a required parameter is missing, + * etc. The exception should contain a diagnosis message + * if possible. + */ + Datatype createDatatype() throws DatatypeException; +} diff --git a/external/relaxngDatatype/org/relaxng/datatype/DatatypeException.java b/external/relaxngDatatype/org/relaxng/datatype/DatatypeException.java new file mode 100755 index 000000000..970a99548 --- /dev/null +++ b/external/relaxngDatatype/org/relaxng/datatype/DatatypeException.java @@ -0,0 +1,39 @@ +package org.relaxng.datatype; + +/** + * Signals Datatype related exceptions. + * + * @author <a href="mailto:jjc@jclark.com">James Clark</a> + * @author <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> + */ +public class DatatypeException extends Exception { + + public DatatypeException( int index, String msg ) { + super(msg); + this.index = index; + } + public DatatypeException( String msg ) { + this(UNKNOWN,msg); + } + /** + * A constructor for those datatype libraries which don't support any + * diagnostic information at all. + */ + public DatatypeException() { + this(UNKNOWN,null); + } + + + private final int index; + + public static final int UNKNOWN = -1; + + /** + * Gets the index of the content where the error occured. + * UNKNOWN can be returned to indicate that no index information + * is available. + */ + public int getIndex() { + return index; + } +} diff --git a/external/relaxngDatatype/org/relaxng/datatype/DatatypeLibrary.java b/external/relaxngDatatype/org/relaxng/datatype/DatatypeLibrary.java new file mode 100755 index 000000000..e18f2b379 --- /dev/null +++ b/external/relaxngDatatype/org/relaxng/datatype/DatatypeLibrary.java @@ -0,0 +1,37 @@ +package org.relaxng.datatype; + +/** + * A Datatype library + * + * @author <a href="mailto:jjc@jclark.com">James Clark</a> + * @author <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> + */ +public interface DatatypeLibrary { + + /** + * Creates a new instance of DatatypeBuilder. + * + * The callee should throw a DatatypeException in case of an error. + * + * @param baseTypeLocalName + * The local name of the base type. + * + * @return + * A non-null valid datatype object. + */ + DatatypeBuilder createDatatypeBuilder( String baseTypeLocalName ) + throws DatatypeException; + + /** + * Gets or creates a pre-defined type. + * + * This is just a short-cut of + * <code>createDatatypeBuilder(typeLocalName).createDatatype();</code> + * + * The callee should throw a DatatypeException in case of an error. + * + * @return + * A non-null valid datatype object. + */ + Datatype createDatatype( String typeLocalName ) throws DatatypeException; +} diff --git a/external/relaxngDatatype/org/relaxng/datatype/DatatypeLibraryFactory.java b/external/relaxngDatatype/org/relaxng/datatype/DatatypeLibraryFactory.java new file mode 100755 index 000000000..cdf1eef3c --- /dev/null +++ b/external/relaxngDatatype/org/relaxng/datatype/DatatypeLibraryFactory.java @@ -0,0 +1,26 @@ +package org.relaxng.datatype; + +/** + * Factory class for the DatatypeLibrary class. + * + * <p> + * The datatype library should provide the implementation of + * this interface if it wants to be found by the schema processors. + * The implementor also have to place a file in your jar file. + * See the reference datatype library implementation for detail. + * + * @author <a href="mailto:jjc@jclark.com">James Clark</a> + * @author <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> + */ +public interface DatatypeLibraryFactory +{ + /** + * Creates a new instance of a DatatypeLibrary that supports + * the specified namespace URI. + * + * @return + * <code>null</code> if the specified namespace URI is not + * supported. + */ + DatatypeLibrary createDatatypeLibrary( String namespaceURI ); +} diff --git a/external/relaxngDatatype/org/relaxng/datatype/DatatypeStreamingValidator.java b/external/relaxngDatatype/org/relaxng/datatype/DatatypeStreamingValidator.java new file mode 100755 index 000000000..995205731 --- /dev/null +++ b/external/relaxngDatatype/org/relaxng/datatype/DatatypeStreamingValidator.java @@ -0,0 +1,46 @@ +package org.relaxng.datatype; + +/** + * Datatype streaming validator. + * + * <p> + * The streaming validator is an optional feature that is useful for + * certain Datatypes. It allows the caller to incrementally provide + * the literal. + * + * @author <a href="mailto:jjc@jclark.com">James Clark</a> + * @author <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> + */ +public interface DatatypeStreamingValidator { + + /** + * Passes an additional fragment of the literal. + * + * <p> + * The application can call this method several times, then call + * the isValid method (or the checkValid method) to check the validity + * of the accumulated characters. + */ + void addCharacters( char[] buf, int start, int len ); + + /** + * Tells if the accumulated literal is valid with respect to + * the underlying Datatype. + * + * @return + * True if it is valid. False if otherwise. + */ + boolean isValid(); + + /** + * Similar to the isValid method, but this method throws + * Exception (with possibly diagnostic information), instead of + * returning false. + * + * @exception DatatypeException + * If the callee supports the diagnosis and the accumulated + * literal is invalid, then this exception that possibly + * contains diagnosis information is thrown. + */ + void checkValid() throws DatatypeException; +} diff --git a/external/relaxngDatatype/org/relaxng/datatype/ValidationContext.java b/external/relaxngDatatype/org/relaxng/datatype/ValidationContext.java new file mode 100755 index 000000000..61e38f28d --- /dev/null +++ b/external/relaxngDatatype/org/relaxng/datatype/ValidationContext.java @@ -0,0 +1,66 @@ +package org.relaxng.datatype; + +/** + * An interface that must be implemented by caller to + * provide context information that is necessary to + * perform validation of some Datatypes. + * + * @author <a href="mailto:jjc@jclark.com">James Clark</a> + * @author <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> + */ +public interface ValidationContext { + + /** + * Resolves a namespace prefix to the corresponding namespace URI. + * + * This method is used for validating the QName type, for example. + * + * <p> + * If the prefix is "" (empty string), it indicates + * an unprefixed value. The callee + * should resolve it as for an unprefixed + * element, rather than for an unprefixed attribute. + * + * <p> + * If the prefix is "xml", then the callee must resolve + * this prefix into "http://www.w3.org/XML/1998/namespace", + * as defined in the XML Namespaces Recommendation. + * + * @return + * namespace URI of this prefix. + * If the specified prefix is not declared, + * the implementation must return null. + */ + String resolveNamespacePrefix( String prefix ); + + /** + * Returns the base URI of the context. The null string may be returned + * if no base URI is known. + */ + String getBaseUri(); + + /** + * Checks if an unparsed entity is declared with the + * specified name. + * + * @return + * true + * if the DTD has an unparsed entity declaration for + * the specified name. + * false + * otherwise. + */ + boolean isUnparsedEntity( String entityName ); + + /** + * Checks if a notation is declared with the + * specified name. + * + * @return + * true + * if the DTD has a notation declaration for the specified name. + * false + * otherwise. + */ + boolean isNotation( String notationName ); +} diff --git a/external/relaxngDatatype/org/relaxng/datatype/helpers/DatatypeLibraryLoader.java b/external/relaxngDatatype/org/relaxng/datatype/helpers/DatatypeLibraryLoader.java new file mode 100755 index 000000000..43c44382f --- /dev/null +++ b/external/relaxngDatatype/org/relaxng/datatype/helpers/DatatypeLibraryLoader.java @@ -0,0 +1,262 @@ +/** + * Copyright (c) 2001, Thai Open Source Software Center Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Thai Open Source Software Center Ltd nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.relaxng.datatype.helpers; + +import org.relaxng.datatype.DatatypeLibraryFactory; +import org.relaxng.datatype.DatatypeLibrary; +import java.util.Enumeration; +import java.util.NoSuchElementException; +import java.util.Vector; +import java.io.Reader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URL; + +/** + * Discovers the datatype library implementation from the classpath. + * + * <p> + * The call of the createDatatypeLibrary method finds an implementation + * from a given datatype library URI at run-time. + */ +public class DatatypeLibraryLoader implements DatatypeLibraryFactory { + private final Service service = new Service(DatatypeLibraryFactory.class); + + public DatatypeLibrary createDatatypeLibrary(String uri) { + for (Enumeration e = service.getProviders(); + e.hasMoreElements();) { + DatatypeLibraryFactory factory + = (DatatypeLibraryFactory)e.nextElement(); + DatatypeLibrary library = factory.createDatatypeLibrary(uri); + if (library != null) + return library; + } + return null; + } + + private static class Service { + private final Class serviceClass; + private final Enumeration configFiles; + private Enumeration classNames = null; + private final Vector providers = new Vector(); + private Loader loader; + + private class ProviderEnumeration implements Enumeration { + private int nextIndex = 0; + + public boolean hasMoreElements() { + return nextIndex < providers.size() || moreProviders(); + } + + public Object nextElement() { + try { + return providers.elementAt(nextIndex++); + } + catch (ArrayIndexOutOfBoundsException e) { + throw new NoSuchElementException(); + } + } + } + + private static class Singleton implements Enumeration { + private Object obj; + private Singleton(Object obj) { + this.obj = obj; + } + + public boolean hasMoreElements() { + return obj != null; + } + + public Object nextElement() { + if (obj == null) + throw new NoSuchElementException(); + Object tem = obj; + obj = null; + return tem; + } + } + + // JDK 1.1 + private static class Loader { + Enumeration getResources(String resName) { + ClassLoader cl = Loader.class.getClassLoader(); + URL url; + if (cl == null) + url = ClassLoader.getSystemResource(resName); + else + url = cl.getResource(resName); + return new Singleton(url); + } + + Class loadClass(String name) throws ClassNotFoundException { + return Class.forName(name); + } + } + + // JDK 1.2+ + private static class Loader2 extends Loader { + private ClassLoader cl; + + Loader2() { + cl = Loader2.class.getClassLoader(); + // If the thread context class loader has the class loader + // of this class as an ancestor, use the thread context class + // loader. Otherwise, the thread context class loader + // probably hasn't been set up properly, so don't use it. + ClassLoader clt = Thread.currentThread().getContextClassLoader(); + for (ClassLoader tem = clt; tem != null; tem = tem.getParent()) + if (tem == cl) { + cl = clt; + break; + } + } + + Enumeration getResources(String resName) { + try { + return cl.getResources(resName); + } + catch (IOException e) { + return new Singleton(null); + } + } + + Class loadClass(String name) throws ClassNotFoundException { + return Class.forName(name, true, cl); + } + } + + public Service(Class cls) { + try { + loader = new Loader2(); + } + catch (NoSuchMethodError e) { + loader = new Loader(); + } + serviceClass = cls; + String resName = "META-INF/services/" + serviceClass.getName(); + configFiles = loader.getResources(resName); + } + + public Enumeration getProviders() { + return new ProviderEnumeration(); + } + + synchronized private boolean moreProviders() { + for (;;) { + while (classNames == null) { + if (!configFiles.hasMoreElements()) + return false; + classNames = parseConfigFile((URL)configFiles.nextElement()); + } + while (classNames.hasMoreElements()) { + String className = (String)classNames.nextElement(); + try { + Class cls = loader.loadClass(className); + Object obj = cls.newInstance(); + if (serviceClass.isInstance(obj)) { + providers.addElement(obj); + return true; + } + } + catch (ClassNotFoundException e) { } + catch (InstantiationException e) { } + catch (IllegalAccessException e) { } + catch (LinkageError e) { } + } + classNames = null; + } + } + + private static final int START = 0; + private static final int IN_NAME = 1; + private static final int IN_COMMENT = 2; + + private static Enumeration parseConfigFile(URL url) { + try { + InputStream in = url.openStream(); + Reader r; + try { + r = new InputStreamReader(in, "UTF-8"); + } + catch (UnsupportedEncodingException e) { + r = new InputStreamReader(in, "UTF8"); + } + r = new BufferedReader(r); + Vector tokens = new Vector(); + StringBuffer tokenBuf = new StringBuffer(); + int state = START; + for (;;) { + int n = r.read(); + if (n < 0) + break; + char c = (char)n; + switch (c) { + case '\r': + case '\n': + state = START; + break; + case ' ': + case '\t': + break; + case '#': + state = IN_COMMENT; + break; + default: + if (state != IN_COMMENT) { + state = IN_NAME; + tokenBuf.append(c); + } + break; + } + if (tokenBuf.length() != 0 && state != IN_NAME) { + tokens.addElement(tokenBuf.toString()); + tokenBuf.setLength(0); + } + } + if (tokenBuf.length() != 0) + tokens.addElement(tokenBuf.toString()); + return tokens.elements(); + } + catch (IOException e) { + return null; + } + } + } + +} + diff --git a/external/relaxngDatatype/org/relaxng/datatype/helpers/ParameterlessDatatypeBuilder.java b/external/relaxngDatatype/org/relaxng/datatype/helpers/ParameterlessDatatypeBuilder.java new file mode 100755 index 000000000..1f571978f --- /dev/null +++ b/external/relaxngDatatype/org/relaxng/datatype/helpers/ParameterlessDatatypeBuilder.java @@ -0,0 +1,42 @@ +package org.relaxng.datatype.helpers; + +import org.relaxng.datatype.*; + +/** + * Dummy implementation of {@link DatatypeBuilder}. + * + * This implementation can be used for Datatypes which have no parameters. + * Any attempt to add parameters will be rejected. + * + * <p> + * Typical usage would be: + * <PRE><XMP> + * class MyDatatypeLibrary implements DatatypeLibrary { + * .... + * DatatypeBuilder createDatatypeBuilder( String typeName ) { + * return new ParameterleessDatatypeBuilder(createDatatype(typeName)); + * } + * .... + * } + * </XMP></PRE> + * + * @author <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> + */ +public final class ParameterlessDatatypeBuilder implements DatatypeBuilder { + + /** This type object is returned for the derive method. */ + private final Datatype baseType; + + public ParameterlessDatatypeBuilder( Datatype baseType ) { + this.baseType = baseType; + } + + public void addParameter( String name, String strValue, ValidationContext context ) + throws DatatypeException { + throw new DatatypeException(); + } + + public Datatype createDatatype() throws DatatypeException { + return baseType; + } +} diff --git a/external/relaxngDatatype/org/relaxng/datatype/helpers/StreamingValidatorImpl.java b/external/relaxngDatatype/org/relaxng/datatype/helpers/StreamingValidatorImpl.java new file mode 100755 index 000000000..636867065 --- /dev/null +++ b/external/relaxngDatatype/org/relaxng/datatype/helpers/StreamingValidatorImpl.java @@ -0,0 +1,55 @@ +package org.relaxng.datatype.helpers; + +import org.relaxng.datatype.*; + +/** + * Dummy implementation of {@link DatatypeStreamingValidator}. + * + * <p> + * This implementation can be used as a quick hack when the performance + * of streaming validation is not important. And this implementation + * also shows you how to implement the DatatypeStreamingValidator interface. + * + * <p> + * Typical usage would be: + * <PRE><XMP> + * class MyDatatype implements Datatype { + * .... + * public DatatypeStreamingValidator createStreamingValidator( ValidationContext context ) { + * return new StreamingValidatorImpl(this,context); + * } + * .... + * } + * </XMP></PRE> + * + * @author <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a> + */ +public final class StreamingValidatorImpl implements DatatypeStreamingValidator { + + /** This buffer accumulates characters. */ + private final StringBuffer buffer = new StringBuffer(); + + /** Datatype obejct that creates this streaming validator. */ + private final Datatype baseType; + + /** The current context. */ + private final ValidationContext context; + + public void addCharacters( char[] buf, int start, int len ) { + // append characters to the current buffer. + buffer.append(buf,start,len); + } + + public boolean isValid() { + return baseType.isValid(buffer.toString(),context); + } + + public void checkValid() throws DatatypeException { + baseType.checkValid(buffer.toString(),context); + } + + public StreamingValidatorImpl( Datatype baseType, ValidationContext context ) { + this.baseType = baseType; + this.context = context; + } +} diff --git a/gnu/CORBA/IOR.java b/gnu/CORBA/IOR.java index 5d6d3152f..917e19832 100644 --- a/gnu/CORBA/IOR.java +++ b/gnu/CORBA/IOR.java @@ -140,6 +140,27 @@ public class IOR b.append(' '); return b.toString(); } + + /** + * Get a better formatted multiline string representation. + */ + public String toStringFormatted() + { + StringBuffer b = new StringBuffer(); + b.append("\n Native set " + name(native_set)); + if (conversion != null && conversion.length > 0) + { + b.append("\n Other supported sets:\n "); + for (int i = 0; i < conversion.length; i++) + { + b.append(name(conversion[i])); + b.append(' '); + } + } + b.append("\n"); + return b.toString(); + } + /** * Write into CDR stream. @@ -590,6 +611,39 @@ public class IOR return b.toString(); } + + /** + * Returns a multiline formatted human readable string representation of + * this IOR object. + */ + public String toStringFormatted() + { + StringBuffer b = new StringBuffer(); + b.append("\nObject Id:\n "); + b.append(Id); + b.append("\nObject is accessible at:\n "); + b.append(Internet); + + if (Big_Endian) + b.append("\n Big endian encoding"); + else + b.append("\n Little endian encoding."); + + b.append("\nObject Key\n "); + + for (int i = 0; i < key.length; i++) + { + b.append(Integer.toHexString(key[i] & 0xFF)); + } + + b.append("\nSupported code sets:"); + b.append("\n Wide:"); + b.append(Internet.CodeSets.wide.toStringFormatted()); + b.append(" Narrow:"); + b.append(Internet.CodeSets.wide.toStringFormatted()); + + return b.toString(); + } /** * Returs a stringified reference. diff --git a/gnu/CORBA/NamingService/NamingMap.java b/gnu/CORBA/NamingService/NamingMap.java index 95deb0096..f4e940ea9 100644 --- a/gnu/CORBA/NamingService/NamingMap.java +++ b/gnu/CORBA/NamingService/NamingMap.java @@ -58,11 +58,11 @@ public class NamingMap /** * The actual map. */ - private final TreeMap map; + protected final TreeMap map; /** * Creates an instance of the naming map, intialising the comparator - * to the {@link cmpNameComparator}. + * to the {@link NameComponentComparator}. */ public NamingMap() { @@ -70,7 +70,7 @@ public class NamingMap } /** - * Put the given CORBA object, specifying the given name as a key. + * Put the given GIOP object, specifying the given name as a key. * If the entry with the given name already exists, or if the given * object is already mapped under another name, the * {@link AlreadyBound} exception will be thrown. @@ -93,8 +93,11 @@ public class NamingMap else { if (containsValue(object)) - throw new AlreadyBound("Tha object has another name"); + throw new AlreadyBound("The object has another name"); } + + // There are no restrictions in binding the object. + rebind(name, object); } /** @@ -141,7 +144,7 @@ public class NamingMap } /** - * Put the given CORBA object, specifying the given name as a key. + * Put the given GIOP object, specifying the given name as a key. * Remove all pre - existing mappings for the given name and object. * * @param name the name. diff --git a/gnu/CORBA/NamingService/NamingServiceTransient.java b/gnu/CORBA/NamingService/NamingServiceTransient.java index bf72637d7..3669879f2 100644 --- a/gnu/CORBA/NamingService/NamingServiceTransient.java +++ b/gnu/CORBA/NamingService/NamingServiceTransient.java @@ -136,7 +136,7 @@ public class NamingServiceTransient System.out.println("GNU Classpath transient naming service " + "started at " + iorr.Internet.host + ":" + iorr.Internet.port + " key 'NameService'.\n\n" - + "Copyright (C) 2005 Free Software Foundation\n" + + "Copyright (C) 2006 Free Software Foundation\n" + "This tool comes with ABSOLUTELY NO WARRANTY. " + "This is free software, and you are\nwelcome to " + "redistribute it under conditions, defined in " diff --git a/gnu/CORBA/NamingService/TransientContext.java b/gnu/CORBA/NamingService/TransientContext.java index 4b7c1938f..c2d8275e0 100644 --- a/gnu/CORBA/NamingService/TransientContext.java +++ b/gnu/CORBA/NamingService/TransientContext.java @@ -59,7 +59,7 @@ import java.util.Map; /** * This class implements the transient naming service, defined by - * {@link NamingContex}. The 'transient' means that the service does + * {@link NamingContext}. The 'transient' means that the service does * not store its state into the persistent memory. If the service is * restarted, the named objects must be re-registered again. * @@ -71,15 +71,40 @@ public class TransientContext extends _NamingContextImplBase implements NamingContext, NamingContextOperations { + /** + * Use serial version UID for interoperability. + */ + private static final long serialVersionUID = 2; + /** * The already named contexts. */ - protected final NamingMap named_contexts = new NamingMap(); + protected final NamingMap named_contexts; /** * The already named objects. */ - protected final NamingMap named_objects = new NamingMap(); + protected final NamingMap named_objects; + + /** + * Create the naming conetxt with default (transient) naming maps. + */ + public TransientContext() + { + this(new NamingMap(), new NamingMap()); + } + + /** + * Create the naming conetxt with the two provided naming maps. + * + * @param context_map the map for contexts + * @param object_map the map for objectss + */ + public TransientContext(NamingMap context_map, NamingMap object_map) + { + named_contexts = context_map; + named_objects = object_map; + } /** * Gives the object a name, valid in this context. @@ -376,7 +401,7 @@ public class TransientContext /** * Create a binding. * - * @param entry the entry, defining the bound object. + * @param an_entry the entry, defining the bound object. * @param type the binding type. * @return the created binding. */ @@ -396,7 +421,7 @@ public class TransientContext * name, and pass the remainder (without the first node) * of the name for that context to resolve. * - * @param name the name to resolve. + * @param a_name the name to resolve. * * @return the resolved context */ diff --git a/gnu/classpath/ServiceFactory.java b/gnu/classpath/ServiceFactory.java index 711a9042c..122a79c96 100644 --- a/gnu/classpath/ServiceFactory.java +++ b/gnu/classpath/ServiceFactory.java @@ -282,7 +282,7 @@ public final class ServiceFactory * An iterator over service providers that are listed in service * provider configuration files, which get passed as an Enumeration * of URLs. This is a helper class for {@link - * ServiceFactory#lookupProviders}. + * ServiceFactory#lookupProviders(Class, ClassLoader)}. * * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a> */ @@ -314,7 +314,8 @@ public final class ServiceFactory * The security context used when loading and initializing service * providers. We want to load and initialize all plug-in service * providers under the same security context, namely the one that - * was active when {@link #lookupProviders} has been called. + * was active when {@link #lookupProviders(Class, ClassLoader)} has + * been called. */ private final AccessControlContext securityContext; @@ -527,7 +528,7 @@ public final class ServiceFactory * framework. This call returns very quickly if no log message will * be produced, so there is not much overhead in the standard case. * - * @param the severity of the message, for instance {@link + * @param level the severity of the message, for instance {@link * Level#WARNING}. * * @param msg the log message, for instance <code>“Could not diff --git a/gnu/classpath/ServiceProviderLoadingAction.java b/gnu/classpath/ServiceProviderLoadingAction.java index b5e59cb4b..9f9dc51cb 100644 --- a/gnu/classpath/ServiceProviderLoadingAction.java +++ b/gnu/classpath/ServiceProviderLoadingAction.java @@ -48,9 +48,9 @@ import java.security.PrivilegedExceptionAction; * <code>PriviledgedAction</code> in order to restrict the loaded * service providers to the {@link java.security.AccessControlContext} * that was active when {@link - * gnu.classpath.ServiceFactory#lookupProviders} was called, even - * though the actual loading is delayed to the time when the provider - * is actually needed. + * gnu.classpath.ServiceFactory#lookupProviders(Class, ClassLoader)} was + * called, even though the actual loading is delayed to the time when the + * provider is actually needed. * * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a> */ diff --git a/gnu/classpath/debug/Component.java b/gnu/classpath/debug/Component.java index 242419ce4..af030ed27 100644 --- a/gnu/classpath/debug/Component.java +++ b/gnu/classpath/debug/Component.java @@ -89,9 +89,9 @@ public final class Component extends Level public static final Component SSL_HANDSHAKE = new Component ("SSL HANDSHAKE", 0); /** - * Traces the application messages during SSL communications. + * Traces record layer messages during SSL communications. */ - public static final Component SSL_APPLICATION = new Component ("SSL APPLICATION", 1); + public static final Component SSL_RECORD_LAYER = new Component ("SSL RECORD LAYER", 1); /** * Trace details about the SSL key exchange. diff --git a/gnu/classpath/jdwp/Jdwp.java b/gnu/classpath/jdwp/Jdwp.java index 43a37de24..f73e09610 100644 --- a/gnu/classpath/jdwp/Jdwp.java +++ b/gnu/classpath/jdwp/Jdwp.java @@ -1,5 +1,5 @@ /* Jdwp.java -- Virtual machine to JDWP back-end programming interface - Copyright (C) 2005 Free Software Foundation + Copyright (C) 2005, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -159,7 +159,7 @@ public class Jdwp { AccessController.doPrivileged (_packetProcessor); } - }); + }, "packet processor"); _ppThread.start (); } @@ -258,7 +258,7 @@ public class Jdwp break; case EventRequest.SUSPEND_THREAD: - VMVirtualMachine.suspendThread (this); + VMVirtualMachine.suspendThread (Thread.currentThread ()); break; case EventRequest.SUSPEND_ALL: diff --git a/gnu/classpath/jdwp/event/EventRequest.java b/gnu/classpath/jdwp/event/EventRequest.java index eadad2840..6c2acf3c4 100644 --- a/gnu/classpath/jdwp/event/EventRequest.java +++ b/gnu/classpath/jdwp/event/EventRequest.java @@ -1,5 +1,5 @@ /* EventRequest.java -- an event request from the debugger - Copyright (C) 2005 Free Software Foundation + Copyright (C) 2005, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -44,8 +44,9 @@ import gnu.classpath.jdwp.event.filters.*; import gnu.classpath.jdwp.exception.JdwpIllegalArgumentException; import gnu.classpath.jdwp.id.*; +import java.util.Collection; +import java.util.Iterator; import java.util.LinkedList; -import java.util.ListIterator; /** * A class which represents a request by the debugger for an event @@ -319,6 +320,14 @@ public class EventRequest _filters.add (filter); } + /** + * Returns the filters attached to this request + */ + public Collection getFilters () + { + return _filters; + } + /** * Returns the suspend policy for this request */ @@ -363,7 +372,7 @@ public class EventRequest // Loop through filters; all must match // Note that we must allow EVERY filter to evaluate. This way // things like CountFilter will work. - ListIterator iter = _filters.listIterator (); + Iterator iter = _filters.iterator (); while (iter.hasNext ()) { IEventFilter filter = (IEventFilter) iter.next (); diff --git a/gnu/classpath/jdwp/id/JdwpId.java b/gnu/classpath/jdwp/id/JdwpId.java index 7f610e353..472650de8 100644 --- a/gnu/classpath/jdwp/id/JdwpId.java +++ b/gnu/classpath/jdwp/id/JdwpId.java @@ -1,5 +1,5 @@ /* JdwpId.java -- base class for all object ID types - Copyright (C) 2005 Free Software Foundation + Copyright (C) 2005, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -50,6 +50,11 @@ import java.lang.ref.SoftReference; */ public abstract class JdwpId { + /** + * The size of an ID. The default is 8 bytes (a long). + */ + public static final int SIZE = 8; + /** * ID assigned to this object */ @@ -121,11 +126,6 @@ public abstract class JdwpId return (id.getId () == getId ()); } - /** - * Returns size of this type (used by IDSizes) - */ - public abstract int size (); - /** * Writes the contents of this type to the <code>DataOutputStream</code> * @param outStream the <code>DataOutputStream</code> to use diff --git a/gnu/classpath/jdwp/id/ObjectId.java b/gnu/classpath/jdwp/id/ObjectId.java index 3e2abd4f6..a4a37fd13 100644 --- a/gnu/classpath/jdwp/id/ObjectId.java +++ b/gnu/classpath/jdwp/id/ObjectId.java @@ -1,5 +1,5 @@ /* ObjectId.java -- object IDs - Copyright (C) 2005 Free Software Foundation + Copyright (C) 2005, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -82,14 +82,6 @@ public class ObjectId super (tag); } - /** - * Returns the size of this id type - */ - public int size () - { - return 8; - } - /** * Returns the object referred to by this ID * diff --git a/gnu/classpath/jdwp/id/ReferenceTypeId.java b/gnu/classpath/jdwp/id/ReferenceTypeId.java index e7a5d2c3d..b82acf34a 100644 --- a/gnu/classpath/jdwp/id/ReferenceTypeId.java +++ b/gnu/classpath/jdwp/id/ReferenceTypeId.java @@ -1,5 +1,5 @@ /* ReferenceTypeId.java -- a base class for all reference type IDs - Copyright (C) 2005 Free Software Foundation + Copyright (C) 2005, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -61,14 +61,6 @@ public class ReferenceTypeId super (tag); } - /** - * Returns the size of this ID type - */ - public int size () - { - return 8; - } - /** * Gets the class associated with this ID * diff --git a/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java b/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java index 6bdb23681..a7edb287a 100644 --- a/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java +++ b/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java @@ -1,6 +1,6 @@ /* VirtualMachineCommandSet.java -- class to implement the VirtualMachine Command Set - Copyright (C) 2005 Free Software Foundation + Copyright (C) 2005, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -40,6 +40,7 @@ exception statement from your version. */ package gnu.classpath.jdwp.processor; import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMFrame; import gnu.classpath.jdwp.VMVirtualMachine; import gnu.classpath.jdwp.exception.JdwpException; import gnu.classpath.jdwp.exception.JdwpInternalErrorException; @@ -298,12 +299,11 @@ public class VirtualMachineCommandSet private void executeIDsizes(ByteBuffer bb, DataOutputStream os) throws JdwpException, IOException { - ObjectId oid = new ObjectId(); - os.writeInt(oid.size()); // fieldId - os.writeInt(oid.size()); // methodId - os.writeInt(oid.size()); // objectId - os.writeInt(new ReferenceTypeId((byte) 0x00).size()); // referenceTypeId - os.writeInt(oid.size()); // frameId + os.writeInt(ObjectId.SIZE); // fieldId FIXME + os.writeInt(ObjectId.SIZE); // methodId FIXME + os.writeInt(ObjectId.SIZE); // objectId + os.writeInt(ReferenceTypeId.SIZE); // referenceTypeId + os.writeInt(VMFrame.SIZE); // frameId } private void executeSuspend(ByteBuffer bb, DataOutputStream os) diff --git a/gnu/java/awt/peer/GLightweightPeer.java b/gnu/java/awt/peer/GLightweightPeer.java index 5252e80f1..daaa143d0 100644 --- a/gnu/java/awt/peer/GLightweightPeer.java +++ b/gnu/java/awt/peer/GLightweightPeer.java @@ -227,7 +227,12 @@ public class GLightweightPeer public void print(Graphics graphics) {} - public void repaint(long tm, int x, int y, int width, int height) {} + public void repaint(long tm, int x, int y, int width, int height) + { + Component p = comp.getParent(); + if (p != null) + p.repaint(tm, x + comp.getX(), y + comp.getY(), width, height); + } public void requestFocus() {} diff --git a/gnu/java/awt/peer/gtk/GtkButtonPeer.java b/gnu/java/awt/peer/gtk/GtkButtonPeer.java index 054ead6d6..63d9cd487 100644 --- a/gnu/java/awt/peer/gtk/GtkButtonPeer.java +++ b/gnu/java/awt/peer/gtk/GtkButtonPeer.java @@ -1,5 +1,5 @@ /* GtkButtonPeer.java -- Implements ButtonPeer with GTK - Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -57,7 +57,10 @@ public class GtkButtonPeer extends GtkComponentPeer public native void connectSignals (); - native void gtkWidgetModifyFont (String name, int style, int size); + /** + * Overridden to set Font of Label inside Button inside EventBox. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); native void gtkSetLabel (String label); native void gtkWidgetSetForeground (int red, int green, int blue); native void gtkWidgetSetBackground (int red, int green, int blue); diff --git a/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java b/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java index 01a6e3102..be9247e8d 100644 --- a/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java +++ b/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java @@ -1,5 +1,5 @@ /* GtkCheckboxMenuItemPeer.java -- Implements CheckboxMenuItemPeer with GTK+ - Copyright (C) 1999, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -46,7 +46,7 @@ import java.awt.peer.CheckboxMenuItemPeer; public class GtkCheckboxMenuItemPeer extends GtkMenuItemPeer implements CheckboxMenuItemPeer { - native void create (String label); + protected native void create (String label); public GtkCheckboxMenuItemPeer (CheckboxMenuItem menu) { @@ -56,6 +56,11 @@ public class GtkCheckboxMenuItemPeer extends GtkMenuItemPeer public native void setState(boolean t); + /** + * Called from the signal handler of the gtk widget. Posts a + * ItemEvent to indicate a state changed, then calls super to post + * an ActionEvent. + */ protected void postMenuActionEvent () { CheckboxMenuItem item = (CheckboxMenuItem)awtWidget; diff --git a/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java b/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java index 3e05cf8ab..094aa3c03 100644 --- a/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java +++ b/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java @@ -1,5 +1,5 @@ /* GtkCheckboxPeer.java -- Implements CheckboxPeer with GTK - Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2002, 2003, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,8 @@ import java.awt.Checkbox; import java.awt.CheckboxGroup; import java.awt.peer.CheckboxPeer; +import java.awt.event.ItemEvent; + public class GtkCheckboxPeer extends GtkComponentPeer implements CheckboxPeer { @@ -49,12 +51,15 @@ public class GtkCheckboxPeer extends GtkComponentPeer public GtkCheckboxGroupPeer old_group; // The current state of the GTK checkbox. private boolean currentState; - private boolean changing = false; public native void create (GtkCheckboxGroupPeer group); public native void nativeSetCheckboxGroup (GtkCheckboxGroupPeer group); public native void connectSignals (); - native void gtkWidgetModifyFont (String name, int style, int size); + + /** + * Overridden to set Font of label inside button. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); native void gtkButtonSetLabel (String label); native void gtkToggleButtonSetActive (boolean is_active); @@ -71,23 +76,24 @@ public class GtkCheckboxPeer extends GtkComponentPeer CheckboxGroup g = checkbox.getCheckboxGroup (); old_group = GtkCheckboxGroupPeer.getCheckboxGroupPeer (g); create (old_group); - gtkToggleButtonSetActive (checkbox.getState ()); + currentState = checkbox.getState(); + gtkToggleButtonSetActive(currentState); gtkButtonSetLabel (checkbox.getLabel ()); } - public void setState (boolean state) + /** + * Sets native GtkCheckButton is state is different from current + * state. Will set currentState to state to prevent posting an + * event since events should only be posted for user initiated + * clicks on the GtkCheckButton. + */ + synchronized public void setState (boolean state) { - // prevent item_toggled_cb -> postItemEvent -> - // awtComponent.setState -> this.setState -> - // gtkToggleButtonSetActive self-deadlock on the GDK lock. - if (changing && Thread.currentThread() == GtkToolkit.mainThread) + if (currentState != state) { - changing = false; - return; + currentState = state; + gtkToggleButtonSetActive(state); } - - if (currentState != state) - gtkToggleButtonSetActive (state); } public void setLabel (String label) @@ -111,22 +117,15 @@ public class GtkCheckboxPeer extends GtkComponentPeer // Override the superclass postItemEvent so that the peer doesn't // need information that we have. // called back by native side: item_toggled_cb - public void postItemEvent (Object item, int stateChange) + synchronized public void postItemEvent(Object item, boolean state) { - Checkbox currentCheckBox = ((Checkbox)awtComponent); - // A firing of the event is only desired if the state has changed due to a - // button press. The currentCheckBox's state must be different from the - // one that the stateChange is changing to. - // stateChange = 1 if it goes from false -> true - // stateChange = 2 if it goes from true -> false - if (( !currentCheckBox.getState() && stateChange == 1) - || (currentCheckBox.getState() && stateChange == 2)) - { - super.postItemEvent (awtComponent, stateChange); - currentState = !currentCheckBox.getState(); - changing = true; - currentCheckBox.setState(currentState); - } + // Only fire event is state actually changed. + if (currentState != state) + { + currentState = state; + super.postItemEvent(awtComponent, + state ? ItemEvent.SELECTED : ItemEvent.DESELECTED); + } } public void dispose () diff --git a/gnu/java/awt/peer/gtk/GtkComponentPeer.java b/gnu/java/awt/peer/gtk/GtkComponentPeer.java index fe0dae70d..b48479bb2 100644 --- a/gnu/java/awt/peer/gtk/GtkComponentPeer.java +++ b/gnu/java/awt/peer/gtk/GtkComponentPeer.java @@ -1,5 +1,6 @@ /* GtkComponentPeer.java -- Implements ComponentPeer with GTK - Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2002, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -46,10 +47,10 @@ import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Insets; @@ -87,8 +88,6 @@ public class GtkComponentPeer extends GtkGenericPeer boolean isInRepaint; - static final Timer repaintTimer = new Timer (true); - /* this isEnabled differs from Component.isEnabled, in that it knows if a parent is disabled. In that case Component.isEnabled may return true, but our isEnabled will always return false */ @@ -303,29 +302,29 @@ public class GtkComponentPeer extends GtkGenericPeer { case PaintEvent.PAINT: case PaintEvent.UPDATE: - { - try - { - Graphics g = getGraphics (); - - // Some peers like GtkFileDialogPeer are repainted by Gtk itself - if (g == null) - break; - - g.setClip (((PaintEvent) event).getUpdateRect()); - - if (id == PaintEvent.PAINT) - awtComponent.paint (g); - else - awtComponent.update (g); - - g.dispose (); - } - catch (InternalError e) - { - System.err.println (e); - } - } + { + try + { + Graphics g = getGraphics(); + + if (!awtComponent.isShowing() || awtComponent.getWidth() < 1 + || awtComponent.getHeight() < 1 || g == null) + break; + + g.setClip(((PaintEvent) event).getUpdateRect()); + + if (id == PaintEvent.PAINT) + awtComponent.paint(g); + else + awtComponent.update(g); + + g.dispose(); + } + catch (InternalError e) + { + System.err.println(e); + } + } break; case KeyEvent.KEY_PRESSED: ke = (KeyEvent) event; @@ -383,19 +382,30 @@ public class GtkComponentPeer extends GtkGenericPeer if (x == 0 && y == 0 && width == 0 && height == 0) return; - repaintTimer.schedule(new RepaintTimerTask(x, y, width, height), tm); + if (tm <= 0) + q().postEvent(new PaintEvent(awtComponent, PaintEvent.UPDATE, + new Rectangle(x, y, width, height))); + else + RepaintTimerTask.schedule(tm, x, y, width, height, awtComponent); } - private class RepaintTimerTask extends TimerTask + /** + * Used for scheduling delayed paint updates on the event queue. + */ + private static class RepaintTimerTask extends TimerTask { + private static final Timer repaintTimer = new Timer(true); + private int x, y, width, height; + private Component awtComponent; - RepaintTimerTask(int x, int y, int width, int height) + RepaintTimerTask(Component c, int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; + this.awtComponent = c; } public void run() @@ -403,6 +413,12 @@ public class GtkComponentPeer extends GtkGenericPeer q().postEvent (new PaintEvent (awtComponent, PaintEvent.UPDATE, new Rectangle (x, y, width, height))); } + + static void schedule(long tm, int x, int y, int width, int height, + Component c) + { + repaintTimer.schedule(new RepaintTimerTask(c, x, y, width, height), tm); + } } public void requestFocus () @@ -429,8 +445,7 @@ public class GtkComponentPeer extends GtkGenericPeer int new_y = y; Component parent = awtComponent.getParent (); - Component next_parent; - + // Heavyweight components that are children of one or more // lightweight containers have to be handled specially. Because // calls to GLightweightPeer.setBounds do nothing, GTK has no @@ -441,33 +456,19 @@ public class GtkComponentPeer extends GtkGenericPeer // so we need to continue adding offsets until we reach a // container whose position GTK knows -- that is, the first // non-lightweight. - boolean lightweightChild = false; - Insets i; - while (parent.isLightweight ()) + Insets i; + while (parent.isLightweight()) { - lightweightChild = true; - - next_parent = parent.getParent (); - - i = ((Container) parent).getInsets (); - - if (next_parent instanceof Window) - { - new_x += i.left; - new_y += i.top; - } - else - { - new_x += parent.getX () + i.left; - new_y += parent.getY () + i.top; - } - - parent = next_parent; + i = ((Container) parent).getInsets(); + + new_x += parent.getX() + i.left; + new_y += parent.getY() + i.top; + + parent = parent.getParent(); } - // We only need to convert from Java to GTK coordinates if we're // placing a heavyweight component in a Window. - if (parent instanceof Window && !lightweightChild) + if (parent instanceof Window) { GtkWindowPeer peer = (GtkWindowPeer) parent.getPeer (); // important: we want the window peer's insets here, not the @@ -479,9 +480,10 @@ public class GtkComponentPeer extends GtkGenericPeer int menuBarHeight = 0; if (peer instanceof GtkFramePeer) menuBarHeight = ((GtkFramePeer) peer).getMenuBarHeight (); - - new_x = x - insets.left; - new_y = y - insets.top + menuBarHeight; + + new_x -= insets.left; + new_y -= insets.top; + new_y += menuBarHeight; } setNativeBounds (new_x, new_y, width, height); @@ -571,6 +573,8 @@ public class GtkComponentPeer extends GtkGenericPeer KeyEvent keyEvent = new KeyEvent (awtComponent, id, when, mods, keyCode, keyChar, keyLocation); + EventQueue q = q(); + // Also post a KEY_TYPED event if keyEvent is a key press that // doesn't represent an action or modifier key. if (keyEvent.getID () == KeyEvent.KEY_PRESSED @@ -579,15 +583,17 @@ public class GtkComponentPeer extends GtkGenericPeer && keyCode != KeyEvent.VK_CONTROL && keyCode != KeyEvent.VK_ALT)) { - synchronized (q) - { - q().postEvent (keyEvent); - q().postEvent (new KeyEvent (awtComponent, KeyEvent.KEY_TYPED, when, mods, - KeyEvent.VK_UNDEFINED, keyChar, keyLocation)); + synchronized(q) + { + q.postEvent(keyEvent); + keyEvent = new KeyEvent(awtComponent, KeyEvent.KEY_TYPED, when, + mods, KeyEvent.VK_UNDEFINED, keyChar, + keyLocation); + q.postEvent(keyEvent); } } else - q().postEvent (keyEvent); + q.postEvent(keyEvent); } protected void postFocusEvent (int id, boolean temporary) diff --git a/gnu/java/awt/peer/gtk/GtkContainerPeer.java b/gnu/java/awt/peer/gtk/GtkContainerPeer.java index b035a9814..37ed36131 100644 --- a/gnu/java/awt/peer/gtk/GtkContainerPeer.java +++ b/gnu/java/awt/peer/gtk/GtkContainerPeer.java @@ -1,5 +1,5 @@ /* GtkContainerPeer.java -- Implements ContainerPeer with GTK - Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -67,10 +67,13 @@ public class GtkContainerPeer extends GtkComponentPeer { Component parent = awtComponent.getParent (); - // Only set our parent on the GTK side if our parent on the AWT - // side is not showing. Otherwise the gtk peer will be shown - // before we've had a chance to position and size it properly. - if (parent != null && parent.isShowing ()) + // We only set our parent on the GTK side if our parent on the AWT + // side is not showing in the constuctor. Otherwise the gtk peer will + // be shown before we've had a chance to position and size it properly. + // So we set it here at the end of validation. + if ((parent != null && parent.isShowing()) + || (awtComponent instanceof Window + && ((Window) awtComponent).isShowing())) { Component[] components = ((Container) awtComponent).getComponents (); int ncomponents = components.length; diff --git a/gnu/java/awt/peer/gtk/GtkFramePeer.java b/gnu/java/awt/peer/gtk/GtkFramePeer.java index 99cca0cff..f59e781c2 100644 --- a/gnu/java/awt/peer/gtk/GtkFramePeer.java +++ b/gnu/java/awt/peer/gtk/GtkFramePeer.java @@ -43,10 +43,7 @@ import java.awt.Graphics; import java.awt.Image; import java.awt.MenuBar; import java.awt.Rectangle; -import java.awt.Window; -import java.awt.event.ComponentEvent; import java.awt.event.PaintEvent; -import java.awt.image.ColorModel; import java.awt.peer.FramePeer; import java.awt.peer.MenuBarPeer; @@ -77,7 +74,10 @@ public class GtkFramePeer extends GtkWindowPeer removeMenuBarPeer (); insets.top -= menuBarHeight; menuBarHeight = 0; - awtComponent.validate (); + // if component has already been validated, we need to revalidate. + // otherwise, it will be validated when it is shown. + if (awtComponent.isValid()) + awtComponent.validate (); gtkFixedSetVisible (true); } else if (bar != null && menuBar == null) @@ -92,7 +92,10 @@ public class GtkFramePeer extends GtkWindowPeer setMenuBarWidth (menuBar, menuBarWidth); menuBarHeight = getMenuBarHeight (); insets.top += menuBarHeight; - awtComponent.validate (); + // if component has already been validated, we need to revalidate. + // otherwise, it will be validated when it is shown. + if (awtComponent.isValid()) + awtComponent.validate (); gtkFixedSetVisible (true); } else if (bar != null && menuBar != null) diff --git a/gnu/java/awt/peer/gtk/GtkGenericPeer.java b/gnu/java/awt/peer/gtk/GtkGenericPeer.java index 705eed235..468c46dc4 100644 --- a/gnu/java/awt/peer/gtk/GtkGenericPeer.java +++ b/gnu/java/awt/peer/gtk/GtkGenericPeer.java @@ -1,5 +1,5 @@ /* GtkGenericPeer.java - Has a hashcode. Yuck. - Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2002, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,23 +39,28 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; import java.awt.EventQueue; +import java.awt.Font; import java.awt.Toolkit; import java.awt.event.ActionEvent; public class GtkGenericPeer { + // Used by Native State Association (NSA) functions to map + // gtk_widget to peer object. final int native_state = getUniqueInteger (); // Next native state value we will assign. private static int next_native_state = 0; // The widget or other java-side object we wrap. - protected Object awtWidget; - - // Global event queue. - protected static EventQueue q = null; - - // Dispose of our native state. + protected final Object awtWidget; + + /** + * Dispose of our native state. Calls gtk_widget_destroy on the + * native widget and removes the awtWidget from the native state + * tables. Should be overridden by subclasses if this is not (all) + * that needs to be done. + */ public native void dispose (); static EventQueue q () @@ -68,12 +73,6 @@ public class GtkGenericPeer this.awtWidget = awtWidget; } - public static void enableQueue (EventQueue sq) - { - if (q == null) - q = sq; - } - protected void postActionEvent (String command, int mods) { q().postEvent (new ActionEvent (awtWidget, ActionEvent.ACTION_PERFORMED, @@ -88,8 +87,20 @@ public class GtkGenericPeer // Let's assume this will never wrap. return next_native_state++; } + + /** + * Helper method to set Font for Gtk Widget. + */ + protected void gtkWidgetModifyFont(Font f) + { + gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize()); + } - native void gtkWidgetModifyFont (String name, int style, int size); + /** + * Sets font for this Gtk Widget. Should be overridden by peers which + * are composed of different widgets or are contained in bins. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); static void printCurrentThread () { diff --git a/gnu/java/awt/peer/gtk/GtkImage.java b/gnu/java/awt/peer/gtk/GtkImage.java index 82a346304..b48a2049e 100644 --- a/gnu/java/awt/peer/gtk/GtkImage.java +++ b/gnu/java/awt/peer/gtk/GtkImage.java @@ -1,5 +1,5 @@ /* GtkImage.java - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -329,6 +329,24 @@ public class GtkImage extends Image props = new Hashtable(); } + // The singleton GtkImage that is returned on errors by GtkToolkit. + private static GtkImage errorImage; + + /** + * Returns an empty GtkImage with the errorLoading flag set. + * Called from GtkToolKit when some error occured, but an image needs + * to be returned anyway. + */ + static synchronized GtkImage getErrorImage() + { + if (errorImage == null) + { + errorImage = new GtkImage(); + errorImage.errorLoading = true; + } + return errorImage; + } + /** * Native helper function for constructor that takes a pixbuf Pointer. */ diff --git a/gnu/java/awt/peer/gtk/GtkLabelPeer.java b/gnu/java/awt/peer/gtk/GtkLabelPeer.java index 3d099e9ca..bbf4230b3 100644 --- a/gnu/java/awt/peer/gtk/GtkLabelPeer.java +++ b/gnu/java/awt/peer/gtk/GtkLabelPeer.java @@ -1,5 +1,5 @@ /* GtkLabelPeer.java -- Implements LabelPeer with GTK - Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -48,7 +48,12 @@ public class GtkLabelPeer extends GtkComponentPeer implements LabelPeer { native void create (String text, float alignment); - native void gtkWidgetModifyFont (String name, int style, int size); + + /** + * Overridden to set the Font of the label inside the gtk_event_box. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); + native void nativeSetAlignment (float alignment); public native void setText(String text); diff --git a/gnu/java/awt/peer/gtk/GtkListPeer.java b/gnu/java/awt/peer/gtk/GtkListPeer.java index ff12fe34b..285f79416 100644 --- a/gnu/java/awt/peer/gtk/GtkListPeer.java +++ b/gnu/java/awt/peer/gtk/GtkListPeer.java @@ -1,5 +1,5 @@ /* GtkListPeer.java -- Implements ListPeer with GTK - Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -59,7 +59,12 @@ public class GtkListPeer extends GtkComponentPeer native void create (int rows); native void connectSignals (); - native void gtkWidgetModifyFont (String name, int style, int size); + + /** + * Overridden to set the Font of the text insode the gtk_scrolled_window. + */ + protected native void gtkWidgetModifyFont (String name, int style, int size); + native void gtkWidgetRequestFocus (); native void getSize (int rows, int visibleRows, int dims[]); diff --git a/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java b/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java index a1a1cbd6d..d203b437f 100644 --- a/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java +++ b/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java @@ -1,5 +1,5 @@ /* GtkMenuBarPeer.java -- Implements MenuBarPeer with GTK+ - Copyright (C) 1999, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -48,38 +48,69 @@ import java.awt.peer.MenuPeer; public class GtkMenuBarPeer extends GtkMenuComponentPeer implements MenuBarPeer { - - native void create (); - native void addMenu (MenuPeer menu); - - public GtkMenuBarPeer (MenuBar target) + /** Whether we already have an help menu set on this peer. */ + private boolean hasHelpMenu; + + /** + * Creates the gtk+ widget for this peer and puts it in the nsa + * table. Called from the (super class) constructor. + */ + protected native void create(); + + /** + * Adds a new GtkMenuPeer to the end of the GtkMenuBarPeer. + */ + private native void addMenu(GtkMenuPeer menu); + + /** + * Creates a new GtkMenuBarPeer associated with the given MenuBar. + */ + public GtkMenuBarPeer(MenuBar menubar) { - super (target); + super(menubar); } - void setFont () - { - MenuComponent mc = (MenuComponent) awtWidget; - Font f = mc.getFont (); - - if (f == null) - mc.setFont (new Font ("Dialog", Font.PLAIN, 12)); - } - - // FIXME: remove this method or replace it with one that does - // something useful. - /* In Gnome, help menus are no longer right flushed. */ - native void nativeSetHelpMenu(MenuPeer menuPeer); - + /** + * Adds a help menu to this MenuBar. Gnome styleguides say the help + * menu is just the last item in the menubar (they are NOT right + * justified). + */ public void addHelpMenu (Menu menu) { - // nativeSetHelpMenu((MenuPeer) menu.getPeer()); + if (hasHelpMenu) + { + // Remove the (help) menu, which is after all the other items. + delMenu(((MenuBar) awtWidget).getMenuCount()); + hasHelpMenu = false; + } + + if (menu != null) + { + addMenu(menu); + hasHelpMenu = true; + } } + /** + * Deletes the menu at (zero-based) index from this GtkMenuBar. + */ public native void delMenu(int index); - public void addMenu (Menu m) + /** + * Adds the GtkMenuPeer associated with the Menu to this + * GtkMenuBarPeer. Makes sure that any help menus keep the last menu + * on the bar. + */ + public void addMenu(Menu m) { - // FIXME: implement + // Make sure the help menu is the last one. + if (hasHelpMenu) + { + addHelpMenu(null); + addMenu((GtkMenuPeer) m.getPeer()); + addHelpMenu(((MenuBar) awtWidget).getHelpMenu()); + } + else + addMenu((GtkMenuPeer) m.getPeer()); } } diff --git a/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java b/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java index 4c6335933..55b95a18d 100644 --- a/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java +++ b/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java @@ -1,5 +1,5 @@ /* GtkMenuComponentPeer.java -- Implements MenuComponentPeer with GTK+ - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,31 +39,66 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; import java.awt.Font; +import java.awt.MenuComponent; +import java.awt.MenuContainer; import java.awt.peer.MenuComponentPeer; -public class GtkMenuComponentPeer extends GtkGenericPeer +public abstract class GtkMenuComponentPeer extends GtkGenericPeer implements MenuComponentPeer { - void create () - { - throw new RuntimeException (); - } + /** + * Creates the associated gtk+ widget and stores it in the nsa table + * for this peer. Called by the constructor. + */ + protected abstract void create (); - void setFont () + /** + * Sets font based on MenuComponent font, or containing menu(bar) + * parent font. + */ + private void setFont() { + MenuComponent mc = ((MenuComponent) awtWidget); + Font f = mc.getFont(); + + if (f == null) + { + MenuContainer parent = mc.getParent (); + // Submenus inherit the font of their containing Menu(Bar). + if (parent instanceof MenuComponent) + f = parent.getFont (); + } + + setFont(f); } - public GtkMenuComponentPeer (Object awtWidget) + /** + * Will call the abstract <code>create()</code> that needs to be + * overridden by subclasses, to create the MenuComponent. It will + * then correctly setup the font for the component based on the + * component and/or its containing parent component. + */ + public GtkMenuComponentPeer(MenuComponent component) { - super (awtWidget); - create (); - setFont (); + super(component); + create(); + setFont(); } + /** + * Removes the awtWidget components from the native state tables. + * Subclasses should call <code>super.dispose()</code> if they don't + * remove these themselves. + */ public native void dispose(); + /** + * Sets the font for this particular MenuComponent only (not any + * containing items, if any). + */ public void setFont(Font font) { - // FIXME: implement + if (font != null) + gtkWidgetModifyFont(font); } } diff --git a/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java b/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java index 5728f262b..251bab233 100644 --- a/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java +++ b/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java @@ -1,5 +1,5 @@ /* GtkMenuItemPeer.java -- Implements MenuItemPeer with GTK+ - Copyright (C) 1999, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -49,70 +49,71 @@ import java.awt.peer.MenuPeer; public class GtkMenuItemPeer extends GtkMenuComponentPeer implements MenuItemPeer { - native void create (String label); - native void connectSignals (); - native void gtkWidgetModifyFont (String name, int style, int size); - - void create () + /** + * Creates the associated gtk+ widget and stores it in the nsa table + * for this peer. Called by the create() method with the label name + * of the associated MenuItem. Needs to be overridden my subclasses + * that want to create a different gtk+ widget. + */ + protected native void create (String label); + + /** + * Called from constructor to enable signals from an item. If a + * subclass needs different (or no) signals connected this method + * should be overridden. + */ + protected native void connectSignals (); + + /** + * Overridden to set font on menu item label. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); + + /** + * Creates the associated gtk+ widget and stores it in the nsa table + * for this peer. Called by the (super class) constructor. + * Overridden to get the label if the assiociated MenuItem and to + * call create(String). + */ + protected void create() { create (((MenuItem) awtWidget).getLabel()); } - public GtkMenuItemPeer (MenuItem item) - { - super (item); - setEnabled (item.isEnabled ()); - setParent (item); - - if (item.getParent() instanceof Menu && ! (item instanceof Menu)) - connectSignals(); - } - - void setFont () + /** + * Creates a new GtkMenuItemPeer associated with the given MenuItem. + * It will call create(), setFont(), setEnabled() and + * connectSignals() in that order. + */ + public GtkMenuItemPeer(MenuItem item) { - MenuComponent mc = ((MenuComponent) awtWidget); - Font f = mc.getFont (); - - if (f == null) - { - MenuComponent parent = (MenuComponent) mc.getParent (); - Font pf = parent.getFont (); - gtkWidgetModifyFont (pf.getName (), pf.getStyle (), pf.getSize ()); - } - else - gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize()); + super(item); + setEnabled (item.isEnabled()); + connectSignals(); } - void setParent (MenuItem item) + /** + * Calls setEnabled(false). + */ + public void disable() { - // add ourself differently, based on what type of parent we have - // yes, the typecasting here is nasty. - Object parent = item.getParent (); - if (parent instanceof MenuBar) - { - ((GtkMenuBarPeer)((MenuBar)parent).getPeer ()).addMenu ((MenuPeer) this); - } - else // parent instanceof Menu - { - ((GtkMenuPeer)((Menu)parent).getPeer ()).addItem (this, - item.getShortcut ()); - } + setEnabled(false); } - public void disable () + /** + * Calls setEnabled(true). + */ + public void enable() { - setEnabled (false); - } - - public void enable () - { - setEnabled (true); + setEnabled(true); } public native void setEnabled(boolean b); - public native void setLabel(String label); + /** + * Callback setup through connectSignals(). + */ protected void postMenuActionEvent () { postActionEvent (((MenuItem)awtWidget).getActionCommand (), 0); diff --git a/gnu/java/awt/peer/gtk/GtkMenuPeer.java b/gnu/java/awt/peer/gtk/GtkMenuPeer.java index fabcf1f09..1d581c1a1 100644 --- a/gnu/java/awt/peer/gtk/GtkMenuPeer.java +++ b/gnu/java/awt/peer/gtk/GtkMenuPeer.java @@ -1,5 +1,5 @@ /* GtkMenuPeer.java -- Implements MenuPeer with GTK+ - Copyright (C) 1999, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -49,10 +49,28 @@ import java.awt.peer.MenuPeer; public class GtkMenuPeer extends GtkMenuItemPeer implements MenuPeer { - native void create (String label); - native void addItem (MenuItemPeer item, int key, boolean shiftModifier); + /** + * Creates the associated gtk+ widget and stores it in the nsa table + * for this peer. Called by the create() method with the label name + * of the associated MenuItem. Overridden to greate a Menu widget. + */ + protected native void create (String label); + + private native void addItem(MenuItemPeer item, int key, + boolean shiftModifier); + + /** XXX - Document this and the override in GtkPopupMenuPeer. */ native void setupAccelGroup (GtkGenericPeer container); - native void addTearOff (); + + private native void addTearOff (); + + /** + * Overridden to not connect any signals. + */ + protected void connectSignals() + { + // No signals to connect. + } public GtkMenuPeer (Menu menu) { @@ -63,11 +81,11 @@ public class GtkMenuPeer extends GtkMenuItemPeer MenuContainer parent = menu.getParent (); if (parent instanceof Menu) - setupAccelGroup ((GtkGenericPeer)((Menu)parent).getPeer ()); + setupAccelGroup ((GtkMenuPeer)((Menu)parent).getPeer ()); else if (parent instanceof Component) - setupAccelGroup ((GtkGenericPeer)((Component)parent).getPeer ()); + setupAccelGroup ((GtkComponentPeer)((Component)parent).getPeer ()); else - setupAccelGroup (null); + setupAccelGroup (null); // XXX, should we warn about unknown parent? } public void addItem (MenuItem item) diff --git a/gnu/java/awt/peer/gtk/GtkPanelPeer.java b/gnu/java/awt/peer/gtk/GtkPanelPeer.java index fb5addeb4..88bb71569 100644 --- a/gnu/java/awt/peer/gtk/GtkPanelPeer.java +++ b/gnu/java/awt/peer/gtk/GtkPanelPeer.java @@ -39,8 +39,11 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; import java.awt.AWTEvent; +import java.awt.Graphics; import java.awt.Panel; +import java.awt.event.ComponentEvent; import java.awt.event.MouseEvent; +import java.awt.event.PaintEvent; import java.awt.peer.PanelPeer; public class GtkPanelPeer extends GtkContainerPeer @@ -53,17 +56,39 @@ public class GtkPanelPeer extends GtkContainerPeer super (p); } - public void handleEvent (AWTEvent event) + public void handleEvent(AWTEvent event) { int id = event.getID(); - switch (id) { case MouseEvent.MOUSE_PRESSED: - awtComponent.requestFocusInWindow (); + awtComponent.requestFocusInWindow(); break; + case PaintEvent.UPDATE: + case PaintEvent.PAINT: + { + try + { + Graphics g = getGraphics(); + if (! awtComponent.isShowing() || awtComponent.getWidth() < 1 + || awtComponent.getHeight() < 1 || g == null) + return; + + g.setClip(((PaintEvent) event).getUpdateRect()); + + // Do not want to clear anything before painting.); + awtComponent.paint(g); + + g.dispose(); + return; + } + catch (InternalError e) + { + System.err.println(e); + } + } } - super.handleEvent (event); + super.handleEvent(event); } native void connectSignals (); diff --git a/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java b/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java index d14c16dd7..525a910bc 100644 --- a/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java +++ b/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java @@ -1,5 +1,5 @@ /* GtkPopupMenuPeer.java -- Implements PopupMenuPeer with GTK+ - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -55,11 +55,6 @@ public class GtkPopupMenuPeer extends GtkMenuPeer native void setupAccelGroup (GtkGenericPeer container); - void setParent (MenuItem item) - { - // we don't need to "add" ourselves to our parent - } - native void show (int x, int y, long time); public void show (Component origin, int x, int y) { diff --git a/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java b/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java index aa3a26e34..9b31a7390 100644 --- a/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java +++ b/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java @@ -1,5 +1,5 @@ /* GtkScrollbarPeer.java -- Implements ScrollbarPeer with GTK+ - Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; import java.awt.Adjustable; +import java.awt.EventQueue; import java.awt.Scrollbar; import java.awt.event.AdjustmentEvent; import java.awt.peer.ScrollbarPeer; @@ -69,12 +70,25 @@ public class GtkScrollbarPeer extends GtkComponentPeer public native void setLineIncrement(int amount); public native void setPageIncrement(int amount); - public native void setValues(int value, int visible, int min, int max); + public void setValues(int value, int visible, int min, int max) + { + Scrollbar sb = (Scrollbar) awtComponent; + if (!sb.getValueIsAdjusting()) + setBarValues(value, visible, min, max); + } + + private native void setBarValues(int value, int visible, int min, int max); + + /** + * Called from the native site when the scrollbar changed. + * Posts a "user generated" AdjustmentEvent to the queue. + */ protected void postAdjustmentEvent (int type, int value) { - q().postEvent (new AdjustmentEvent ((Adjustable)awtComponent, + Scrollbar bar = (Scrollbar) awtComponent; + q().postEvent(new AdjustmentEvent(bar, AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, - type, value)); + type, value, true)); } } diff --git a/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java b/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java index e6896c913..5d9be1aec 100644 --- a/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java +++ b/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java @@ -55,7 +55,11 @@ public class GtkTextAreaPeer extends GtkComponentPeer native void create (int width, int height, int scrollbarVisibility); - native void gtkWidgetModifyFont (String name, int style, int size); + /** + * Overridden to set Font for text widget inside scrolled window. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); + native void gtkWidgetRequestFocus (); public native void connectSignals (); diff --git a/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java b/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java index 4afdae82e..763304864 100644 --- a/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java +++ b/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java @@ -112,8 +112,6 @@ public class GtkTextFieldPeer extends GtkComponentPeer native int gtkEntryGetBorderWidth (); - native void gtkWidgetModifyFont (String name, int style, int size); - public GtkTextFieldPeer (TextField tf) { super (tf); diff --git a/gnu/java/awt/peer/gtk/GtkToolkit.java b/gnu/java/awt/peer/gtk/GtkToolkit.java index 0889d85f4..70e25a319 100644 --- a/gnu/java/awt/peer/gtk/GtkToolkit.java +++ b/gnu/java/awt/peer/gtk/GtkToolkit.java @@ -1,5 +1,6 @@ /* GtkToolkit.java -- Implements an AWT Toolkit using GTK for peers - Copyright (C) 1998, 1999, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -159,137 +160,93 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit } /** - * A helper class to return to clients in cases where a BufferedImage is - * desired but its construction fails. + * Helper to return either a Image -- the argument -- or a + * GtkImage with the errorLoading flag set if the argument is null. */ - private class GtkErrorImage extends Image - { - public GtkErrorImage() - { - } - - public int getWidth(ImageObserver observer) - { - return -1; - } - - public int getHeight(ImageObserver observer) - { - return -1; - } - - public ImageProducer getSource() - { - - return new ImageProducer() - { - HashSet consumers = new HashSet(); - public void addConsumer(ImageConsumer ic) - { - consumers.add(ic); - } - - public boolean isConsumer(ImageConsumer ic) - { - return consumers.contains(ic); - } - - public void removeConsumer(ImageConsumer ic) - { - consumers.remove(ic); - } - - public void startProduction(ImageConsumer ic) - { - consumers.add(ic); - Iterator i = consumers.iterator(); - while(i.hasNext()) - { - ImageConsumer c = (ImageConsumer) i.next(); - c.imageComplete(ImageConsumer.IMAGEERROR); - } - } - public void requestTopDownLeftRightResend(ImageConsumer ic) - { - startProduction(ic); - } - }; - } - - public Graphics getGraphics() - { - return null; - } - - public Object getProperty(String name, ImageObserver observer) - { - return null; - } - public Image getScaledInstance(int width, int height, int flags) - { - return new GtkErrorImage(); - } - - public void flush() - { - } - } - - - /** - * Helper to return either a BufferedImage -- the argument -- or a - * GtkErrorImage if the argument is null. - */ - - private Image bufferedImageOrError(BufferedImage b) + private Image imageOrError(Image b) { if (b == null) - return new GtkErrorImage(); + return GtkImage.getErrorImage(); else return b; } - public Image createImage (String filename) { if (filename.length() == 0) return new GtkImage (); - - if (useGraphics2D()) - return bufferedImageOrError(GdkPixbufDecoder.createBufferedImage (filename)); - else - return new GtkImage (filename); + + Image image; + try + { + if (useGraphics2D()) + image = GdkPixbufDecoder.createBufferedImage(filename); + else + image = new GtkImage(filename); + } + catch (IllegalArgumentException iae) + { + image = null; + } + return imageOrError(image); } public Image createImage (URL url) { - if (useGraphics2D()) - return bufferedImageOrError(GdkPixbufDecoder.createBufferedImage (url)); - else - return new GtkImage (url); + Image image; + try + { + if (useGraphics2D()) + image = GdkPixbufDecoder.createBufferedImage(url); + else + image = new GtkImage(url); + } + catch (IllegalArgumentException iae) + { + image = null; + } + return imageOrError(image); } public Image createImage (ImageProducer producer) { - if (useGraphics2D()) - return bufferedImageOrError(GdkPixbufDecoder.createBufferedImage (producer)); - else - return new GtkImage (producer); + Image image; + try + { + if (useGraphics2D()) + image = GdkPixbufDecoder.createBufferedImage(producer); + else + image = new GtkImage(producer); + } + catch (IllegalArgumentException iae) + { + image = null; + } + return imageOrError(image); } public Image createImage (byte[] imagedata, int imageoffset, int imagelength) { - if (useGraphics2D()) - return bufferedImageOrError(GdkPixbufDecoder.createBufferedImage (imagedata, - imageoffset, - imagelength)); - else + Image image; + try + { + if (useGraphics2D()) + image = GdkPixbufDecoder.createBufferedImage(imagedata, + imageoffset, + imagelength); + else + { + byte[] datacopy = new byte[imagelength]; + System.arraycopy(imagedata, imageoffset, datacopy, 0, imagelength); + return new GtkImage(datacopy); + } + } + catch (IllegalArgumentException iae) { - byte[] datacopy = new byte[imagelength]; - System.arraycopy (imagedata, imageoffset, datacopy, 0, imagelength); - return new GtkImage (datacopy); + image = null; } + return imageOrError(image); } /** @@ -608,7 +565,6 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit if (q == null) { q = new EventQueue(); - GtkGenericPeer.enableQueue (q); } } return q; diff --git a/gnu/java/awt/peer/gtk/GtkWindowPeer.java b/gnu/java/awt/peer/gtk/GtkWindowPeer.java index 57fb87f37..6cc1390ea 100644 --- a/gnu/java/awt/peer/gtk/GtkWindowPeer.java +++ b/gnu/java/awt/peer/gtk/GtkWindowPeer.java @@ -38,9 +38,12 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; +import java.awt.AWTEvent; import java.awt.Component; import java.awt.Frame; +import java.awt.Graphics; import java.awt.Window; +import java.awt.event.PaintEvent; import java.awt.event.WindowEvent; import java.awt.peer.WindowPeer; @@ -123,7 +126,23 @@ public class GtkWindowPeer extends GtkContainerPeer native void nativeSetBounds (int x, int y, int width, int height); native void nativeSetBoundsUnlocked (int x, int y, int width, int height); + native void nativeSetLocation (int x, int y); + native void nativeSetLocationUnlocked (int x, int y); + public void setLocation (int x, int y) + { + // prevent window_configure_cb -> awtComponent.setSize -> + // peer.setBounds -> nativeSetBounds self-deadlock on GDK lock. + if (Thread.currentThread() == GtkToolkit.mainThread) + return; + nativeSetLocation (x, y); + } + + public void setLocationUnlocked (int x, int y) + { + nativeSetLocationUnlocked (x, y); + } + public void setBounds (int x, int y, int width, int height) { // prevent window_configure_cb -> awtComponent.setSize -> @@ -192,12 +211,7 @@ public class GtkWindowPeer extends GtkContainerPeer public void show () { - // Prevent the window manager from automatically placing this - // window when it is shown. - setBounds (awtComponent.getX(), - awtComponent.getY(), - awtComponent.getWidth(), - awtComponent.getHeight()); + setLocation(awtComponent.getX(), awtComponent.getY()); setVisible (true); } @@ -235,4 +249,32 @@ public class GtkWindowPeer extends GtkContainerPeer // TODO Auto-generated method stub return false; } + + public void handleEvent(AWTEvent event) + { + int id = event.getID(); + if (id == PaintEvent.UPDATE || id == PaintEvent.PAINT) + { + try + { + Graphics g = getGraphics(); + if (! awtComponent.isShowing() || awtComponent.getWidth() < 1 + || awtComponent.getHeight() < 1 || g == null) + return; + + g.setClip(((PaintEvent) event).getUpdateRect()); + + // Do not want to clear anything before painting. + awtComponent.paint(g); + + g.dispose(); + return; + } + catch (InternalError e) + { + System.err.println(e); + } + } + super.handleEvent(event); + } } diff --git a/gnu/java/awt/peer/swing/SwingButtonPeer.java b/gnu/java/awt/peer/swing/SwingButtonPeer.java new file mode 100644 index 000000000..2357fcbfb --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingButtonPeer.java @@ -0,0 +1,224 @@ +/* SwingButtonPeer.java -- A Swing based peer for AWT buttons + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Button; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ButtonPeer; + +import javax.swing.JButton; +import javax.swing.JComponent; + +/** + * A Swing based peer for the AWT button. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingButtonPeer + extends SwingComponentPeer + implements ButtonPeer +{ + + /** + * A specialized Swing button to be used as AWT button. + * + * @author Roman Kennke (kennke@aicas.com) + */ + class SwingButton + extends JButton + implements SwingComponent + { + /** + * Overridden so that this method returns the correct value even without a + * peer. + * + * @return the screen location of the button + */ + public Point getLocationOnScreen() + { + return SwingButtonPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value for the + * swing button, even if it has no peer on its own. + * + * @return <code>true</code> if the button is currently showing, + * <code>false</code> otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (SwingButtonPeer.this.awtComponent != null) + retVal = SwingButtonPeer.this.awtComponent.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingButtonPeer.this.createImage(w, h); + } + + /** + * Overridden, so that the Swing button can create a Graphics without its + * own peer. + * + * @return a graphics instance for the button + */ + public Graphics getGraphics() + { + return SwingButtonPeer.this.getGraphics(); + } + + /** + * Returns this button. + * + * @return this button + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * <code>processMouseEvent()</code> after having retargetted it to this + * button. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding it to + * <code>processMouseMotionEvent()</code> after having retargetted it to + * this button. + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to + * <code>processKeyEvent()</code> after having retargetted it to this + * button. + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + ev.setSource(this); + processKeyEvent(ev); + } + } + + /** + * Listens for ActionEvents on the Swing button and triggers corresponding + * ActionEvents on the AWT button. + * + * @author Roman Kennke (kennke@aicas.com) + */ + class SwingButtonListener implements ActionListener + { + + /** + * Receives notification when an action was performend on the button. + * + * @param event the action event + */ + public void actionPerformed(ActionEvent event) + { + Button b = (Button) SwingButtonPeer.this.awtComponent; + ActionListener[] l = b.getActionListeners(); + if (l.length == 0) + return; + ActionEvent ev = new ActionEvent(b, ActionEvent.ACTION_PERFORMED, + b.getActionCommand()); + for (int i = 0; i < l.length; ++i) + l[i].actionPerformed(ev); + } + + } + + /** + * Constructs a new SwingButtonPeer. + * + * @param theButton the AWT button for this peer + */ + public SwingButtonPeer(Button theButton) + { + SwingButton button = new SwingButton(); + button.setText(theButton.getLabel()); + button.addActionListener(new SwingButtonListener()); + init(theButton, button); + } + + /** + * Sets the label of the button. This call is forwarded to the setText method + * of the managed Swing button. + * + * @param label the label to set + */ + public void setLabel(String label) + { + ((SwingButton) swingComponent).setText(label); + } +} diff --git a/gnu/java/awt/peer/swing/SwingCanvasPeer.java b/gnu/java/awt/peer/swing/SwingCanvasPeer.java new file mode 100644 index 000000000..abef9ef12 --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingCanvasPeer.java @@ -0,0 +1,64 @@ +/* SwingCanvasPeer.java -- A canvas peer based on Swing + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.swing; + +import java.awt.Canvas; +import java.awt.peer.CanvasPeer; +import java.awt.peer.LightweightPeer; + +/** + * A CanvasPeer to be used together with the Swing peers. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingCanvasPeer + extends SwingComponentPeer + implements LightweightPeer, CanvasPeer +{ + + /** + * Creates a new <code>SwingCanvasPeer</code> for the specified Canvas. + * + * @param canvas the canvas. + */ + public SwingCanvasPeer(Canvas canvas) + { + init(canvas, null); + } +} diff --git a/gnu/java/awt/peer/swing/SwingComponent.java b/gnu/java/awt/peer/swing/SwingComponent.java new file mode 100644 index 000000000..04ca7294f --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingComponent.java @@ -0,0 +1,89 @@ +/* SwingComponent.java -- An interface that defines a Swing component for peers + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; + +import javax.swing.JComponent; + +/** + * Defines some additional methods that the Swing components must implement + * in order to work with the Swing peers. This is usually achieved by + * subclassing a Swing component and forwarding the method calls to some + * protected JComponent method. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public interface SwingComponent +{ + + /** + * Returns the actual swing compenent. + * + * @return the actual swing compenent + */ + JComponent getJComponent(); + + /** + * Handles a mouse event. This is usually forwarded to + * {@link Component#processMouseMotionEvent(MouseEvent)} of the swing + * component. + * + * @param ev the mouse event + */ + void handleMouseEvent(MouseEvent ev); + + /** + * Handles a mouse motion event. This is usually forwarded to + * {@link Component#processMouseEvent(MouseEvent)} of the swing + * component. + * + * @param ev the mouse motion event + */ + void handleMouseMotionEvent(MouseEvent ev); + + /** + * Handles a key event. This is usually forwarded to + * {@link Component#processKeyEvent(KeyEvent)} of the swing + * component. + * + * @param ev the key event + */ + void handleKeyEvent(KeyEvent ev); +} diff --git a/gnu/java/awt/peer/swing/SwingComponentPeer.java b/gnu/java/awt/peer/swing/SwingComponentPeer.java new file mode 100644 index 000000000..5e34bc9dd --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingComponentPeer.java @@ -0,0 +1,994 @@ +/* SwingComponentPeer.java -- An abstract base class for Swing based peers + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.BufferCapabilities; +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.BufferCapabilities.FlipContents; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.PaintEvent; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ContainerPeer; + +/** + * The base class for Swing based component peers. This provides the basic + * functionality needed for Swing based component peers. Many methods are + * implemented to forward to the Swing component. Others however forward + * to the component's parent and expect the toplevel component peer to provide + * a real implementation of it. These are for example the key methods + * {@link #getGraphics()} and {@link #createImage(int, int)}, as well as + * {@link #getLocationOnScreen()}. + * + * This class also provides the necesary hooks into the Swing painting and + * event handling system. In order to achieve this, it traps paint, mouse and + * key events in {@link #handleEvent(AWTEvent)} and calls some special methods + * ({@link #peerPaint(Graphics)}, {@link #handleKeyEvent(KeyEvent)}, + * {@link #handleMouseEvent(MouseEvent)} and + * {@link #handleMouseMotionEvent(MouseEvent)}) that call the corresponding + * Swing methods. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingComponentPeer + implements ComponentPeer +{ + + /** + * The AWT component for this peer. + */ + protected Component awtComponent; + + /** + * The Swing component for this peer. + */ + protected SwingComponent swingComponent; + + /** + * Creates a SwingComponentPeer instance. Subclasses are expected to call + * this constructor and thereafter call {@link #init(Component, JComponent)} + * in order to setup the AWT and Swing components properly. + */ + protected SwingComponentPeer() + { + // Nothing to do here. + } + + /** + * Initializes the AWT and Swing component for this peer. It is expected that + * subclasses call this from within their constructor. + * + * @param awtComp the AWT component for this peer + * @param swingComp the Swing component for this peer + */ + protected void init(Component awtComp, SwingComponent swingComp) + { + awtComponent = awtComp; + swingComponent = swingComp; + } + + /** + * Returns the construction status of the specified image. This is called + * by {@link Component#checkImage(Image, int, int, ImageObserver)}. + * + * @param img the image + * @param width the width of the image + * @param height the height of the image + * @param ob the image observer to be notified of updates of the status + * + * @return a bitwise ORed set of ImageObserver flags + */ + public int checkImage(Image img, int width, int height, ImageObserver ob) + { + return Toolkit.getDefaultToolkit().checkImage(img, width, height, ob); + } + + /** + * Creates an image by starting the specified image producer. This is called + * by {@link Component#createImage(ImageProducer)}. + * + * @param prod the image producer to be used to create the image + * + * @return the created image + */ + public Image createImage(ImageProducer prod) + { + Image image = Toolkit.getDefaultToolkit().createImage(prod); + return image; + } + + /** + * Creates an empty image with the specified <code>width</code> and + * <code>height</code>. + * + * This is implemented to let the parent component create the image. This + * eventually goes up to the top-level component peer, which is then expected + * to deliver the image. + * + * @param width the width of the image to be created + * @param height the height of the image to be created + * + * @return the created image + */ + public Image createImage(int width, int height) + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.createImage(width, height); + } + + /** + * Disables the component. This is called by {@link Component#disable()}. + */ + public void disable() + { + if (swingComponent != null) + swingComponent.getJComponent().setEnabled(false); + } + + /** + * Disposes the component peer. This should release all resources held by the + * peer. This is called when the component is no longer in use. + */ + public void dispose() + { + awtComponent = null; + swingComponent = null; + } + + /** + * Enables the component. This is called by {@link Component#enable()}. + */ + public void enable() + { + if (swingComponent != null) + swingComponent.getJComponent().setEnabled(true); + } + + /** + * Returns the color model of the component. This is currently not used. + * + * @return the color model of the component + */ + public ColorModel getColorModel() + { + // FIXME: When this peer method will be used, we need to provide an + // implementation of this, probably forwarding to the toplevel peer, like + // in the other methods. + return null; + } + + /** + * Returns the font metrics for the specified font. This is called by + * {@link Component#getFontMetrics(Font)}. + * + * This is implemented to query the font metrics from the parent component. + * This will eventually call the top-level component peer, which is then + * expected to deliver a font metrics object. + * + * @param f the font for which to query the font metrics + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font f) + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.getFontMetrics(f); + } + + /** + * Returns a {@link Graphics} object suitable for drawing on this component. + * This is called by {@link Component#getGraphics()}. + * + * This is implemented to query the graphics from the parent component and + * adjust the clip and translation to match this component. + * This will eventually call the top-level component peer, which is then + * expected to deliver a graphics object. + * + * @return a graphics object suitable for drawing on this component + */ + public Graphics getGraphics() + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + Graphics g = parentPeer.getGraphics(); + g.translate(awtComponent.getX(), awtComponent.getY()); + g.setClip(0, 0, awtComponent.getWidth(), awtComponent.getHeight()); + return g; + } + + /** + * Returns the location of this component in screen coordinates. This is + * called by {@link Component#getLocationOnScreen()}. + * + * This is implemented to query the parent component peer for its screen + * location and adds the offset of this component to it. This will eventually + * call the top-level component's peer, which is then expected to provide + * it's screen location. + * + * @return the location of this component in screen coordinates + */ + public Point getLocationOnScreen() + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + Point location = parentPeer.getLocationOnScreen(); + location.x += awtComponent.getX(); + location.y += awtComponent.getY(); + return location; + } + + /** + * Returns the minimum size for the component. This is called by + * {@link Component#getMinimumSize()}. + * + * This is implemented to return the Swing component's minimum size. + * + * @return the minimum size for the component + */ + public Dimension getMinimumSize() + { + Dimension retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getMinimumSize(); + else + retVal = new Dimension(0, 0); + return retVal; + } + + /** + * Returns the preferred size for the component. This is called by + * {@link Component#getPreferredSize()}. + * + * This is implemented to return the Swing component's preferred size. + * + * @return the preferred size for the component + */ + public Dimension getPreferredSize() + { + Dimension retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getPreferredSize(); + else + retVal = new Dimension(0, 0); + return retVal; + } + + /** + * Returns the toolkit that created this peer. + * + * @return the toolkit that created this peer + */ + public Toolkit getToolkit() + { + return Toolkit.getDefaultToolkit(); + } + + /** + * Handles the given event. This is called from + * {@link Component#dispatchEvent(AWTEvent)} to give the peer a chance to + * react to events for the component. + * + * @param e the event + */ + public void handleEvent(AWTEvent e) + { + switch (e.getID()) + { + case PaintEvent.UPDATE: + case PaintEvent.PAINT: + Graphics g = getGraphics(); + Rectangle clip = ((PaintEvent)e).getUpdateRect(); + g.clipRect(clip.x, clip.y, clip.width, clip.height); + //if (this instanceof LightweightPeer) + // { + if (e.getID() == PaintEvent.UPDATE) + awtComponent.update(g); + else + awtComponent.paint(g); + // } + // We paint the 'heavyweights' at last, so that they appear on top of + // everything else. + peerPaint(g); + + g.dispose(); + break; + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + case MouseEvent.MOUSE_CLICKED: + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + handleMouseEvent((MouseEvent) e); + break; + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + handleMouseMotionEvent((MouseEvent) e); + break; + case KeyEvent.KEY_PRESSED: + case KeyEvent.KEY_RELEASED: + case KeyEvent.KEY_TYPED: + handleKeyEvent((KeyEvent) e); + break; + default: + // Other event types are not handled here. + break; + } + } + + /** + * Makes the component invisible. This is called from + * {@link Component#hide()}. + * + * This is implemented to call setVisible(false) on the Swing component. + */ + public void hide() + { + if (swingComponent != null) + swingComponent.getJComponent().setVisible(false); + } + + /** + * Returns <code>true</code> if the component can receive keyboard input + * focus. This is called from {@link Component#isFocusTraversable()}. + * + * This is implemented to return isFocusable() from the Swing component. + * + * @specnote Part of the earlier 1.1 API, replaced by isFocusable(). + */ + public boolean isFocusTraversable() + { + return swingComponent != null ? + swingComponent.getJComponent().isFocusable() : false; + } + + /** + * Returns <code>true</code> if the component can receive keyboard input + * focus. This is called from {@link Component#isFocusable()}. + * + * This is implemented to return isFocusable() from the Swing component. + */ + public boolean isFocusable() + { + return swingComponent != null ? + swingComponent.getJComponent().isFocusable() : false; + } + + /** + * Returns the minimum size for the component. This is called by + * {@link Component#minimumSize()}. + * + * This is implemented to return the Swing component's minimum size. + * + * @return the minimum size for the component + */ + public Dimension minimumSize() + { + Dimension retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getMinimumSize(); + else + retVal = new Dimension(0, 0); + return retVal; + } + + /** + * Returns the preferred size for the component. This is called by + * {@link Component#getPreferredSize()}. + * + * This is implemented to return the Swing component's preferred size. + * + * @return the preferred size for the component + */ + public Dimension preferredSize() + { + Dimension retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getPreferredSize(); + else + retVal = new Dimension(0, 0); + return retVal; + } + + /** + * Prepares an image for rendering on this component. This is called by + * {@link Component#prepareImage(Image, int, int, ImageObserver)}. + * + * @param img the image to prepare + * @param width the desired width of the rendered image + * @param height the desired height of the rendered image + * @param ob the image observer to be notified of updates in the preparation + * process + * + * @return <code>true</code> if the image has been fully prepared, + * <code>false</code> otherwise (in which case the image observer + * receives updates) + */ + public void paint(Graphics graphics) + { + // FIXME: I don't know what this method is supposed to do. + } + + /** + * Prepares an image for rendering on this component. This is called by + * {@link Component#prepareImage(Image, int, int, ImageObserver)}. + * + * @param img the image to prepare + * @param width the desired width of the rendered image + * @param height the desired height of the rendered image + * @param ob the image observer to be notified of updates in the preparation + * process + * + * @return <code>true</code> if the image has been fully prepared, + * <code>false</code> otherwise (in which case the image observer + * receives updates) + */ + public boolean prepareImage(Image img, int width, int height, ImageObserver ob) + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.prepareImage(img, width, height, ob); + } + + public void print(Graphics graphics) + { + // FIXME: I don't know what this method is supposed to do. + } + + /** + * Repaints the specified rectangle of this component. This is called from + * {@link Component#repaint(long, int, int, int, int)}. + * + * This is implemented to call repaint() on the Swing component. + * + * @param tm number of milliseconds to wait with repainting + * @param x the X coordinate of the upper left corner of the damaged rectangle + * @param y the Y coordinate of the upper left corner of the damaged rectangle + * @param width the width of the damaged rectangle + * @param height the height of the damaged rectangle + */ + public void repaint(long tm, int x, int y, int width, int height) + { + if (swingComponent != null) + swingComponent.getJComponent().repaint(tm, x, y, width, height); + else + { + PaintEvent ev = new PaintEvent(awtComponent, PaintEvent.UPDATE, + new Rectangle(x, y, width, height)); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ev); + } + } + + /** + * Requests that this component receives the focus. This is called from + * {@link Component#requestFocus()}. + * + * This calls requestFocus() on the Swing component. + * + * @specnote Part of the earlier 1.1 API, apparently replaced by argument + * form of the same method. + */ + public void requestFocus() + { + if (swingComponent != null) + swingComponent.getJComponent().requestFocus(); + } + + /** + * Requests that this component receives the focus. This is called from + * {@link Component#requestFocus()}. + * + * This calls requestFocus() on the Swing component. + * + * @param source TODO + * @param bool1 TODO + * @param bool2 TODO + * @param x TODO + * + * @return TODO + */ + public boolean requestFocus(Component source, boolean bool1, boolean bool2, long x) + { + if (swingComponent != null) + swingComponent.getJComponent().requestFocus(); + return swingComponent != null; + } + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#reshape(int, int, int, int)}. + * + * This is implemented to call setBounds() on the Swing component. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ + public void reshape(int x, int y, int width, int height) + { + if (swingComponent != null) + swingComponent.getJComponent().setBounds(x, y, width, height); + } + + /** + * Sets the background color of the component. This is called by + * {@link Component#setBackground(Color)}. + * + * This is implemented to call setBackground() on the Swing component. + * + * @param color the background color to set + */ + public void setBackground(Color color) + { + if (swingComponent != null) + swingComponent.getJComponent().setBackground(color); + } + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#setBounds(int, int, int, int)}. + * + * This is implemented to call setBounds() on the Swing component. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ + public void setBounds(int x, int y, int width, int height) + { + if (swingComponent != null) + swingComponent.getJComponent().setBounds(x, y, width, height); + } + + /** + * Sets the cursor of the component. This is called by + * {@link Component#setCursor(Cursor)}. + * + * This is implemented to call setCursor() on the Swing component. + * + * @specnote Part of the earlier 1.1 API, apparently no longer needed. + */ + public void setCursor(Cursor cursor) + { + if (swingComponent != null) + swingComponent.getJComponent().setCursor(cursor); + } + + /** + * Sets the enabled/disabled state of this component. This is called by + * {@link Component#setEnabled(boolean)}. + * + * This is implemented to call setEnabled() on the Swing component. + * + * @param enabled <code>true</code> to enable the component, + * <code>false</code> to disable it + */ + public void setEnabled(boolean enabled) + { + if (swingComponent != null) + swingComponent.getJComponent().setEnabled(enabled); + } + + /** + * Sets the font of the component. This is called by + * {@link Component#setFont(Font)}. + * + * This is implemented to call setFont() on the Swing component. + * + * @param font the font to set + */ + public void setFont(Font font) + { + if (swingComponent != null) + swingComponent.getJComponent().setFont(font); + } + + /** + * Sets the foreground color of the component. This is called by + * {@link Component#setForeground(Color)}. + * + * This is implemented to call setForeground() on the Swing component. + * + * @param color the foreground color to set + */ + public void setForeground(Color color) + { + if (swingComponent != null) + swingComponent.getJComponent().setForeground(color); + } + + /** + * Sets the visibility state of the component. This is called by + * {@link Component#setVisible(boolean)}. + * + * This is implemented to call setVisible() on the Swing component. + * + * @param visible <code>true</code> to make the component visible, + * <code>false</code> to make it invisible + */ + public void setVisible(boolean visible) + { + if (swingComponent != null) + swingComponent.getJComponent().setVisible(visible); + } + + /** + * Makes the component visible. This is called by {@link Component#show()}. + * + * This is implemented to call setVisible(true) on the Swing component. + */ + public void show() + { + if (swingComponent != null) + swingComponent.getJComponent().setVisible(true); + } + + /** + * Get the graphics configuration of the component. The color model + * of the component can be derived from the configuration. + * + * This is implemented to return the GraphicsConfiguration of the parent + * component. This will eventually call the toplevel component peer, which + * is expected to provide a real implementation. + * + * @return the graphics configuration of the component + */ + public GraphicsConfiguration getGraphicsConfiguration() + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.getGraphicsConfiguration(); + } + + /** + * Part of an older API, no longer needed. + */ + public void setEventMask(long mask) + { + // Nothing to do here. + } + + /** + * Returns <code>true</code> if this component has been obscured, + * <code>false</code> otherwise. This will only work if + * {@link #canDetermineObscurity()} also returns <code>true</code>. + * + * This is not yet implemented. + * + * @return <code>true</code> if this component has been obscured, + * <code>false</code> otherwise. + */ + public boolean isObscured() + { + return false; + } + + /** + * Returns <code>true</code> if this component peer can determine if the + * component has been obscured, <code>false</code> otherwise. + * + * This is not yet implemented. + * + * @return <code>true</code> if this component peer can determine if the + * component has been obscured, <code>false</code> otherwise + */ + public boolean canDetermineObscurity() + { + return false; + } + + /** + * Coalesces the specified paint event. + * + * @param e the paint event + */ + public void coalescePaintEvent(PaintEvent e) + { + // Nothing to do here yet. + } + + /** + * Updates the cursor. This is not yet implemented. + */ + public void updateCursorImmediately() + { + // Nothing to do here yet. + } + + /** + * Returns true, if this component can handle wheel scrolling, + * <code>false</code> otherwise. + * + * This is not yet implemented and returns <code>false</code>. + * + * @return true, if this component can handle wheel scrolling, + * <code>false</code> otherwise + */ + public boolean handlesWheelScrolling() + { + return false; + } + + /** + * A convenience method that creates a volatile image. The volatile + * image is created on the screen device on which this component is + * displayed, in the device's current graphics configuration. + * + * This is implemented to let the parent component peer create an image. + * This eventually ends up in the toplevel component peer, which is then + * responsible for creating the real image. + * + * @param width width of the image + * @param height height of the image + * + * @see VolatileImage + * + * @since 1.2 + */ + public VolatileImage createVolatileImage(int width, int height) + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.createVolatileImage(width, height); + } + + /** + * Create a number of image buffers that implement a buffering + * strategy according to the given capabilities. + * + * This is implemented to forward to the parent component peer. Eventually + * this ends up in the top level component peer, which is then responsible + * for doing the real work. + * + * @param numBuffers the number of buffers + * @param caps the buffering capabilities + * + * @throws AWTException if the specified buffering strategy is not + * implemented + * + * @since 1.2 + */ + public void createBuffers(int numBuffers, BufferCapabilities caps) throws AWTException + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + parentPeer.createBuffers(numBuffers, caps); + } + + /** + * Return the back buffer of this component. + * + * This is implemented to forward to the parent. Eventually this ends + * up in the toplevel component, which is then responsible for providing + * a back buffer. + * + * @return the back buffer of this component. + * + * @since 1.2 + */ + public Image getBackBuffer() + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.getBackBuffer(); + } + + /** + * Perform a page flip, leaving the contents of the back buffer in + * the specified state. + * + * This is implemented to forward to the parent. Eventually this ends + * up in the toplevel component, which is then responsible for doing the real + * work. + * + * @param contents the state in which to leave the back buffer + * + * @since 1.2 + */ + public void flip(FlipContents contents) + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + parentPeer.flip(contents); + } + + /** + * Destroy the resources created by createBuffers. + * + * This is implemented to forward to the parent component peer. Eventually + * this ends up in the top level component peer, which is then responsible + * for doing the real work. + * + * @since 1.2 + */ + public void destroyBuffers() + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + parentPeer.destroyBuffers(); + } + + /** + * Get the bounds of this component peer. + * + * This is implemented to forward to the Swing component. + * + * @return component peer bounds + * @since 1.5 + */ + public Rectangle getBounds() + { + Rectangle retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getBounds(); + else + retVal = new Rectangle(); + return retVal; + } + + /** + * Reparent this component under another container. + * + * @param parent + * @since 1.5 + */ + public void reparent(ContainerPeer parent) + { + // Nothing to do here. + } + + /** + * Set the bounds of this component peer. + * + * This is implemented to forward to the swing component. + * + * @param x the new x co-ordinate + * @param y the new y co-ordinate + * @param width the new width + * @param height the new height + * @param z the new stacking level + * @since 1.5 + */ + public void setBounds(int x, int y, int width, int height, int z) + { + if (swingComponent != null) + swingComponent.getJComponent().setBounds(x, y, width, height); + // FIXME: Somehow handle the Z order. + } + + /** + * Check if this component supports being reparented. + * + * @return true if this component can be reparented, + * false otherwise. + * @since 1.5 + */ + public boolean isReparentSupported() + { + return true; + } + + + /** + * Layout this component peer. + * + * @since 1.5 + */ + public void layout() + { + if (swingComponent != null) + swingComponent.getJComponent().doLayout(); + } + + /** + * Triggers 'heavyweight' painting of the components. This usually calls + * paint() on the Swing component. + * + * @param g the graphics context to use for painting + */ + protected void peerPaint(Graphics g) + { + if (swingComponent != null) + swingComponent.getJComponent().paint(g); + } + + /** + * Handles mouse events on the component. This is usually forwarded to the + * SwingComponent's processMouseEvent() method. + * + * @param e the mouse event + */ + protected void handleMouseEvent(MouseEvent e) + { + if (swingComponent != null) + swingComponent.handleMouseEvent(e); + } + + /** + * Handles mouse motion events on the component. This is usually forwarded + * to the SwingComponent's processMouseMotionEvent() method. + * + * @param e the mouse motion event + */ + protected void handleMouseMotionEvent(MouseEvent e) + { + if (swingComponent != null) + swingComponent.handleMouseMotionEvent(e); + } + + /** + * Handles key events on the component. This is usually forwarded to the + * SwingComponent's processKeyEvent() method. + * + * @param e the key event + */ + protected void handleKeyEvent(KeyEvent e) + { + if (swingComponent != null) + swingComponent.handleKeyEvent(e); + } + + /** + * Returns the AWT component for this peer. + * + * @return the AWT component for this peer + */ + public Component getComponent() + { + return awtComponent; + } +} diff --git a/gnu/java/awt/peer/swing/SwingContainerPeer.java b/gnu/java/awt/peer/swing/SwingContainerPeer.java new file mode 100644 index 000000000..37bea751f --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingContainerPeer.java @@ -0,0 +1,241 @@ +/* SwingContainerPeer.java -- A Swing based peer for AWT containers + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Shape; +import java.awt.event.MouseEvent; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ContainerPeer; + +/** + * A peer for Container to be used with the Swing based AWT peers. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingContainerPeer + extends SwingComponentPeer + implements ContainerPeer +{ + + /** + * Creates a new SwingContainerPeer. + * + * @param awtCont + */ + public SwingContainerPeer(Container awtCont) + { + init(awtCont, null); + } + + /** + * Returns the insets of the container. + * + * This is implemented to return the insets of the Swing container. + * + * @return the insets of the container + */ + public Insets insets() + { + Insets retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getInsets(); + else + retVal = new Insets(0, 0, 0, 0); + return retVal; + } + + /** + * Returns the insets of the container. + * + * This is implemented to return the insets of the Swing container. + * + * @return the insets of the container + */ + public Insets getInsets() + { + Insets retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getInsets(); + else + retVal = new Insets(0, 0, 0, 0); + return retVal; + } + + /** + * Called before the validation of this containers begins. + */ + public void beginValidate() + { + // Nothing to do here. + } + + /** + * Called after the validation of this containers ended. + */ + public void endValidate() + { + // Nothing to do here. + } + + /** + * Called before the layout of this containers begins. + */ + public void beginLayout() + { + // Nothing to do here. + } + + /** + * Called after the layout of this containers ended. + */ + public void endLayout() + { + // Nothing to do here. + } + + /** + * Returns <code>false</code> unconditionally. This method is not used at + * the moment. + * + * @return <code>false</code> + */ + public boolean isPaintPending() + { + return false; + } + + /** + * Returns <code>false</code> unconditionally. This method is not used at + * the moment. + * + * @return <code>false</code> + */ + public boolean isRestackSupported() + { + return false; + } + + /** + * This method is not used at the moment. + */ + public void cancelPendingPaint(int x, int y, int width, int height) + { + // Nothing to do here. + } + + /** + * This method is not used at the moment. + */ + public void restack() + { + // Nothing to do here. + } + + /** + * Triggers painting of a component. This calls peerPaint on all the child + * components of this container. + * + * @param g the graphics context to paint to + */ + protected void peerPaint(Graphics g) + { + Container c = (Container) awtComponent; + Component[] children = c.getComponents(); + for (int i = children.length - 1; i >= 0; --i) + { + Component child = children[i]; + ComponentPeer peer = child.getPeer(); + boolean translated = false; + boolean clipped = false; + Shape oldClip = g.getClip(); + try + { + g.translate(child.getX(), child.getY()); + translated = true; + g.setClip(0, 0, child.getWidth(), child.getHeight()); + clipped = true; + if (peer instanceof SwingComponentPeer) + ((SwingComponentPeer) peer).peerPaint(g); + } + finally + { + if (translated) + g.translate(- child.getX(), - child.getY()); + if (clipped) + g.setClip(oldClip); + } + } + } + + /** + * Handles mouse events by dispatching it to the correct component. + * + * @param ev the mouse event + */ + protected void handleMouseEvent(MouseEvent ev) + { + Component comp = awtComponent.getComponentAt(ev.getPoint()); + ComponentPeer peer = comp.getPeer(); + if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer) + { + ev.translatePoint(comp.getX(), comp.getY()); + ev.setSource(comp); + ((SwingComponentPeer) peer).handleMouseEvent(ev); + } + } + + /** + * Handles mouse events by dispatching it to the correct component. + * + * @param ev the mouse event + */ + protected void handleMouseMotionEvent(MouseEvent ev) + { + Component comp = awtComponent.getComponentAt(ev.getPoint()); + ComponentPeer peer = comp.getPeer(); + if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer) + { + ev.translatePoint(comp.getX(), comp.getY()); + ((SwingComponentPeer) peer).handleMouseMotionEvent(ev); + } + } +} diff --git a/gnu/java/awt/peer/swing/SwingFramePeer.java b/gnu/java/awt/peer/swing/SwingFramePeer.java new file mode 100644 index 000000000..fea1b504a --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingFramePeer.java @@ -0,0 +1,196 @@ +/* SwingFramePeer.java -- An abstract Swing based peer for AWT frames + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.MenuBar; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.awt.peer.FramePeer; + +/** + * An abstract base class for FramePeer implementations based on Swing. + * This class provides the ability to display and handle AWT MenuBars that + * are based on Swing. + * + * As a minimum, a subclass must implement all the remaining abstract methods + * as well as the following methods: + * <ul> + * <li>{@link ComponentPeer#getLocationOnScreen()}</li> + * <li>{@link ComponentPeer#getGraphics()}</li> + * <li>{@link ComponentPeer#createImage(int, int)}</li> + * </ul> + * + * @author Roman Kennke (kennke@aicas.com) + */ +public abstract class SwingFramePeer + extends SwingWindowPeer + implements FramePeer +{ + /** + * The menu bar to display. + */ + SwingMenuBarPeer menuBar = null; + + /** + * Creates a new SwingFramePeer. + * + * @param frame the frame + */ + public SwingFramePeer(Frame frame) + { + super(frame); + } + + /** + * Sets the menu bar to display in this frame. + * + * @param mb the menu bar to set + */ + public void setMenuBar(MenuBar mb) + { + menuBar = (SwingMenuBarPeer) mb.getPeer(); + menuBar.setFramePeer(this); + menuBar.setWidth(awtComponent.getWidth()); + } + + /** + * Triggers 'heavyweight' painting of the frame. This will paint a menu bar + * if present as well as the child components of this frame. + * + * @param g the graphics context to use for painting + */ + protected void peerPaint(Graphics g) + { + super.peerPaint(g); + if (menuBar != null) + menuBar.peerPaint(g); + } + + /** + * Sets the size and location of this frame. This resizes the menubar to fit + * within the frame. + * + * @param x the X coordinate of the screen location + * @param y the Y coordinate of the screen location + * @param w the width of the frame + * @param h the height of the frame + */ + public void setBounds(int x, int y, int w, int h) + { + super.setBounds(x, y, w, h); + if (menuBar != null) + menuBar.setWidth(w); + } + + /** + * Calculates the insets of this frame peer. This fetches the insets + * from the superclass and adds the insets of the menubar if one is present. + * + * @return the insets of the frame + */ + public Insets getInsets() + { + Insets insets = super.getInsets(); + if (menuBar != null) + insets.top += menuBar.getHeight(); + return insets; + } + + /** + * Returns the location of the menu on the screen. This is needed internally + * by the {@link SwingMenuBarPeer} in order to determine its screen location. + * + * @return the location of the menu on the screen + */ + public Point getMenuLocationOnScreen() + { + Insets i = super.getInsets(); + return new Point(i.top, i.left); + } + + /** + * Overridden to provide the ability to handle menus. + * + * @param ev the mouse event + */ + protected void handleMouseEvent(MouseEvent ev) + { + Point p = ev.getPoint(); + Insets i = super.getInsets(); + if (menuBar != null) + { + int menuHeight = menuBar.getHeight(); + if (p.y >= i.top && p.y <= i.top + menuHeight) + menuBar.handleMouseEvent(ev); + else + { + ev.translatePoint(0, -menuHeight); + super.handleMouseMotionEvent(ev); + } + } + + super.handleMouseEvent(ev); + } + + /** + * Overridden to provide the ability to handle menus. + * + * @param ev the mouse event + */ + protected void handleMouseMotionEvent(MouseEvent ev) + { + Point p = ev.getPoint(); + Insets i = super.getInsets(); + if (menuBar != null) + { + int menuHeight = menuBar.getHeight(); + if (p.y >= i.top && p.y <= i.top + menuHeight) + menuBar.handleMouseMotionEvent(ev); + else + { + ev.translatePoint(0, -menuHeight); + super.handleMouseMotionEvent(ev); + } + } + + super.handleMouseMotionEvent(ev); + } +} diff --git a/gnu/java/awt/peer/swing/SwingLabelPeer.java b/gnu/java/awt/peer/swing/SwingLabelPeer.java new file mode 100644 index 000000000..dd86fff2d --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingLabelPeer.java @@ -0,0 +1,196 @@ +/* SwingLabelPeer.java -- A Swing based peer for AWT labels + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Image; +import java.awt.Label; +import java.awt.Point; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.LabelPeer; + +import javax.swing.JComponent; +import javax.swing.JLabel; + + +/** + * A Label peer based on {@link JLabel}. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingLabelPeer + extends SwingComponentPeer + implements LabelPeer +{ + + /** + * A spezialized Swing label used to paint the label for the AWT Label. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingLabel + extends JLabel + implements SwingComponent + { + + /** + * Returns this label. + * + * @return <code>this</code> + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * <code>processMouseEvent()</code>. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + processMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding it to + * <code>processMouseMotionEvent()</code>. + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to <code>processKeyEvent()</code>. + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + processKeyEvent(ev); + } + + /** + * Overridden so that this method returns the correct value even without a + * peer. + * + * @return the screen location of the button + */ + public Point getLocationOnScreen() + { + return SwingLabelPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value for the + * swing button, even if it has no peer on its own. + * + * @return <code>true</code> if the button is currently showing, + * <code>false</code> otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (SwingLabelPeer.this.awtComponent != null) + retVal = SwingLabelPeer.this.awtComponent.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingLabelPeer.this.createImage(w, h); + } + + } + + /** + * Creates a new <code>SwingLabelPeer</code> for the specified AWT label. + * + * @param label the AWT label + */ + public SwingLabelPeer(Label label) + { + super(); + SwingLabel swingLabel = new SwingLabel(); + swingLabel.setText(label.getText()); + swingLabel.setHorizontalAlignment(label.getAlignment()); + swingLabel.setOpaque(true); + init(label, swingLabel); + } + + /** + * Sets the text of the label. This is implemented to set the text on the + * Swing label. + * + * @param text the text to be set + */ + public void setText(String text) + { + ((JLabel) swingComponent.getJComponent()).setText(text); + } + + /** + * Sets the horizontal alignment of the label. This is implemented to + * set the alignment on the Swing label. + * + * @param alignment the horizontal alignment + * + * @see Label#LEFT + * @see Label#RIGHT + * @see Label#CENTER + */ + public void setAlignment(int alignment) + { + ((JLabel) swingComponent.getJComponent()).setHorizontalAlignment(alignment); + } + +} diff --git a/gnu/java/awt/peer/swing/SwingMenuBarPeer.java b/gnu/java/awt/peer/swing/SwingMenuBarPeer.java new file mode 100644 index 000000000..bd9dcd77a --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingMenuBarPeer.java @@ -0,0 +1,295 @@ +/* SwingMenuBarPeer.java -- A Swing based peer for AWT menu bars + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Container; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.awt.peer.MenuBarPeer; + +import javax.swing.JMenuBar; + +/** + * A Swing based peer for the AWT menu bar. This is a little bit different from + * the other peers, since the AWT MenuBar is not derived from the AWT + * component. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingMenuBarPeer + implements MenuBarPeer +{ + + /** + * The AWT menu bar. + */ + MenuBar awtMenuBar; + + /** + * The Swing menu bar. + */ + SwingMenuBar menuBar; + + /** + * The peer of the frame that contains this menu bar. + */ + SwingFramePeer framePeer; + + /** + * A specialized JMenuBar that can be used as 'backend' for AWT MenuBars. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingMenuBar + extends JMenuBar + { + /** + * Overridden in order to provide a parent frame for this menu bar. The + * menu bar still is not inside the component hierarchy, we are faking + * here. + */ + public Container getParent() + { + Container result = null; + if (framePeer != null) + result = (Container) framePeer.awtComponent; + return result; + } + + /** + * Unconditionally returns <code>true</code>, since we assume that when the + * menubar has a peer, it must be showing. + * + * @return <code>true</code> + */ + public boolean isShowing() + { + // FIXME: This might be wrong. Maybe find a better way to do that. + return true; + } + + /** + * Handles mouse events by forwarding it to + * <code>processMouseEvent()</code>. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Determines the menubar's screen location by asking the SwingFramePeer + * for it. + * + * @return the screen location of the menu bar + */ + public Point getLocationOnScreen() + { + return framePeer.getMenuLocationOnScreen(); + } + } + + /** + * Creates a new <code>SwingMenuBarPeer</code> instance. + * + * @param awtMenuBar the AWT menu bar + */ + public SwingMenuBarPeer(MenuBar awtMenuBar) + { + this.awtMenuBar = awtMenuBar; + menuBar = new SwingMenuBar(); + menuBar.setDoubleBuffered(false); + // Add all the menus that are already in the MenuBar. + for (int i = 0; i < awtMenuBar.getMenuCount(); i++) + { + Menu menu = awtMenuBar.getMenu(i); + menu.addNotify(); + addMenu(awtMenuBar.getMenu(i)); + } + } + + /** + * Sets the <code>SwingFramePeer</code> of the frame that holds this menu. + * + * @param peer the <code>SwingFramePeer</code> to set + */ + public void setFramePeer(SwingFramePeer peer) + { + framePeer = peer; + } + + /** + * Adds a menu to the menu bar. + * + * @param m the menu to add + */ + public void addMenu(Menu m) + { + SwingMenuPeer menuPeer = (SwingMenuPeer) m.getPeer(); + menuBar.add(menuPeer.menu); + } + + /** + * Adds a help menu to the menu bar. + * + * @param m the menu to add + */ + public void addHelpMenu(Menu menu) + { + // FIXME: We should manage the help menu differently, so that it always + // appears at the rightmost position. + SwingMenuPeer menuPeer = (SwingMenuPeer) menu.getPeer(); + menuBar.add(menuPeer.menu); + } + + /** + * Removes the menu with the specified index. + * + * @param index the index of the menu to remove + */ + public void delMenu(int index) + { + menuBar.remove(index); + } + + /** + * Disposes this peer. This releases any reference to the AWT and Swing + * components. + */ + public void dispose() + { + menuBar = null; + awtMenuBar = null; + } + + /** + * Sets a font for the menu bar. + * + * @param font the font to set + */ + public void setFont(Font font) + { + menuBar.setFont(font); + } + + /** + * Sets the width of the menu bar. This is called from the top level + * component peers to adjust the width of the menubar when their sizes + * change. + * + * @param w the width to set + */ + public void setWidth(int w) + { + menuBar.setSize(w, menuBar.getPreferredSize().height); + menuBar.doLayout(); + } + + /** + * Paints the menu bar. + * + * @param g the graphics context to use for painting + */ + public void peerPaint(Graphics g) + { + menuBar.paint(g); + } + + /** + * Determines the height of the menubar. + * + * @return the height of the menu bar + */ + public int getHeight() + { + return menuBar.getPreferredSize().height; + } + + /** + * Handles mouse events. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + Point point = ev.getPoint(); + for (int i = 0; i < awtMenuBar.getMenuCount(); i++) + { + Menu menu = awtMenuBar.getMenu(i); + SwingMenuPeer peer = (SwingMenuPeer) menu.getPeer(); + int x1 = peer.getX(); + int x2 = x1 + peer.getWidth(); + if (point.x >= x1 && point.x <= x2) + { + ev.translatePoint(peer.getX(), peer.getY()); + peer.handleMouseEvent(ev); + break; + } + } + } + + /** + * Handles mouse motion events. + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + Point point = ev.getPoint(); + for (int i = 0; i < awtMenuBar.getMenuCount(); i++) + { + Menu menu = awtMenuBar.getMenu(i); + SwingMenuPeer peer = (SwingMenuPeer) menu.getPeer(); + int x1 = peer.getX(); + int x2 = x1 + peer.getWidth(); + if (point.x >= x1 && point.x <= x2) + { + ev.translatePoint(peer.getX(), peer.getY()); + peer.handleMouseMotionEvent(ev); + break; + } + } + } +} diff --git a/gnu/java/awt/peer/swing/SwingMenuItemPeer.java b/gnu/java/awt/peer/swing/SwingMenuItemPeer.java new file mode 100644 index 000000000..8b9d47ec0 --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingMenuItemPeer.java @@ -0,0 +1,157 @@ +/* SwingMenuItemPeer.java -- A Swing based peer for AWT menu items + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Font; +import java.awt.MenuItem; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.peer.MenuItemPeer; + +import javax.swing.JMenuItem; + +/** + * A Swing based peer for the AWT MenuItem. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingMenuItemPeer + implements MenuItemPeer +{ + /** + * The AWT menu item. + */ + MenuItem awtMenuItem; + + /** + * The Swing menu item. + */ + JMenuItem menuItem; + + /** + * Receives ActionEvents from the Swing menu item and forwards them + * to the ActionListeners of the AWT MenuItem. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingMenuItemListener implements ActionListener + { + + /** + * Receives notification when the action has been performed. + * + * @param event the action event + */ + public void actionPerformed(ActionEvent event) + { + event.setSource(awtMenuItem); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event); + } + + } + + /** + * Creates a new instance of <code>SwingMenuItemPeer</code>. + * + * @param awtMenuItem the AWT menu item + */ + public SwingMenuItemPeer(MenuItem awtMenuItem) + { + this.awtMenuItem = awtMenuItem; + menuItem = new JMenuItem(awtMenuItem.getLabel()); + menuItem.addActionListener(new SwingMenuItemListener()); + } + + /** + * Disables the menu item. + */ + public void disable() + { + menuItem.setEnabled(false); + } + + /** + * Enables the menu item. + */ + public void enable() + { + menuItem.setEnabled(true); + } + + /** + * Sets the enabled state to <code>enabled</code>. + * + * @param enabled if the menu item should be enabled or not + */ + public void setEnabled(boolean enabled) + { + menuItem.setEnabled(enabled); + } + + /** + * Sets the label for the menu item. + * + * @param text the label to set + */ + public void setLabel(String text) + { + menuItem.setText(text); + } + + /** + * Disposes the menu item. This releases any reference to the Swing and AWT + * menu item. + */ + public void dispose() + { + menuItem = null; + awtMenuItem = null; + } + + /** + * Sets the font for this menu item. + * + * @param font the font to set + */ + public void setFont(Font font) + { + menuItem.setFont(font); + } + +} diff --git a/gnu/java/awt/peer/swing/SwingMenuPeer.java b/gnu/java/awt/peer/swing/SwingMenuPeer.java new file mode 100644 index 000000000..ecb54a524 --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingMenuPeer.java @@ -0,0 +1,284 @@ +/* SwingMenuPeer.java -- A Swing based peer for AWT menus + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Font; +import java.awt.Menu; +import java.awt.MenuItem; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.awt.peer.MenuPeer; + +import javax.swing.JMenu; + +/** + * A Swing based peer for the AWT menu. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingMenuPeer + implements MenuPeer +{ + + /** + * The AWT menu. + */ + Menu awtMenu; + + /** + * The Swing menu. + */ + SwingMenu menu; + + /** + * A specialized JMenu that can be used as 'backend' for an AWT menu. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingMenu + extends JMenu + { + + /** + * Unconditionally returns <code>true</code>, since we assume that when the + * menu has a peer, it must be showing. + * + * @return <code>true</code> + */ + public boolean isShowing() + { + // FIXME: This might be wrong. Maybe find a better way to do that. + return true; + } + + /** + * Overridden so that we can provide a location even without a real peer + * attached. + * + * @return the screen location of this menu + */ + public Point getLocationOnScreen() + { + Point parentLoc = getParent().getLocationOnScreen(); + parentLoc.x += getX(); + parentLoc.y += getY(); + return parentLoc; + } + + /** + * Handles mouse events by forwarding them to + * <code>processMouseEvent()</code>. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Handles mouse events by forwarding them to + * <code>processMouseMotionEvent()</code>. + * + * @param ev the mouse event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseMotionEvent(ev); + } + } + + /** + * Creates a new <code>SwingMenuPeer</code> instance. + * + * @param awtMenu the AWT menu + */ + public SwingMenuPeer(Menu awtMenu) + { + this.awtMenu = awtMenu; + menu = new SwingMenu(); + menu.setDoubleBuffered(false); + menu.setText(awtMenu.getLabel()); + for (int i = 0; i < awtMenu.getItemCount(); i++) + { + MenuItem item = awtMenu.getItem(i); + item.addNotify(); + SwingMenuItemPeer peer = (SwingMenuItemPeer) item.getPeer(); + menu.add(peer.menuItem); + } + } + + /** + * Adds a menu item to this menu. + * + * @param item the menu item to add + */ + public void addItem(MenuItem item) + { + SwingMenuItemPeer menuItemPeer = (SwingMenuItemPeer) item.getPeer(); + menu.add(menuItemPeer.menuItem); + } + + /** + * Adds a separator to the menu. + */ + public void addSeparator() + { + menu.addSeparator(); + } + + /** + * Removes a menu item from the menu. + * + * @param index the index of the menu item to remove + */ + public void delItem(int index) + { + menu.remove(index); + } + + /** + * Disables the menu. + */ + public void disable() + { + menu.setEnabled(false); + } + + /** + * Enables the menu. + */ + public void enable() + { + menu.setEnabled(true); + } + + /** + * Sets the enabled state of the menu to <code>enabled</code>. + * + * @param enabled if the menu should be enabled or not + */ + public void setEnabled(boolean enabled) + { + menu.setEnabled(enabled); + } + + /** + * Sets the label of the menu. + * + * @param text the label to set + */ + public void setLabel(String text) + { + menu.setText(text); + } + + /** + * Releases any reference to the AWT and Swing menu instances. + */ + public void dispose() + { + menu = null; + awtMenu = null; + } + + /** + * Sets the font for the menu. + * + * @param font the font to set + */ + public void setFont(Font font) + { + menu.setFont(font); + } + + /** + * Handles mouse events by forwarding them to the Swing menu. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + menu.handleMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding them to the Swing menu. + * + * @param ev the mouse event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + menu.handleMouseMotionEvent(ev); + } + + /** + * Returns the X coordinate of the upper left corner of the menu. This is + * used internally by the SwingMenuBarPeer. + * + * @return the X coordinate of the upper left corner of the menu + */ + int getX() + { + return menu.getX(); + } + + /** + * Returns the width of the menu. This is used internally by the + * SwingMenuBarPeer. + * + * @return the X coordinate of the upper left corner of the menu + */ + int getWidth() + { + return menu.getWidth(); + } + + /** + * Returns the Y coordinate of the upper left corner of the menu. This is + * used internally by the SwingMenuBarPeer. + * + * @return the X coordinate of the upper left corner of the menu + */ + public int getY() + { + return menu.getY(); + } +} diff --git a/gnu/java/awt/peer/swing/SwingPanelPeer.java b/gnu/java/awt/peer/swing/SwingPanelPeer.java new file mode 100644 index 000000000..0a0f20fe8 --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingPanelPeer.java @@ -0,0 +1,67 @@ +/* SwingPanelPeer.java -- A PanelPeer based on Swing + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.swing; + +import java.awt.Panel; +import java.awt.peer.LightweightPeer; +import java.awt.peer.PanelPeer; + +/** + * A panel peer based on Swing. + * + * @author Roman Kennke (kennke@aicas.com) + */ +// TODO: Maybe base implementation on JPanel. However, this doesn't seem +// necessary, but might be good for more consistend Look. +public class SwingPanelPeer + extends SwingContainerPeer + implements PanelPeer, LightweightPeer +{ + + /** + * Creates a new instance of <code>SwingPanelPeer</code> for the specified + * AWT panel. + * + * @param panel the AWT panel + */ + public SwingPanelPeer(Panel panel) + { + super(panel); + } +} diff --git a/gnu/java/awt/peer/swing/SwingTextFieldPeer.java b/gnu/java/awt/peer/swing/SwingTextFieldPeer.java new file mode 100644 index 000000000..a4c6d82d2 --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingTextFieldPeer.java @@ -0,0 +1,367 @@ +/* SwingTextFieldPeer.java -- A Swing based peer for AWT textfields + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.java.awt.peer.swing; + +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextFieldPeer; + +import javax.swing.JComponent; +import javax.swing.JTextField; + +/** + * A TextFieldPeer based on Swing JTextField. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingTextFieldPeer + extends SwingComponentPeer + implements TextFieldPeer +{ + + /** + * A specialized Swing textfield for use in the peer. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingTextField + extends JTextField + implements SwingComponent + { + + /** + * Overridden to provide normal behaviour even without a real peer + * attached. + * + * @return the location of the textfield on screen + */ + public Point getLocationOnScreen() + { + return SwingTextFieldPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value for the + * swing button, even if it has no peer on its own. + * + * @return <code>true</code> if the button is currently showing, + * <code>false</code> otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (SwingTextFieldPeer.this.awtComponent != null) + retVal = SwingTextFieldPeer.this.awtComponent.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingTextFieldPeer.this.createImage(w, h); + } + + /** + * Returns this textfield. + * + * @return <code>this</code> + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to the swing textfield. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding it to the swing textfield. + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to the swing textfield. + * + * @param ev the key event + */ + public void handleKeyEvent(KeyEvent ev) + { + ev.setSource(this); + processKeyEvent(ev); + } + + } + + /** + * Creates a new <code>SwingTextFieldPeer</code> instance for the specified + * AWT textfield. + * + * @param textField the AWT textfield + */ + public SwingTextFieldPeer(TextField textField) + { + SwingTextField swingTextField = new SwingTextField(); + swingTextField.setText(textField.getText()); + init(textField, swingTextField); + } + + /** + * Returns the minimum size of the textfield. + * + * @param len not used here + * + * @return the minimum size of the textfield + */ + public Dimension minimumSize(int len) + { + return swingComponent.getJComponent().getMinimumSize(); + } + + /** + * Returns the preferred size of the textfield. + * + * @param len not used here + * + * @return the preferred size of the textfield + */ + public Dimension preferredSize(int len) + { + return swingComponent.getJComponent().getPreferredSize(); + } + + /** + * Returns the minimum size of the textfield. + * + * @param len not used here + * + * @return the minimum size of the textfield + */ + public Dimension getMinimumSize(int len) + { + return swingComponent.getJComponent().getMinimumSize(); + } + + /** + * Returns the preferred size of the textfield. + * + * @param len not used here + * + * @return the preferred size of the textfield + */ + public Dimension getPreferredSize(int len) + { + return swingComponent.getJComponent().getPreferredSize(); + } + + /** + * Sets the echo character. + * + * @param echoChar the echo character to be set + */ + public void setEchoChar(char echoChar) + { + // TODO: Must be implemented. + } + + /** + * Sets the echo character. + * + * @param echoChar the echo character to be set + */ + public void setEchoCharacter(char echoChar) + { + // TODO: Must be implemented. + } + + /** + * Returns the end index of the current selection. + * + * @return the end index of the current selection + */ + public int getSelectionEnd() + { + // TODO: Must be implemented. + return 0; + } + + /** + * Returns the start index of the current selection. + * + * @return the start index of the current selection + */ + public int getSelectionStart() + { + // TODO: Must be implemented. + return 0; + } + + /** + * Returns the current content of the textfield. + * + * @return the current content of the textfield + */ + public String getText() + { + return ((JTextField) swingComponent.getJComponent()).getText(); + } + + /** + * Sets the content of the textfield. + * + * @param text the text to set + */ + public void setText(String text) + { + ((JTextField) swingComponent.getJComponent()).setText(text); + } + + /** + * Sets the current selection. + * + * @param startPos the start index of the selection + * @param endPos the start index of the selection + */ + public void select(int start_pos, int endPos) + { + // TODO: Must be implemented. + } + + /** + * Sets the editable flag of the text field. + * + * @param editable <code>true</code> to make the textfield editable, + * <code>false</code> to make it uneditable + */ + public void setEditable(boolean editable) + { + ((JTextField) swingComponent.getJComponent()).setEditable(editable); + } + + /** + * Returns the current caret position. + * + * @return the current caret position + */ + public int getCaretPosition() + { + return ((JTextField) swingComponent.getJComponent()).getCaret().getDot(); + } + + /** + * Sets the current caret position. + * + * @param pos the caret position to set + */ + public void setCaretPosition(int pos) + { + ((JTextField) swingComponent.getJComponent()).getCaret().setDot(pos); + } + + /** + * Returns the index of the character at the specified location. + * + * @param x the X coordinate of the point to query + * @param y the Y coordinate of the point to query + * + * @return the index of the character at the specified location + */ + public int getIndexAtPoint(int x, int y) + { + // TODO: Must be implemented. + return 0; + } + + /** + * Returns the bounds of the character at the specified index. + * + * @param pos the index of the character + * + * @return the bounds of the character at the specified index + */ + public Rectangle getCharacterBounds(int pos) + { + // TODO: Must be implemented. + return null; + } + + /** + * Not used. + */ + public long filterEvents(long filter) + { + // TODO: Must be implemented. + return 0; + } + + /** + * Not used. + */ + public InputMethodRequests getInputMethodRequests() + { + // TODO: Must be implemented. + return null; + } + +} diff --git a/gnu/java/awt/peer/swing/SwingToolkit.java b/gnu/java/awt/peer/swing/SwingToolkit.java new file mode 100644 index 000000000..166e1f47b --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingToolkit.java @@ -0,0 +1,165 @@ +/* SwingToolkit.java -- A base toolkit for Swing peers + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.swing; + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.TextField; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.TextFieldPeer; + +import gnu.java.awt.ClasspathToolkit; + +/** + * A base implementation for {@link java.awt.Toolkit} that provides the + * Swing based widgets. Concrete implementations still must provide the + * remaining abstract methods. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public abstract class SwingToolkit extends ClasspathToolkit +{ + + /** + * Creates a SwingButtonPeer. + * + * @param button the AWT button + * + * @return the Swing button peer + */ + protected ButtonPeer createButton(Button button) + { + return new SwingButtonPeer(button); + } + + /** + * Creates a SwingCanvasPeer. + * + * @param canvas the AWT canvas + * + * @return the Swing canvas peer + */ + protected CanvasPeer createCanvas(Canvas canvas) + { + return new SwingCanvasPeer(canvas); + } + + /** + * Creates a SwingLabelPeer. + * + * @param label the AWT label + * + * @return the Swing label peer + */ + protected LabelPeer createLabel(Label label) + { + return new SwingLabelPeer(label); + } + + /** + * Creates a SwingMenuPeer. + * + * @param menu the AWT menu + * + * @return the Swing menu peer + */ + protected MenuPeer createMenu(Menu menu) + { + return new SwingMenuPeer(menu); + } + + /** + * Creates a SwingMenuBarPeer. + * + * @param menuBar the AWT menubar + * + * @return the Swing menu bar peer + */ + protected MenuBarPeer createMenuBar(MenuBar menuBar) + { + return new SwingMenuBarPeer(menuBar); + } + + /** + * Creates a SwingMenuItemPeer. + * + * @param menuItem the AWT menu item + * + * @return the Swing menu item peer + */ + protected MenuItemPeer createMenuItem(MenuItem menuItem) + { + return new SwingMenuItemPeer(menuItem); + } + + /** + * Creates a SwingPanelPeer. + * + * @param panel the AWT panel + * + * @return the Swing panel peer + */ + protected PanelPeer createPanel(Panel panel) + { + return new SwingPanelPeer(panel); + } + + /** + * Creates a SwingTextFieldPeer. + * + * @param textField the AWT text field + * + * @return the Swing text field peer + */ + protected TextFieldPeer createTextField(TextField textField) + { + return new SwingTextFieldPeer(textField); + } +} diff --git a/gnu/java/awt/peer/swing/SwingWindowPeer.java b/gnu/java/awt/peer/swing/SwingWindowPeer.java new file mode 100644 index 000000000..2f89795ca --- /dev/null +++ b/gnu/java/awt/peer/swing/SwingWindowPeer.java @@ -0,0 +1,72 @@ +/* SwingWindowPeer.java -- An abstract base for Swing based window peers + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Window; +import java.awt.peer.WindowPeer; + +/** + * An abstract base class for Swing based WindowPeer implementation. Concrete + * implementations of WindowPeers should subclass this class in order to get + * the correct behaviour. + * + * As a minimum, a subclass must implement all the remaining abstract methods + * as well as the following methods: + * <ul> + * <li>{@link ComponentPeer#getLocationOnScreen()}</li> + * <li>{@link ComponentPeer#getGraphics()}</li> + * <li>{@link ComponentPeer#createImage(int, int)}</li> + * </ul> + * + * @author Roman Kennke (kennke@aicas.com) + */ +public abstract class SwingWindowPeer + extends SwingContainerPeer + implements WindowPeer +{ + + /** + * Creates a new instance of WindowPeer. + * + * @param window the AWT window + */ + public SwingWindowPeer(Window window) + { + super(window); + } +} diff --git a/gnu/java/awt/peer/swing/package.html b/gnu/java/awt/peer/swing/package.html new file mode 100644 index 000000000..506eda883 --- /dev/null +++ b/gnu/java/awt/peer/swing/package.html @@ -0,0 +1,71 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in gnu.java.awt.peer.swing package. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> + <head> + <title>Swing based AWT peers + + +

Swing based AWT peers.

+

This package defines an abstract set of AWT peers that is based on Swing + widgets. This can be used as an implementation base for peer implementors + who don't have access to native widgets or who want to build a quick + prototype of a peer set without implementing all of the AWT widgets. +

+

An actual implementation would have to provide the following: +

    +
  • A concrete implementation of {@link java.awt.Toolkit}, possibly based + on {@link SwingToolkit}. This implementation must provide all the missing + methods of the SwingToolkit.
  • +
  • Concrete implementations of {@link java.awt.peer.DialogPeer}, + {@link java.awt.peer.FramePeer} and {@link java.awt.peer.WindowPeer}, + ideally based on their SwingXXXPeer counterparts. + Some methods must be specially + overridden in those peers to provide useful functionality, like + getLocationOnScreen(). See the API documentation for more + details
  • +
  • An implementation of {@link java.awt.Image}. These must be provided by + the toplevel component peers.
  • +
  • An implementation of {@link java.awt.Graphics}. This must also be + provided by the toplevel peers.
  • +
  • An implementation of {@link java.awt.Font}. This must be + provided by the toolkit.
  • +
+

+ + diff --git a/gnu/java/beans/DefaultExceptionListener.java b/gnu/java/beans/DefaultExceptionListener.java new file mode 100644 index 000000000..42b31fae8 --- /dev/null +++ b/gnu/java/beans/DefaultExceptionListener.java @@ -0,0 +1,66 @@ +/* gnu.java.beans.DefaultExceptionListener + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans; + +import java.beans.ExceptionListener; + +/** The DefaultExceptionListener is the default implementation of the + * {@link ExceptionListener} interface. An instance of + * this class is used whenever the user provided no + * ExceptionListener instance on its own. + * + *

The implementation just writes the exception's message + * to System.err and is used by the {@link java.beans.Encoder} + * and the {@link java.beans.XMLDecoder}. + *

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class DefaultExceptionListener implements ExceptionListener +{ + public final static DefaultExceptionListener INSTANCE + = new DefaultExceptionListener(); + + public void exceptionThrown(Exception e) + { + System.err.println("exception thrown: " + + e + " - message: " + + e.getMessage()); + } + +} diff --git a/gnu/java/beans/decoder/DefaultExceptionListener.java b/gnu/java/beans/decoder/DefaultExceptionListener.java deleted file mode 100644 index 71e7158e7..000000000 --- a/gnu/java/beans/decoder/DefaultExceptionListener.java +++ /dev/null @@ -1,57 +0,0 @@ -/* gnu.java.beans.DefaultExceptionListener - Copyright (C) 2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package gnu.java.beans.decoder; - -import java.beans.ExceptionListener; - -/** The DefaultExceptionListener is the default implementation of the ExceptionListener - * interface. An instance of this class is used whenever the user provided no - * ExceptionListener instance on its own. - * - *

The implementation just writes the exception's message to System.err.

- * - * @author Robert Schuster - */ -public class DefaultExceptionListener implements ExceptionListener -{ - public void exceptionThrown(Exception e) - { - System.err.println("non-critical exception: " + e + " - message: " - + e.getMessage()); - } -} diff --git a/gnu/java/lang/CharData.java b/gnu/java/lang/CharData.java index b12078d9f..a84d94da2 100644 --- a/gnu/java/lang/CharData.java +++ b/gnu/java/lang/CharData.java @@ -41,22 +41,26 @@ package gnu.java.lang; /** * This contains the info about the unicode characters, that * java.lang.Character needs. It is generated automatically from - * doc/unicode/UnicodeData-3.0.0.txt and - * doc/unicode/SpecialCasing-2.txt, by some - * perl scripts. These Unicode definition file can be found on the + * ../doc/unicode/UnicodeData-4.0.0.txt and + * ../doc/unicode/SpecialCasing-4.0.0.txt, by some + * perl scripts. These Unicode definition files can be found on the * http://www.unicode.org website. - * JDK 1.4 uses Unicode version 3.0.0. + * JDK 1.5 uses Unicode version 4.0.0. * * The data is stored as string constants, but Character will convert these - * Strings to their respective char[] components. The field + * Strings to their respective char[] components. The fields + * are stored in arrays of 17 elements each, one element per Unicode plane. * BLOCKS stores the offset of a block of 2SHIFT * characters within DATA. The DATA field, in turn, stores * information about each character in the low order bits, and an offset * into the attribute tables UPPER, LOWER, * NUM_VALUE, and DIRECTION. Notice that the * attribute tables are much smaller than 0xffff entries; as many characters - * in Unicode share common attributes. The DIRECTION table also contains - * a field for detecting characters with multi-character uppercase expansions. + * in Unicode share common attributes. Numbers that are too large to fit + * into NUM_VALUE as 16 bit chars are stored in LARGENUMS and a number N is + * stored in NUM_VALUE such that (-N - 3) is the offset into LARGENUMS for + * the particular character. The DIRECTION table also contains a field for + * detecting characters with multi-character uppercase expansions. * Next, there is a listing for TITLE exceptions (most characters * just have the same title case as upper case). Finally, there are two * tables for multi-character capitalization, UPPER_SPECIAL @@ -73,208 +77,622 @@ public interface CharData /** * The Unicode definition file that was parsed to build this database. */ - String SOURCE = "doc/unicode/UnicodeData-3.0.0.txt"; + String SOURCE = "../doc/unicode/UnicodeData-4.0.0.txt"; /** * The character shift amount to look up the block offset. In other words, - * (char) (BLOCKS.value[ch >> SHIFT] + ch) is the index where - * ch is described in DATA. + * (char) (BLOCKS.value[ch >> SHIFT[p]] + ch) is the index + * where ch is described in DATA if ch + * is in Unicode plane p. Note that p is simply + * the integer division of ch and 0x10000. */ - int SHIFT = 5; + int[] SHIFT + = new int[] {4, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8}; /** * The mapping of character blocks to their location in DATA. * Each entry has been adjusted so that the 16-bit sum with the desired * character gives the actual index into DATA. */ - String BLOCKS - = "\u01c2\u01c2\u01c1\u012c\u012b\u01a0\u01f8\u02dc\u025f\u02ee\u0215" - + "\u0346\u02dc\u0326\u02bc\u0216\u015f\u02d4\u0376\u0376\u0376\u0369" - + "\ufe8f\u0344\uff85\uff65\ufdb5\ufda1\033\u02c4\034G\ufea8" - + "\uff8c\u0235\ufeff\032\ufebf&\ufb20\ufe28\u0113\u0104\ufb61" - + "\ufb5a\u010b\u0109\u00fe\uff08\u0229\u025e\u01c7\u01fc\u01dc\ufc46" - + "\u0229\ufe27\ufb55\u0169\ufbc8\u00fc\u0103\ufb68\ufb48\ufb28\ufb08" - + "\ufae8\ufac8\ufaa8\ufa88\ufa68\ufa48eP\u00ab\u0139\ufe0e" - + "c\u0155\u01a8\uf669\u0129\u0128\uf91f\ufe56\u0108\u0107\ufac0" - + "\ufc8e\ufead\u00c6\ufca7\ufb95\uf47d\u009f\ufb17\ufe20\ufd28\ufb2f" - + ";\uf3b9\ufe57\ufcce\uffbb\uf339\ufa98\uff8b\uff3b\ufa54\uf7e3" - + "\uff2b\ufad7\ufb69\ufc3a\ufee5\uf4c8\ufcb0\ufa88\ufdbf\uf448\ufe45" - + "\ufcc7\ufe4f\uf7f1\uf715\uf2e8\ufd9f\uf348\uf96a\ufc02\ufd97\uf2c8" - + "\uf2a8\uf4b9\uf4b3\uef6b\uf86a\uf84a\ufc58\uf80a\uf7ea\ufc0f\uf7aa" - + "\uee9c\ufb90\uf74a\uf7fa\uf70a\uf7ca\uf792\uf471\uf4d2\uf732\uf64a" - + "\uf401\uf64d\uefa8\uf5ca\uf5aa\ueca1\uf569\uf54a\uf52a\uf50a\uf4ea" - + "\uf4ca\uf4aa\uf48a\uf46a\uf44a\uf42a\uf40a\uf3ea\uf3ca\uf3aa\uf38a" - + "\uf36a\uf34a\uf32a\uf289\uf777\uf2ca\uf2aa\uf737\uec28\uec08\uebe8" - + "\uebc8\uf1ea\uf4a2\uf545\uedc6\uf2d7\uf14a\ue8ed\ue81e\uf0ea\uf597" - + "\uea68\uea48\uea28\uea08\ue9e8\ue9c8\ue9a8\ue988\ue968\ue948\ue928" - + "\ue908\ue8e8\ue8c8\ue8a8\ue888\ue868\ue848\ue828\ue808\ue7e8\ue7c8" - + "\ue7a8\ue788\ue768\ue748\ue728\ue708\ue6e8\ue6c8\ue6a8\ue688\ue668" - + "\ue648\ue628\ue608\ue5e8\ue5c8\ue5a8\ue588\ue568\ue548\ue55f\ue53f" - + "\ue51f\ue4ff\uefd7\ue4bf\ue49f\ue485\uef87\uef57\uef57\uef57\uef57" - + "\uef47\ue1ad\uef46\uef46\uef46\ue1e0\ue3dd\uef06\ue9d9\uebeb\ue244" - + "\ueed4\uef65\ue1f5\uef45\ueee9\uef7c\uee74\uef70\uef7d\uef78\uee91" - + "\uefd3\uee7d\uee25\uee27\uef65\uefdd\uee96\uefd3\uefe1\uef69\udf88" - + "\udf68\udf48\ued2b\ued3d\ued19\uef1c\uef08\ued47\ued3d\ued33\uec2b" - + "\uec0b\uebeb\uebcb\uebce\uea7c\ueb69\ueb6c\ue9b6\ueb0b\ueaeb\ue9e9" - + "\udca8\udc88\udc68\udc48\ue910\uea23\ueb58\ueb4f\ueb45\ueae5\udb68" - + "\udb48\ue92b\ue90b\ue8eb\ue8cb\ue8ab\ue88b\ue86b\ue84b\uda28\uda08" - + "\ud9e8\ud9c8\ud9a8\ud988\ud968\ud948\ud928\ud908\ud8e8\ud8c8\ud8a8" - + "\ud888\ud868\ud848\ud828\ud808\ud7e8\ud7c8\ud7a8\ud788\ud768\ud748" - + "\ud728\ud708\ud6e8\ud6c8\ud6a8\ud688\ud668\ud648\ud628\ud608\ud5e8" - + "\ud5c8\ud5a8\ud588\ud568\ud548\ud528\ud508\ud4e8\ud4c8\ue2b1\ue28b" - + "\ue26b\ue270\ue22b\ue20b\ue1eb\ue1cb\ue1ab\ue18b\ue18e\udd8f\ue3a8" - + "\udfd3\ud929\ud90a\ue348\ud8c9\ud8aa\udcd7\udcb2\ud681\ud82a\ud80a" - + "\ue268\ucede\ud168\ud148\ue116\ue0e9\ue1cb\ue0b7\ue0b7\ue15e\udf17" - + "\ue034\ue013\udff3\udfd3\ude6c\udf93\udf73\udf55\udf34\ud56a\ud54a" - + "\ud52a\ud50a\ud4ea\ud4ca\ud4aa\ud48a\ud46a\ud44a\ud42a\ud40a\ud3ea" - + "\ud3ca\ud3aa\ud38a\ud36a\ud34a\ud32a\ud30a\ud2ea\ud2ca\ud2aa\ud28a" - + "\ud26a\ud24a\ud22a\ud20a\ud1ea\ud1ca\ud1aa\ud18a\ud16a\ud14a\ud12a" - + "\ud10a\ud0ea\ud0ca\ud0aa\ud08a\ud06a\ud04a\ud02a\ud00a\ucfea\ucfca" - + "\ucfaa\ucf8a\ucf6a\ucf4a\ucf2a\ucf0a\uceea\uceca\uceaa\uce8a\uce6a" - + "\uce4a\uce2a\uce0a\ucdea\ucdca\ucdaa\ucd8a\ucd6a\ucd4a\ucd2a\ucd0a" - + "\uccea\uccca\uccaa\ucc8a\ucc6a\ucc4a\ucc2a\ucc0a\ucbea\ucbca\ucbaa" - + "\ucb8a\ucb6a\ucb4a\ucb2a\ucb0a\ucaea\ucaca\ucaaa\uca8a\uca6a\uca4a" - + "\uca2a\uca0a\uc9ea\uc9ca\uc9aa\uc98a\uc96a\uc94a\uc92a\uc90a\uc8ea" - + "\uc8ca\uc8aa\uc88a\uc86a\uc84a\uc82a\uc80a\uc7ea\uc7ca\uc7aa\uc78a" - + "\uc76a\uc74a\uc72a\uc70a\uc6ea\uc6ca\uc6aa\uc68a\uc66a\uc64a\uc62a" - + "\uc60a\uc5ea\uc5ca\uc5aa\uc58a\uc56a\uc54a\uc52a\uc50a\uc4ea\uc4ca" - + "\uc4aa\uc48a\uc46a\uc44a\uc42a\uc40a\uc3ea\uc3ca\uc3aa\uc38a\uc36a" - + "\uc34a\uc32a\uc30a\uc2ea\uc2ca\uc2aa\uc28a\uc26a\uc24a\uc22a\uc20a" - + "\uc1ea\uc1ca\uc1aa\uc18a\uc16a\uc14a\uc12a\uc10a\uc0ea\uc0ca\uc0aa" - + "\uc08a\uc06a\uc04a\uc02a\uc00a\ubfea\ubfca\ubfaa\ubf8a\ubf6a\ubf4a" - + "\ubf2a\ubf0a\ubeea\ubeca\ubeaa\ube8a\ube6a\ube4a\ube2a\ube0a\ubdea" - + "\ubdca\ubdaa\ubd8a\ubd6a\ubd4a\ubd2a\ubd0a\ubcea\ubcca\ubcaa\ubc8a" - + "\ubc6a\ubc4a\ubc2a\ubc0a\ubbea\ub2e0\ub568\ub548\ubb6a\ubb4a\ubb2a" - + "\ubb0a\ubaea\ubaca\ubaaa\uba8a\uba6a\uba4a\uba2a\uba0a\ub9ea\ub9ca" - + "\ub9aa\ub98a\ub96a\ub94a\ub92a\ub90a\ub8ea\ub8ca\ub8aa\ub88a\ub86a" - + "\ub84a\ub82a\ub80a\ub7ea\ub7ca\ub7aa\ub78a\ub76a\ub74a\ub72a\ub70a" - + "\ub6ea\ub6ca\ub6aa\ub68a\ub66a\ub64a\ub62a\ub60a\ub5ea\ub5ca\ub5aa" - + "\ub58a\ub56a\ub54a\ub52a\ub50a\ub4ea\ub4ca\ub4aa\ub48a\ub46a\ub44a" - + "\ub42a\ub40a\ub3ea\ub3ca\ub3aa\ub38a\ub36a\ub34a\ub32a\ub30a\ub2ea" - + "\ub2ca\ub2aa\ub28a\ub26a\ub24a\ub22a\ub20a\ub1ea\ub1ca\ub1aa\ub18a" - + "\ub16a\ub14a\ub12a\ub10a\ub0ea\ub0ca\ub0aa\ub08a\ub06a\ub04a\ub02a" - + "\ub00a\uafea\uafca\uafaa\uaf8a\uaf6a\uaf4a\uaf2a\uaf0a\uaeea\uaeca" - + "\uaeaa\uae8a\uae6a\uae4a\uae2a\uae0a\uadea\uadca\uadaa\uad8a\uad6a" - + "\uad4a\uad2a\uad0a\uacea\uacca\uacaa\uac8a\uac6a\uac4a\uac2a\uac0a" - + "\uabea\uabca\uabaa\uab8a\uab6a\uab4a\uab2a\uab0a\uaaea\uaaca\uaaaa" - + "\uaa8a\uaa6a\uaa4a\uaa2a\uaa0a\ua9ea\ua9ca\ua9aa\ua98a\ua96a\ua94a" - + "\ua92a\ua90a\ua8ea\ua8ca\ua8aa\ua88a\ua86a\ua84a\ua82a\ua80a\ua7ea" - + "\ua7ca\ua7aa\ua78a\ua76a\ua74a\ua72a\ua70a\ua6ea\ua6ca\ua6aa\ua68a" - + "\ua66a\ua64a\ua62a\ua60a\ua5ea\ua5ca\ua5aa\ua58a\ua56a\ua54a\ua52a" - + "\ua50a\ua4ea\ua4ca\ua4aa\ua48a\ua46a\ua44a\ua42a\ua40a\ua3ea\ua3ca" - + "\ua3aa\ua38a\ua36a\ua34a\ua32a\ua30a\ua2ea\ua2ca\ua2aa\ua28a\ua26a" - + "\ua24a\ua22a\ua20a\ua1ea\ua1ca\ua1aa\ua18a\ua16a\ua14a\ua12a\ua10a" - + "\ua0ea\ua0ca\ua0aa\ua08a\ua06a\ua04a\ua02a\ua00a\u9fea\u9fca\u9faa" - + "\u9f8a\u9f6a\u9f4a\u9f2a\u9f0a\u9eea\u9eca\u9eaa\u9e8a\u9e6a\u9e4a" - + "\u9e2a\u9e0a\u9dea\u9dca\u9daa\u9d8a\u9d6a\u9d4a\u9d2a\u9d0a\u9cea" - + "\u9cca\u9caa\u9c8a\u9c6a\u9c4a\u9c2a\u9c0a\u9bea\u9bca\u9baa\u9b8a" - + "\u9b6a\u9b4a\u9b2a\u9b0a\u9aea\u9aca\u9aaa\u9a8a\u9a6a\u9a4a\u9a2a" - + "\u9a0a\u99ea\u99ca\u99aa\u998a\u996a\u994a\u992a\u990a\u98ea\u98ca" - + "\u98aa\u988a\u986a\u984a\u982a\u980a\u97ea\u97ca\u97aa\u978a\u976a" - + "\u974a\u972a\u970a\u96ea\u96ca\u96aa\u968a\u966a\u964a\u962a\u960a" - + "\u95ea\u95ca\u95aa\u958a\u956a\u954a\u952a\u950a\u94ea\u94ca\u94aa" - + "\u948a\u946a\u944a\u942a\u940a\u93ea\u93ca\u93aa\u938a\u936a\u934a" - + "\u932a\u930a\u92ea\u92ca\u92aa\u928a\u926a\u924a\u922a\u920a\u91ea" - + "\u91ca\u91aa\u918a\u916a\u914a\u912a\u910a\u90ea\u90ca\u90aa\u908a" - + "\u906a\u904a\u902a\u900a\u8fea\u8fca\u8faa\u8f8a\u8f6a\u8f4a\u8f2a" - + "\u8f0a\u8eea\u8eca\u8eaa\u8e8a\u8e6a\u8e4a\u8e2a\u8e0a\u8dea\u8dca" - + "\u8daa\u8d8a\u8d6a\u8d4a\u8d2a\u8d0a\u8cea\u8cca\u8caa\u8c8a\u8c6a" - + "\u8c4a\u8c2a\u8c0a\u8bea\u8bca\u8baa\u8b8a\u8b6a\u8b4a\u8b2a\u8b0a" - + "\u8aea\u8aca\u8aaa\u8a8a\u8a6a\u8a4a\u8a2a\u8a0a\u89ea\u89ca\u89aa" - + "\u898a\u896a\u894a\u892a\u890a\u88ea\u88ca\u88aa\u888a\u886a\u884a" - + "\u882a\u880a\u87ea\u87ca\u87aa\u878a\u876a\u874a\u872a\u870a\u86ea" - + "\u86ca\u86aa\u868a\u866a\u864a\u862a\u860a\u85ea\u85ca\u85aa\u858a" - + "\u856a\u854a\u852a\u850a\u84ea\u84ca\u84aa\u848a\u846a\u844a\u842a" - + "\u840a\u83ea\u83ca\u83aa\u838a\u836a\u834a\u832a\u830a\u82ea\u82ca" - + "\u82aa\u828a\u826a\u824a\u822a\u820a\u81ea\u81ca\u81aa\u818a\u816a" - + "\u814a\u812a\u810a\u80ea\u80ca\u80aa\u808a\u806a\u804a\u802a\u800a" - + "\u7fea\u7fca\u7faa\u7f8a\u7f6a\u7f4a\u7f2a\u7f0a\u7eea\u7eca\u7eaa" - + "\u7e8a\u7e6a\u7e4a\u7e2a\u7e0a\u7dea\u7dca\u7daa\u7d8a\u7d6a\u7d4a" - + "\u7d2a\u7d0a\u7cea\u7cca\u7caa\u7c8a\u7c6a\u7c4a\u7c2a\u7c0a\u7bea" - + "\u7bca\u7baa\u7b8a\u7b6a\u7b4a\u7b2a\u7b0a\u7aea\u7aca\u7aaa\u7a8a" - + "\u7a6a\u7a4a\u7a2a\u7a0a\u79ea\u79ca\u79aa\u798a\u796a\u794a\u792a" - + "\u790a\u78ea\u78ca\u78aa\u788a\u786a\u784a\u782a\u780a\u77ea\u77ca" - + "\u77aa\u778a\u776a\u774a\u772a\u770a\u76ea\u76ca\u76aa\u768a\u766a" - + "\u764a\u762a\u760a\u75ea\u75ca\u75aa\u758a\u756a\u754a\u752a\u750a" - + "\u74ea\u74ca\u74aa\u748a\u746a\u744a\u742a\u740a\u73ea\u73ca\u73aa" - + "\u738a\u736a\u734a\u732a\u730a\u72ea\u72ca\u72aa\u728a\u726a\u724a" - + "\u722a\u720a\u71ea\u71ca\u71aa\u718a\u716a\u714a\u712a\u710a\u70ea" - + "\u70ca\u70aa\u708a\u706a\u704a\u702a\u700a\u6fea\u6fca\u6faa\u6f8a" - + "\u6f6a\u6f4a\u6f2a\u6f0a\u6eea\u6eca\u6eaa\u6e8a\u6e6a\u6e4a\u6e2a" - + "\u6e0a\u6dea\u6dca\u6daa\u6d8a\u6d6a\u6d4a\u6d2a\u6d0a\u6cea\u6cca" - + "\u6caa\u6c8a\u6c6a\u6c4a\u6c2a\u6c0a\u6bea\u6bca\u6baa\u6b8a\u6b6a" - + "\u6b4a\u6b2a\u6b0a\u6aea\u6aca\u6aaa\u6a8a\u6a6a\u6a4a\u6a2a\u6a0a" - + "\u69ea\u60f0\u6368\u6348\u696a\u694a\u692a\u690a\u68ea\u68ca\u68aa" - + "\u688a\u686a\u684a\u682a\u680a\u67ea\u67ca\u67aa\u678a\u676a\u674a" - + "\u672a\u670a\u66ea\u66ca\u66aa\u668a\u666a\u664a\u662a\u660a\u65ea" - + "\u65ca\u65aa\u658a\u656a\u654a\u652a\u650a\u6b26\u6de1\u6e9c\u5e48" - + "\u5e28\u5e08\u5de8\u5dc8\u5da8\u5d88\u5d68\u5d48\u5d28\u5d08\u5ce8" - + "\u5cc8\u5ca8\u5c88\u5c68\u5c48\u5c28\u5c08\u5be8\u5bc8\u5ba8\u5b88" - + "\u5b68\u5b48\u5b28\u5b08\u5ae8\u5ac8\u5aa8\u5a88\u5a68\u5a48\u5a28" - + "\u5a08\u59e8\u59c8\u59a8\u5988\u5968\u5948\u5928\u5908\u58e8\u58c8" - + "\u58a8\u5888\u5868\u5848\u5828\u5808\u57e8\u57c8\u57a8\u5788\u5768" - + "\u5748\u5d6a\u5d4a\u5d2a\u5d0a\u5cea\u5cca\u5caa\u5c8a\u5c6a\u5c4a" - + "\u5c2a\u5c0a\u5bea\u5bca\u5baa\u5b8a\u5b6a\u5b4a\u5b2a\u5b0a\u5aea" - + "\u5aca\u5aaa\u5a8a\u5a6a\u5a4a\u5a2a\u5a0a\u59ea\u59ca\u59aa\u598a" - + "\u596a\u594a\u592a\u590a\u58ea\u58ca\u58aa\u588a\u586a\u584a\u582a" - + "\u580a\u57ea\u57ca\u57aa\u578a\u576a\u574a\u572a\u570a\u56ea\u56ca" - + "\u56aa\u568a\u566a\u564a\u562a\u560a\u55ea\u55ca\u55aa\u558a\u556a" - + "\u554a\u552a\u550a\u54ea\u54ca\u54aa\u548a\u546a\u544a\u542a\u540a" - + "\u53ea\u53ca\u53aa\u538a\u536a\u534a\u532a\u530a\u52ea\u52ca\u52aa" - + "\u528a\u526a\u524a\u522a\u520a\u51ea\u51ca\u51aa\u518a\u516a\u514a" - + "\u512a\u510a\u50ea\u50ca\u50aa\u508a\u506a\u504a\u502a\u500a\u4fea" - + "\u4fca\u4faa\u4f8a\u4f6a\u4f4a\u4f2a\u4f0a\u4eea\u4eca\u4eaa\u4e8a" - + "\u4e6a\u4e4a\u4e2a\u4e0a\u4dea\u4dca\u4daa\u4d8a\u4d6a\u4d4a\u4d2a" - + "\u4d0a\u4cea\u4cca\u4caa\u4c8a\u4c6a\u4c4a\u4c2a\u4c0a\u4bea\u4bca" - + "\u4baa\u4b8a\u4b6a\u4b4a\u4b2a\u4b0a\u4aea\u4aca\u4aaa\u4a8a\u4a6a" - + "\u4a4a\u4a2a\u4a0a\u49ea\u49ca\u49aa\u498a\u496a\u494a\u492a\u490a" - + "\u48ea\u48ca\u48aa\u488a\u486a\u484a\u482a\u480a\u47ea\u47ca\u47aa" - + "\u478a\u476a\u474a\u472a\u470a\u46ea\u46ca\u46aa\u468a\u466a\u464a" - + "\u462a\u460a\u45ea\u45ca\u45aa\u458a\u456a\u454a\u452a\u450a\u44ea" - + "\u44ca\u44aa\u448a\u446a\u444a\u442a\u440a\u43ea\u43ca\u43aa\u438a" - + "\u436a\u434a\u432a\u430a\u42ea\u42ca\u42aa\u428a\u426a\u424a\u422a" - + "\u420a\u41ea\u41ca\u41aa\u418a\u416a\u414a\u412a\u410a\u40ea\u40ca" - + "\u40aa\u408a\u406a\u404a\u402a\u400a\u3fea\u3fca\u3faa\u3f8a\u3f6a" - + "\u3f4a\u3f2a\u3f0a\u3eea\u3eca\u3eaa\u3e8a\u3e6a\u3e4a\u3e2a\u3e0a" - + "\u3dea\u3dca\u3daa\u3d8a\u3d6a\u3d4a\u3d2a\u3d0a\u3cea\u3cca\u3caa" - + "\u3c8a\u3c6a\u3c4a\u3c2a\u3c0a\u3bea\u3bca\u3baa\u3b8a\u3b6a\u3b4a" - + "\u3b2a\u3b0a\u3aea\u3aca\u3aaa\u3a8a\u3a6a\u3a4a\u3a2a\u3a0a\u39ea" - + "\u39ca\u39aa\u398a\u396a\u394a\u392a\u390a\u38ea\u38ca\u38aa\u388a" - + "\u386a\u384a\u382a\u380a\u37ea\u37ca\u37aa\u378a\u376a\u374a\u372a" - + "\u370a\u36ea\u36ca\u36aa\u368a\u366a\u364a\u362a\u360a\u35ea\u35ca" - + "\u35aa\u358a\u356a\u354a\u352a\u350a\u34ea\u34ca\u34aa\u348a\u346a" - + "\u344a\u342a\u340a\u33ea\u33ca\u33aa\u338a\u336a\u334a\u332a\u330a" - + "\u32ea\u32ca\u32aa\u328a\u326a\u324a\u322a\u320a\u31ea\u28f2\u2b68" - + "\u2b48\u3c2b\u3c0b\u3beb\u3bcb\u3bab\u3b8b\u3b6b\u3b4b\u3b2b\u3b0b" - + "\u3aeb\u3acb\u3aab\u3a8b\u3a6b\u3a4b\u3a2b\u3a0b\u39eb\u39cb\u39ab" - + "\u398b\u396b\u394b\u392b\u390b\u38eb\u38cb\u38ab\u388b\u386b\u384b" - + "\u382b\u380b\u37eb\u37cb\u37ab\u378b\u376b\u374b\u372b\u370b\u36eb" - + "\u36cb\u36ab\u368b\u366b\u364b\u362b\u360b\u35eb\u35cb\u35ab\u358b" - + "\u356b\u354b\u352b\u350b\u34eb\u34cb\u34ab\u348b\u346b\u344b\u344b" - + "\u342b\u340b\u33eb\u33cb\u33ab\u338b\u336b\u334b\u332b\u330b\u32eb" - + "\u32cb\u32ab\u328b\u326b\u324b\u322b\u320b\u31eb\u31cb\u31ab\u318b" - + "\u316b\u314b\u312b\u310b\u30eb\u30cb\u30ab\u308b\u306b\u304b\u302b" - + "\u300b\u2feb\u2fcb\u2fab\u2f8b\u2f6b\u2f4b\u2f2b\u2f0b\u2eeb\u2ecb" - + "\u2eab\u2e8b\u2e6b\u2e4b\u2e2b\u2e0b\u2deb\u2dcb\u2dab\u2d8b\u2d6b" - + "\u2d4b\u2d2b\u2d0b\u2ceb\u2ccb\u2cab\u2c8b\u2c6b\u2c4b\u2c2b\u2c0b" - + "\u2beb\u2bcb\u2bab\u2b8b\u2b6b\u2b4b\u2b2b\u2b0b\u2aeb\u2acb\u2aab" - + "\u2a8b\u2a6b\u2a4b\u2a2b\u2a0b\u29eb\u29cb\u29ab\u298b\u296b\u294b" - + "\u292b\u290b\u28eb\u28cb\u28ab\u288b\u286b\u284b\u282b\u280b\u27eb" - + "\u27cb\u27ab\u278b\u276b\u274b\u272b\u270b\u26eb\u26cb\u26ab\u268b" - + "\u266b\u264b\u262b\u260b\u25eb\u25cb\u25ab\u258b\u256b\u254b\u252b" - + "\u250b\u24eb\u24cb\u24ab\u248b\u246b\u244b\u242b\u240b\u23eb\u23cb" - + "\u23ab\u238b\u236b\u234b\u232b\u230b\u22eb\u22cb\u22ab\u228b\u226b" - + "\u224b\u222b\u220b\u21eb\u21cb\u21ab\u218b\u216b\u214b\u212b\u210b" - + "\u20eb\u20cb\u20ab\u208b\u206b\u204b\u202b\u200b\u1feb\u1fcb\u1fab" - + "\u1f8b\u1f6b\u1f4b\u1f2b\u1f0b\u1eeb\u1ecb\u1eab\u1e8b\u1e6b\u1e4b" - + "\u1e2b\u1e0b\u1deb\u1dcb\u1dab\u1d8b\u1d6b\u1d4b\u1d2b\u1d0b\u1ceb" - + "\u1ccb\u1cab\u1c8b\u1c6b\u1c4b\u1c2b\u1c0b\u1beb\u1bcb\u1bab\u1b8b" - + "\u1b6b\u106a\u104a\u102a\u100a\u0fea\u0fca\u0faa\u0f8a\u0f6a\u0668" - + "\u08e8\u08c8\u08a8\u0888\u0868\u0848\u07d7\u194b\u07b6\u0d1c\u0cfc" - + "\u0cb2\u0ca9\u0c9c\u0c7c\u0c5c\u0c3c\u0c1c\u0bfc\u0bdc\u0bbc\u0b9c" - + "\u0b7c\u0b5e\u0b2c\u0b1c\u0ab8\u0adc\u0a9c\u02c2\u0528\u166b\u1667" - + "\u03ff\u09fc\u09dc\u09bc\u0659\u0bb8\u15a7\u0fc6\u01c0\u01b1\u09cb" - + "\u082c\u1285"; + String[] BLOCKS = new String[]{ + "\017\0275\00744Z\uff90\uff9d\uff93\013" + + "\uffb5\013\004\034\025\027\007\ufff7\u00ad\u010d\uffc7" + + "\uffb7\uff7b\u0111\u0111\u00b7\u0101\uffdc\uff4a\uff37\ufef3\uff17" + + "\uff07\ufef5\uff79\u00dc2\u0141\005\uffe7\u013d\u0130\u0137" + + "\u0163\u0163\u0112\u0145\u0166\u0156\u0146\u0136\uff81\u0191\u0106" + + "\ufe84\u01ca\ufd3a\u01ba\ufd4b\u01aa\ufe74\ufd37\u014e\u01b3\ufcbb" + + "\ufcab\ufccc\ufcbc\u0173\ufcb7\ufca7\ufca8\ufc87\ufc77\ufc67\u0113" + + "\ufc47\ufc37\ufc42\ufc17\ufe0c\ufdfc\ufcd3\ufcc4\ufcbd\ufe0a\ufdfb" + + "\ufdf4\ufed5\ufec3\ufd17\ufd15\u008a\u007f\u00b5\ufdb1\u00dc\ufd6e" + + "\u00f9\u00cb\uffe3k\u00f9\ufd0f\ufcff\ufcef\ufcdf\ufccf\011" + + "\u00abi\ufffbX\ufc6f\ufd36\uffd6\ufbcc\ufbbc\ufbac\ufc0f" + + "\ufbff\uff70\ufff9\ufb5c\ufb4c\ufb3c\ufb2c\ufb1c\ufb0c\ufafc\ufaec" + + "\ufadc\ufacc\ufabc\ufaac\ufa9c\ufa8c\ufa7c\ufa6c\ufa5c\ufa4c\ufa3c" + + "\ufa2c\ufee1\ufb03\ufaf3\ufef3\ufcd4\uff0b\uff13\uf9ab\ufb8a\uf7fa" + + "\ufa69\ufbe5\ufb6e\uf90e\ufea9\ufeaf\ufb79\uf77a\uf9e9\uf8c7\ufdfc" + + "\uf760\ufb82\ufe3f\uf6e4\uf980\uf969\uf70e\ufbc6\uf764\ufda9\ufddd" + + "\ufa0a\uf67a\uf8e9\ufb48\uf68d\uf5ec\ufd91\uf6c3\uf7c4\uf75b\uf7af" + + "\uf75b\uf93b\ufade\ufb5b\ufd17\uf704\uf801\uf7e9\ufba4\ufcd7\uf72f" + + "\ufc91\uf6ac\ufb4b\uf781\uf769\ufc77\ufb71\uf99a\ufc11\uf62c\ufacb" + + "\uf701\uf6e9\ufa8f\ufbf7\uf95e\ufb91\uf5ac\ufbd4\uf3eb\uf673\uf7da" + + "\ufb87\uf832\uf53c\uf527\uf612\uf603\uf5f3\ufa8f\ufa9d\ufa29\uf4bc" + + "\uf4ac\uf2c7\uf6f4\uf678\ufab9\ufab9\uf9bf\uf43c\uf42c\ufa89\uf30a" + + "\uf6c8\uf6c4\uf4ca\uf4c3\uf89b\uf57d\uf967\uf4cd\uf4c6\uf4b9\uf264" + + "\uf34c\uf33c\uf32c\uf413\uf403\uf502\uf969\uf8b7\uf959\uf2bc\uf2ac" + + "\uf29c\uf28c\uf927\uf917\uf911\uf343\uf333\uf773\uf313\uf303\uf2f3" + + "\uf2e3\uf2d3\uf6ac\uf2b3\uf2a3\uf293\uf283\uf663\uf263\uf253\uf243" + + "\uf233\uf7f1\uf20b\uf203\uf1f3\uf1e3\uef2b\uef1b\uf1b3\uf1a3\ueeeb" + + "\uf183\uf163\ueec3\ueeb3\uf13b\uf123\uf123\uf103\uee63\uf0f3\uf0e3" + + "\uf0cb\uf4ab\uf2c3\uf3d9\uef9c\uef8c\uf073\uf063\uf053\uf043\uf033" + + "\uf5f6\uf012\uf003\ueff3\uefe3\uefd3\uefc3\uefb3\uefa3\uef93\uef83" + + "\uef73\uef63\uef53\uef43\uef33\uef23\uef13\uef03\ueef3\ueee3\ueed3" + + "\ueec3\ueeb3\ueea3\uee93\uee83\uee73\uee63\uee53\uee43\uee33\uee23" + + "\uee13\uee03\uedf3\uede3\uedd3\uedc3\ueb2d\uf374\uf176\uf156\ued73" + + "\ued63\ued53\ued43\uf279\uf307\ued05\uf2f7\uecf3\uf2e7\uecd3\uf2d7" + + "\ueca5\uf2c7\uec93\uec83\uec73\uf297\uee4c\uf292\ueb56\uf291\uf291" + + "\ueb26\uebf3\uebe3\uefda\uebc3\uebb3\uf173\ueb93\ueb83\uf201\uea6c" + + "\uea5c\uea4c\uea3c\uea2c\ueb13\ueee9\uf132\uec73\ue9f0\ueac3\uee98" + + "\uf076\ue99c\ue98c\ue97c\ue96c\ue95c\ue94c\uf0e4\uf0d4\ue91c\ue90c" + + "\ue8fc\ue8ec\ue8dc\ue8cc\ue8bc\ue8ac\ue89c\ue88c\ue87c\ue86c\ue85c" + + "\ue84c\ue83c\ue82c\ue81c\ue80c\ue7fc\ue7ec\ue7dc\ue7cc\ue7bc\ue7ac" + + "\ue79c\ue78c\ue77c\ue76c\ue75c\ue74c\ue73c\ue72c\ue71c\ue70c\ue6fc" + + "\ue6ec\ue6dc\ue6cc\ue6bc\ue6ac\ue69c\ue68c\ue67c\ue66c\ue65c\ue64c" + + "\ue63c\ue62c\ue6d0\ue6c0\ue6b4\ue6b0\ue6a0\ue690\uee5e\ue5ac\ue59c" + + "\ue58c\ue57c\ue56c\ue55c\ue54c\ue53c\ue52c\ue317\ue307\ue2f7\ue2e7" + + "\ue2d7\ue2c7\ue2b7\ue2a7\ue297\ue358\ue277\ue267\ue257\ue247\ue237" + + "\ue6e8\uecce\uecce\uecae\uec9e\uec9e\uec9e\uec6e\uec8e\uec8e\uec7e" + + "\uec6e\uec6e\ue483\uec5e\uec5e\ue165\uec4e\uec4e\ue07b\uec4d\ue053" + + "\udff6\ue71b\uec1d\uec1d\ue28c\uec0d\uec0b\ue25c\uebfb\ue607\ue22c" + + "\ue2bf\ue9a1\uea8e\ue889\uec17\ue56b\uec07\uec07\uec07\uea12\uebf7" + + "\ue914\ue906\ue8ef\ue8e4\ue8e0\ue967\ueb1b\ueb16\ue8d2\ueacf\uea9a" + + "\ue8b9\uea9c\ue8d2\ue8f5\uea66\uea63\uea30\ue87c\uea2e\uea1c\ueaa6" + + "\ue7b4\uea90\uea8b\uea81\uea71\uea61\ue10d\ue744\ue114\ue734\ue100" + + "\ue704\uea29\udf3c\udf2c\ue6c4\ue6b4\ue9d3\udeec\ue9af\udecc\ue9b1" + + "\ue99d\ue989\ue989\ue921\ue9aa\ue9a0\ue9a0\ue996\ue582\ue5c4\ue5b4" + + "\ue5a4\ue594\ue584\ue574\ue564\ue554\ue544\ue534\ue524\ue7ee\ue502" + + "\ue4f4\ue4e4\ue4dc\ue4c4\udea9\ue4a4\ue494\ue484\ue474\ue465\ue77c" + + "\ue444\ue768\ue758\udc6c\udc5c\udc4c\udc3c\udc2c\udd98\ue3b4\udd99" + + "\ue394\udd4a\ue744\udd61\udd5b\udd51\ue654\ue324\ue63b\udb5c\ue50b" + + "\ue6c4\ue2e4\ue2c4\ue2b4\ue2a4\ue294\ue284\ue274\ue264\ue254\ue244" + + "\ue234\ue224\ue214\ue204\ue1f4\ue1e4\ue1d4\ue1d4\ue1c4\ue1b4\ue1a4" + + "\ue194\ue184\ue174\ue164\ue16e\ue166\ue36c\ue1de\ue1af\ue37b\ue14f" + + "\ue0f0\ue0da\ue331\ue13d\ue149\ue094\ue147\ue2bd\ue0d9\ue28c\ue27c" + + "\ue081\ue25c\ue24c\ue03d\ue217\ue04c\ue2ec\ud80c\ud7fc\ud7ec\ud7dc" + + "\ud7cc\ud7bc\ud7ac\ud79c\ud78c\ud77c\ud76c\ud75c\ud74c\ud73c\ud72c" + + "\ud71c\ud70c\ud6fc\ud6ec\ud6dc\ud6cc\ud6bc\ud6ac\ud69c\ud68c\ud67c" + + "\ud66c\ud65c\ud64c\ud63c\ud62c\ud61c\ud60c\ud5fc\ud5ec\ud5dc\ud5cc" + + "\ud5bc\ud5ac\ud59c\ud58c\ud57c\ud56c\ud55c\ud54c\ud53c\ud52c\ud51c" + + "\ud50c\ud4fc\ud4ec\ud4dc\ud4cc\ud4bc\ud4ac\udc44\ud627\udc24\udc14" + + "\udc04\udbf4\udbe4\udf06\udbc4\udbb4\udba4\udb94\udb84\udb74\udb64" + + "\udb54\udb44\udb34\udb24\udb14\udb04\ude24\ud33c\uddfe\udeb4\udeb2" + + "\ud433\ude56\ud3d2\ud3c3\ud3b3\ud3a3\ud393\ud7bc\ud362\ud363\ud353" + + "\ud343\ud333\ud71b\ud706\ud303\ud6d9\ud2e2\ud2d3\ud2c3\ud2b3\ud2a3" + + "\ud283\ud2e7\ud273\ud833\ud15c\ud14c\ud13c\ud223\udbc1\udbb4\udc30" + + "\udb91\udc00\udc82\udb61\udb55\udbd0\udb31\udb21\udb24\udb65\udaf1" + + "\udae1\udb45\udac1\udab1\udaa1\uda91\uda81\uda71\uda61\udaba\uda41" + + "\uda31\uda21\uda11\uda01\ud9f3\ud9e1\ud9d2\ud013\ud003\ucff3\ucfe3" + + "\ucfd3\ucfc3\ucfb3\ucfa3\ucf93\ucf83\ucf73\ucf63\ucf53\ucf43\ucf33" + + "\ucf23\ucf13\ucf03\ucef3\ucee3\uced3\ucec3\uceb3\ucea3\uce93\uce83" + + "\uce73\uce63\uce53\uce43\uce33\uce23\uce13\uce03\ucdf3\ucde3\ucdd3" + + "\ucdc3\ucdb3\ucda3\ucd93\ucd83\ucd73\ucd63\ucd53\ucd43\ucd33\ucd23" + + "\ucd13\ucd03\uccf3\ucce3\uccd3\uccc3\uccb3\ucca3\ucc93\ucc83\ucc73" + + "\ucc63\ucc53\ucc43\ucc33\ucc23\ucc13\ucc03\ucbf3\ucbe3\ucbd3\ucbc3" + + "\ucbb3\ucba3\ucb93\ucb83\ucb73\ucb63\ucb53\ucb43\ucb33\ucb23\ucb13" + + "\ucb03\ucaf3\ucae3\ucad3\ucac3\ucab3\ucaa3\uca93\uca83\uca73\uca63" + + "\uca53\uca43\uca33\uca23\uca13\uca03\uc9f3\uc9e3\uc9d3\uc9c3\uc9b3" + + "\uc9a3\uc993\uc983\uc973\uc963\uc953\uc943\uc933\uc923\uc913\uc903" + + "\uc8f3\uc8e3\uc8d3\uc8c3\uc8b3\uc8a3\uc893\uc883\uc873\uc863\uc853" + + "\uc843\uc833\uc823\uc813\uc803\uc7f3\uc7e3\uc7d3\uc7c3\uc7b3\uc7a3" + + "\uc793\uc783\uc773\uc763\uc753\uc743\uc733\uc723\uc713\uc703\uc6f3" + + "\uc6e3\uc6d3\uc6c3\uc6b3\uc6a3\uc693\uc683\uc673\uc663\uc653\uc643" + + "\uc633\uc623\uc613\uc603\uc5f3\uc5e3\uc5d3\uc5c3\uc5b3\uc5a3\uc593" + + "\uc583\uc573\uc563\uc553\uc543\uc533\uc523\uc513\uc503\uc4f3\uc4e3" + + "\uc4d3\uc4c3\uc4b3\uc4a3\uc493\uc483\uc473\uc463\uc453\uc443\uc433" + + "\uc423\uc413\uc403\uc3f3\uc3e3\uc3d3\uc3c3\uc3b3\uc3a3\uc393\uc383" + + "\uc373\uc363\uc353\uc343\uc333\uc323\uc313\uc303\uc2f3\uc2e3\uc2d3" + + "\uc2c3\uc2b3\uc2a3\uc293\uc283\uc273\uc263\uc253\uc243\uc233\uc223" + + "\uc213\uc203\uc1f3\uc1e3\uc1d3\uc1c3\uc1b3\uc1a3\uc193\uc183\uc173" + + "\uc163\uc153\uc143\uc133\uc123\uc113\uc103\uc0f3\uc0e3\uc0d3\uc0c3" + + "\uc0b3\uc0a3\uc093\uc083\uc073\uc063\uc053\uc043\uc033\uc023\uc013" + + "\uc003\ubff3\ubfe3\ubfd3\ubfc3\ubfb3\ubfa3\ubf93\ubf83\ubf73\ubf63" + + "\ubf53\ubf43\ubf33\ubf23\ubf13\ubf03\ubef3\ubee3\ubed3\ubec3\ubeb3" + + "\ubea3\ube93\ube83\ube73\ube63\ube53\ube43\ube33\ube23\ube13\ube03" + + "\ubdf3\ubde3\ubdd3\ubdc3\ubdb3\ubda3\ubd93\ubd83\ubd73\ubd63\ubd53" + + "\ubd43\ubd33\ubd23\ubd13\ubd03\ubcf3\ubce3\ubcd3\ubcc3\ubcb3\ubca3" + + "\ubc93\ubc83\ubc73\ubc63\ubc53\ubc43\ubc33\ubc23\ubc13\ubc03\ubbf3" + + "\ubbe3\ubbd3\ubbc3\ubbb3\ubba3\ubb93\ubb83\ubb73\ubb63\ubb53\ubb43" + + "\ubb33\ubb23\ubb13\ubb03\ubaf3\ubae3\ubad3\ubac3\ubab3\ubaa3\uba93" + + "\uba83\uba73\uba63\uba53\uba43\uba33\uba23\uba13\uba03\ub9f3\ub9e3" + + "\ub9d3\ub9c3\ub9b3\ub9a3\ub993\ub983\ub973\ub963\ub953\ub943\ub933" + + "\ub923\ub913\ub903\ub8f3\ub8e3\ub8d3\ub8c3\ub8b3\ub8a3\ub893\ub883" + + "\ub873\ub863\ub853\ub843\ub833\ub823\ub813\ub803\ub7f3\ub7e3\ub7d3" + + "\ub7c3\ub7b3\ub7a3\ub793\ub783\ub773\ub763\ub753\ub743\ub733\ub723" + + "\ub713\ub703\ub6f3\ub6e3\ub6d3\ub6c3\ub6b3\ub6a3\ub693\ub683\ub673" + + "\ubc35\ubd04\ubcf4\ubce4\ubcd4\ub613\ub603\ub5f3\ub5e3\ub5d3\ub5c3" + + "\ub5b3\ub5a3\ub593\ub583\ub573\ub563\ub553\ub543\ub533\ub523\ub513" + + "\ub503\ub4f3\ub4e3\ub4d3\ub4c3\ub4b3\ub4a3\ub493\ub483\ub473\ub463" + + "\ub453\ub443\ub433\ub423\ub413\ub403\ub3f3\ub3e3\ub3d3\ub3c3\ub3b3" + + "\ub3a3\ub393\ub383\ub373\ub363\ub353\ub343\ub333\ub323\ub313\ub303" + + "\ub2f3\ub2e3\ub2d3\ub2c3\ub2b3\ub2a3\ub293\ub283\ub273\ub263\ub253" + + "\ub243\ub233\ub223\ub213\ub203\ub1f3\ub1e3\ub1d3\ub1c3\ub1b3\ub1a3" + + "\ub193\ub183\ub173\ub163\ub153\ub143\ub133\ub123\ub113\ub103\ub0f3" + + "\ub0e3\ub0d3\ub0c3\ub0b3\ub0a3\ub093\ub083\ub073\ub063\ub053\ub043" + + "\ub033\ub023\ub013\ub003\uaff3\uafe3\uafd3\uafc3\uafb3\uafa3\uaf93" + + "\uaf83\uaf73\uaf63\uaf53\uaf43\uaf33\uaf23\uaf13\uaf03\uaef3\uaee3" + + "\uaed3\uaec3\uaeb3\uaea3\uae93\uae83\uae73\uae63\uae53\uae43\uae33" + + "\uae23\uae13\uae03\uadf3\uade3\uadd3\uadc3\uadb3\uada3\uad93\uad83" + + "\uad73\uad63\uad53\uad43\uad33\uad23\uad13\uad03\uacf3\uace3\uacd3" + + "\uacc3\uacb3\uaca3\uac93\uac83\uac73\uac63\uac53\uac43\uac33\uac23" + + "\uac13\uac03\uabf3\uabe3\uabd3\uabc3\uabb3\uaba3\uab93\uab83\uab73" + + "\uab63\uab53\uab43\uab33\uab23\uab13\uab03\uaaf3\uaae3\uaad3\uaac3" + + "\uaab3\uaaa3\uaa93\uaa83\uaa73\uaa63\uaa53\uaa43\uaa33\uaa23\uaa13" + + "\uaa03\ua9f3\ua9e3\ua9d3\ua9c3\ua9b3\ua9a3\ua993\ua983\ua973\ua963" + + "\ua953\ua943\ua933\ua923\ua913\ua903\ua8f3\ua8e3\ua8d3\ua8c3\ua8b3" + + "\ua8a3\ua893\ua883\ua873\ua863\ua853\ua843\ua833\ua823\ua813\ua803" + + "\ua7f3\ua7e3\ua7d3\ua7c3\ua7b3\ua7a3\ua793\ua783\ua773\ua763\ua753" + + "\ua743\ua733\ua723\ua713\ua703\ua6f3\ua6e3\ua6d3\ua6c3\ua6b3\ua6a3" + + "\ua693\ua683\ua673\ua663\ua653\ua643\ua633\ua623\ua613\ua603\ua5f3" + + "\ua5e3\ua5d3\ua5c3\ua5b3\ua5a3\ua593\ua583\ua573\ua563\ua553\ua543" + + "\ua533\ua523\ua513\ua503\ua4f3\ua4e3\ua4d3\ua4c3\ua4b3\ua4a3\ua493" + + "\ua483\ua473\ua463\ua453\ua443\ua433\ua423\ua413\ua403\ua3f3\ua3e3" + + "\ua3d3\ua3c3\ua3b3\ua3a3\ua393\ua383\ua373\ua363\ua353\ua343\ua333" + + "\ua323\ua313\ua303\ua2f3\ua2e3\ua2d3\ua2c3\ua2b3\ua2a3\ua293\ua283" + + "\ua273\ua263\ua253\ua243\ua233\ua223\ua213\ua203\ua1f3\ua1e3\ua1d3" + + "\ua1c3\ua1b3\ua1a3\ua193\ua183\ua173\ua163\ua153\ua143\ua133\ua123" + + "\ua113\ua103\ua0f3\ua0e3\ua0d3\ua0c3\ua0b3\ua0a3\ua093\ua083\ua073" + + "\ua063\ua053\ua043\ua033\ua023\ua013\ua003\u9ff3\u9fe3\u9fd3\u9fc3" + + "\u9fb3\u9fa3\u9f93\u9f83\u9f73\u9f63\u9f53\u9f43\u9f33\u9f23\u9f13" + + "\u9f03\u9ef3\u9ee3\u9ed3\u9ec3\u9eb3\u9ea3\u9e93\u9e83\u9e73\u9e63" + + "\u9e53\u9e43\u9e33\u9e23\u9e13\u9e03\u9df3\u9de3\u9dd3\u9dc3\u9db3" + + "\u9da3\u9d93\u9d83\u9d73\u9d63\u9d53\u9d43\u9d33\u9d23\u9d13\u9d03" + + "\u9cf3\u9ce3\u9cd3\u9cc3\u9cb3\u9ca3\u9c93\u9c83\u9c73\u9c63\u9c53" + + "\u9c43\u9c33\u9c23\u9c13\u9c03\u9bf3\u9be3\u9bd3\u9bc3\u9bb3\u9ba3" + + "\u9b93\u9b83\u9b73\u9b63\u9b53\u9b43\u9b33\u9b23\u9b13\u9b03\u9af3" + + "\u9ae3\u9ad3\u9ac3\u9ab3\u9aa3\u9a93\u9a83\u9a73\u9a63\u9a53\u9a43" + + "\u9a33\u9a23\u9a13\u9a03\u99f3\u99e3\u99d3\u99c3\u99b3\u99a3\u9993" + + "\u9983\u9973\u9963\u9953\u9943\u9933\u9923\u9913\u9903\u98f3\u98e3" + + "\u98d3\u98c3\u98b3\u98a3\u9893\u9883\u9873\u9863\u9853\u9843\u9833" + + "\u9823\u9813\u9803\u97f3\u97e3\u97d3\u97c3\u97b3\u97a3\u9793\u9783" + + "\u9773\u9763\u9753\u9743\u9733\u9723\u9713\u9703\u96f3\u96e3\u96d3" + + "\u96c3\u96b3\u96a3\u9693\u9683\u9673\u9663\u9653\u9643\u9633\u9623" + + "\u9613\u9603\u95f3\u95e3\u95d3\u95c3\u95b3\u95a3\u9593\u9583\u9573" + + "\u9563\u9553\u9543\u9533\u9523\u9513\u9503\u94f3\u94e3\u94d3\u94c3" + + "\u94b3\u94a3\u9493\u9483\u9473\u9463\u9453\u9443\u9433\u9423\u9413" + + "\u9403\u93f3\u93e3\u93d3\u93c3\u93b3\u93a3\u9393\u9383\u9373\u9363" + + "\u9353\u9343\u9333\u9323\u9313\u9303\u92f3\u92e3\u92d3\u92c3\u92b3" + + "\u92a3\u9293\u9283\u9273\u9263\u9253\u9243\u9233\u9223\u9213\u9203" + + "\u91f3\u91e3\u91d3\u91c3\u91b3\u91a3\u9193\u9183\u9173\u9163\u9153" + + "\u9143\u9133\u9123\u9113\u9103\u90f3\u90e3\u90d3\u90c3\u90b3\u90a3" + + "\u9093\u9083\u9073\u9063\u9053\u9043\u9033\u9023\u9013\u9003\u8ff3" + + "\u8fe3\u8fd3\u8fc3\u8fb3\u8fa3\u8f93\u8f83\u8f73\u8f63\u8f53\u8f43" + + "\u8f33\u8f23\u8f13\u8f03\u8ef3\u8ee3\u8ed3\u8ec3\u8eb3\u8ea3\u8e93" + + "\u8e83\u8e73\u8e63\u8e53\u8e43\u8e33\u8e23\u8e13\u8e03\u8df3\u8de3" + + "\u8dd3\u8dc3\u8db3\u8da3\u8d93\u8d83\u8d73\u8d63\u8d53\u8d43\u8d33" + + "\u8d23\u8d13\u8d03\u8cf3\u8ce3\u8cd3\u8cc3\u8cb3\u8ca3\u8c93\u8c83" + + "\u8c73\u8c63\u8c53\u8c43\u8c33\u8c23\u8c13\u8c03\u8bf3\u8be3\u8bd3" + + "\u8bc3\u8bb3\u8ba3\u8b93\u8b83\u8b73\u8b63\u8b53\u8b43\u8b33\u8b23" + + "\u8b13\u8b03\u8af3\u8ae3\u8ad3\u8ac3\u8ab3\u8aa3\u8a93\u8a83\u8a73" + + "\u8a63\u8a53\u8a43\u8a33\u8a23\u8a13\u8a03\u89f3\u89e3\u89d3\u89c3" + + "\u89b3\u89a3\u8993\u8983\u8973\u8963\u8953\u8943\u8933\u8923\u8913" + + "\u8903\u88f3\u88e3\u88d3\u88c3\u88b3\u88a3\u8893\u8883\u8873\u8863" + + "\u8853\u8843\u8833\u8823\u8813\u8803\u87f3\u87e3\u87d3\u87c3\u87b3" + + "\u87a3\u8793\u8783\u8773\u8763\u8753\u8743\u8733\u8723\u8713\u8703" + + "\u86f3\u86e3\u86d3\u86c3\u86b3\u86a3\u8693\u8683\u8673\u8663\u8653" + + "\u8643\u8633\u8623\u8613\u8603\u85f3\u85e3\u85d3\u85c3\u85b3\u85a3" + + "\u8593\u8583\u8573\u8563\u8553\u8543\u8533\u8523\u8513\u8503\u84f3" + + "\u84e3\u84d3\u84c3\u84b3\u84a3\u8493\u8483\u8473\u8463\u8453\u8443" + + "\u8433\u8423\u8413\u8403\u83f3\u83e3\u83d3\u83c3\u83b3\u83a3\u8393" + + "\u8383\u8373\u8363\u8353\u8343\u8333\u8323\u8313\u8303\u82f3\u82e3" + + "\u82d3\u82c3\u82b3\u82a3\u8293\u8283\u8273\u8263\u8253\u8243\u8233" + + "\u8223\u8213\u8203\u81f3\u81e3\u81d3\u81c3\u81b3\u81a3\u8193\u8183" + + "\u8173\u8163\u8153\u8143\u8133\u8123\u8113\u8103\u80f3\u80e3\u80d3" + + "\u80c3\u80b3\u80a3\u8093\u8083\u8073\u8063\u8053\u8043\u8033\u8023" + + "\u8013\u8003\u7ff3\u7fe3\u7fd3\u7fc3\u7fb3\u7fa3\u7f93\u7f83\u7f73" + + "\u7f63\u7f53\u7f43\u7f33\u7f23\u7f13\u7f03\u7ef3\u7ee3\u7ed3\u7ec3" + + "\u7eb3\u7ea3\u7e93\u7e83\u7e73\u7e63\u7e53\u7e43\u7e33\u7e23\u7e13" + + "\u7e03\u7df3\u7de3\u7dd3\u7dc3\u7db3\u7da3\u7d93\u7d83\u7d73\u7d63" + + "\u7d53\u7d43\u7d33\u7d23\u7d13\u7d03\u7cf3\u7ce3\u7cd3\u7cc3\u7cb3" + + "\u7ca3\u7c93\u7c83\u7c73\u7c63\u7c53\u7c43\u7c33\u7c23\u7c13\u7c03" + + "\u7bf3\u7be3\u7bd3\u7bc3\u7bb3\u7ba3\u7b93\u7b83\u7b73\u7b63\u7b53" + + "\u7b43\u7b33\u7b23\u7b13\u7b03\u7af3\u7ae3\u7ad3\u7ac3\u7ab3\u7aa3" + + "\u7a93\u7a83\u7a73\u7a63\u7a53\u7a43\u7a33\u7a23\u7a13\u7a03\u79f3" + + "\u79e3\u79d3\u79c3\u79b3\u79a3\u7993\u7983\u7973\u7963\u7953\u7943" + + "\u7933\u7923\u7913\u7903\u78f3\u78e3\u78d3\u78c3\u78b3\u78a3\u7893" + + "\u7883\u7873\u7863\u7853\u7843\u7833\u7823\u7813\u7803\u77f3\u77e3" + + "\u77d3\u77c3\u77b3\u77a3\u7793\u7783\u7773\u7763\u7753\u7743\u7733" + + "\u7723\u7713\u7703\u76f3\u76e3\u76d3\u76c3\u76b3\u76a3\u7693\u7683" + + "\u7673\u7663\u7653\u7643\u7633\u7623\u7613\u7603\u75f3\u75e3\u75d3" + + "\u75c3\u75b3\u75a3\u7593\u7583\u7573\u7563\u7553\u7543\u7533\u7523" + + "\u7513\u7503\u74f3\u74e3\u74d3\u74c3\u74b3\u74a3\u7493\u7483\u7473" + + "\u7463\u7453\u7443\u7433\u7423\u7413\u7403\u73f3\u73e3\u73d3\u73c3" + + "\u73b3\u73a3\u7393\u7383\u7373\u7363\u7353\u7343\u7333\u7323\u7313" + + "\u7303\u72f3\u72e3\u72d3\u72c3\u72b3\u72a3\u7293\u7283\u7273\u7263" + + "\u7253\u7243\u7233\u7223\u7213\u7203\u71f3\u71e3\u71d3\u71c3\u71b3" + + "\u71a3\u7193\u7183\u7173\u7163\u7153\u7143\u7133\u7123\u7113\u7103" + + "\u70f3\u70e3\u70d3\u70c3\u70b3\u70a3\u7093\u7083\u7073\u7063\u7053" + + "\u7043\u7033\u7023\u7013\u7003\u6ff3\u6fe3\u6fd3\u6fc3\u6fb3\u6fa3" + + "\u6f93\u6f83\u6f73\u6f63\u6f53\u6f43\u6f33\u6f23\u6f13\u6f03\u6ef3" + + "\u6ee3\u6ed3\u6ec3\u6eb3\u6ea3\u6e93\u6e83\u6e73\u6e63\u6e53\u6e43" + + "\u6e33\u6e23\u6e13\u6e03\u6df3\u6de3\u6dd3\u6dc3\u6db3\u6da3\u6d93" + + "\u6d83\u6d73\u6d63\u6d53\u6d43\u6d33\u6d23\u6d13\u6d03\u6cf3\u6ce3" + + "\u6cd3\u6cc3\u6cb3\u6ca3\u6c93\u6c83\u6c73\u6c63\u6c53\u6c43\u6c33" + + "\u6c23\u6c13\u6c03\u6bf3\u6be3\u6bd3\u6bc3\u6bb3\u6ba3\u6b93\u6b83" + + "\u6b73\u6b63\u6b53\u6b43\u6b33\u6b23\u6b13\u6b03\u6af3\u6ae3\u6ad3" + + "\u6ac3\u6ab3\u6aa3\u6a93\u6a83\u6a73\u6a63\u6a53\u6a43\u6a33\u6a23" + + "\u6a13\u6a03\u69f3\u69e3\u69d3\u69c3\u69b3\u69a3\u6993\u6983\u6973" + + "\u6963\u6953\u6943\u6933\u6923\u6913\u6903\u68f3\u68e3\u68d3\u68c3" + + "\u68b3\u68a3\u6893\u6883\u6873\u6863\u6853\u6843\u6833\u6823\u6813" + + "\u6803\u67f3\u67e3\u67d3\u67c3\u67b3\u67a3\u6793\u6783\u6773\u6763" + + "\u6753\u6743\u6733\u6723\u6713\u6703\u66f3\u66e3\u66d3\u66c3\u66b3" + + "\u66a3\u6693\u6683\u6673\u6663\u6653\u6643\u6633\u6623\u6613\u6603" + + "\u65f3\u65e3\u65d3\u65c3\u65b3\u65a3\u6593\u6583\u6573\u6563\u6553" + + "\u6543\u6533\u6523\u6513\u6503\u64f3\u64e3\u64d3\u64c3\u64b3\u64a3" + + "\u6493\u6483\u6a45\u636c\u635c\u634c\u633c\u632c\u6413\u6403\u63f3" + + "\u63e3\u63d3\u63c3\u63b3\u63a3\u6393\u6383\u6373\u6363\u6353\u6343" + + "\u6333\u6323\u6313\u6303\u62f3\u62e3\u62d3\u62c3\u62b3\u62a3\u6293" + + "\u6283\u6273\u6263\u6253\u6243\u6233\u6223\u6213\u6203\u61f3\u61e3" + + "\u61d3\u61c3\u61b3\u61a3\u6193\u6183\u6173\u6163\u6153\u6143\u6133" + + "\u6123\u6113\u6103\u60f3\u60e3\u60d3\u60c3\u60b3\u60a3\u6093\u6083" + + "\u6073\u6063\u6053\u6043\u6033\u6023\u6013\u6003\u5ff3\u5fe3\u5fd3" + + "\u5fc3\u5fb3\u5fa3\u6379\u6634\u6624\u6614\u6933\u5e4c\u5e3c\u5e2c" + + "\u5e1c\u5e0c\u5dfc\u5dec\u5ddc\u5dcc\u5dbc\u5dac\u5d9c\u5d8c\u5d7c" + + "\u5d6c\u5d5c\u5d4c\u5d3c\u5d2c\u5d1c\u5d0c\u5cfc\u5cec\u5cdc\u5ccc" + + "\u5cbc\u5cac\u5c9c\u5c8c\u5c7c\u5c6c\u5c5c\u5c4c\u5c3c\u5c2c\u5c1c" + + "\u5c0c\u5bfc\u5bec\u5bdc\u5bcc\u5bbc\u5bac\u5b9c\u5b8c\u5b7c\u5b6c" + + "\u5b5c\u5b4c\u5b3c\u5b2c\u5b1c\u5b0c\u5afc\u5aec\u5adc\u5acc\u5abc" + + "\u5aac\u5a9c\u5a8c\u5a7c\u5a6c\u5a5c\u5a4c\u5a3c\u5a2c\u5a1c\u5a0c" + + "\u59fc\u59ec\u59dc\u59cc\u59bc\u59ac\u599c\u598c\u597c\u596c\u595c" + + "\u594c\u593c\u592c\u591c\u590c\u58fc\u58ec\u58dc\u58cc\u58bc\u58ac" + + "\u589c\u588c\u587c\u586c\u585c\u584c\u583c\u582c\u581c\u580c\u57fc" + + "\u57ec\u57dc\u57cc\u57bc\u57ac\u579c\u578c\u577c\u576c\u575c\u574c" + + "\u573c\u572c\u5813\u5803\u57f3\u57e3\u57d3\u57c3\u57b3\u57a3\u5793" + + "\u5783\u5773\u5763\u5753\u5743\u5733\u5723\u5713\u5703\u56f3\u56e3" + + "\u56d3\u56c3\u56b3\u56a3\u5693\u5683\u5673\u5663\u5653\u5643\u5633" + + "\u5623\u5613\u5603\u55f3\u55e3\u55d3\u55c3\u55b3\u55a3\u5593\u5583" + + "\u5573\u5563\u5553\u5543\u5533\u5523\u5513\u5503\u54f3\u54e3\u54d3" + + "\u54c3\u54b3\u54a3\u5493\u5483\u5473\u5463\u5453\u5443\u5433\u5423" + + "\u5413\u5403\u53f3\u53e3\u53d3\u53c3\u53b3\u53a3\u5393\u5383\u5373" + + "\u5363\u5353\u5343\u5333\u5323\u5313\u5303\u52f3\u52e3\u52d3\u52c3" + + "\u52b3\u52a3\u5293\u5283\u5273\u5263\u5253\u5243\u5233\u5223\u5213" + + "\u5203\u51f3\u51e3\u51d3\u51c3\u51b3\u51a3\u5193\u5183\u5173\u5163" + + "\u5153\u5143\u5133\u5123\u5113\u5103\u50f3\u50e3\u50d3\u50c3\u50b3" + + "\u50a3\u5093\u5083\u5073\u5063\u5053\u5043\u5033\u5023\u5013\u5003" + + "\u4ff3\u4fe3\u4fd3\u4fc3\u4fb3\u4fa3\u4f93\u4f83\u4f73\u4f63\u4f53" + + "\u4f43\u4f33\u4f23\u4f13\u4f03\u4ef3\u4ee3\u4ed3\u4ec3\u4eb3\u4ea3" + + "\u4e93\u4e83\u4e73\u4e63\u4e53\u4e43\u4e33\u4e23\u4e13\u4e03\u4df3" + + "\u4de3\u4dd3\u4dc3\u4db3\u4da3\u4d93\u4d83\u4d73\u4d63\u4d53\u4d43" + + "\u4d33\u4d23\u4d13\u4d03\u4cf3\u4ce3\u4cd3\u4cc3\u4cb3\u4ca3\u4c93" + + "\u4c83\u4c73\u4c63\u4c53\u4c43\u4c33\u4c23\u4c13\u4c03\u4bf3\u4be3" + + "\u4bd3\u4bc3\u4bb3\u4ba3\u4b93\u4b83\u4b73\u4b63\u4b53\u4b43\u4b33" + + "\u4b23\u4b13\u4b03\u4af3\u4ae3\u4ad3\u4ac3\u4ab3\u4aa3\u4a93\u4a83" + + "\u4a73\u4a63\u4a53\u4a43\u4a33\u4a23\u4a13\u4a03\u49f3\u49e3\u49d3" + + "\u49c3\u49b3\u49a3\u4993\u4983\u4973\u4963\u4953\u4943\u4933\u4923" + + "\u4913\u4903\u48f3\u48e3\u48d3\u48c3\u48b3\u48a3\u4893\u4883\u4873" + + "\u4863\u4853\u4843\u4833\u4823\u4813\u4803\u47f3\u47e3\u47d3\u47c3" + + "\u47b3\u47a3\u4793\u4783\u4773\u4763\u4753\u4743\u4733\u4723\u4713" + + "\u4703\u46f3\u46e3\u46d3\u46c3\u46b3\u46a3\u4693\u4683\u4673\u4663" + + "\u4653\u4643\u4633\u4623\u4613\u4603\u45f3\u45e3\u45d3\u45c3\u45b3" + + "\u45a3\u4593\u4583\u4573\u4563\u4553\u4543\u4533\u4523\u4513\u4503" + + "\u44f3\u44e3\u44d3\u44c3\u44b3\u44a3\u4493\u4483\u4473\u4463\u4453" + + "\u4443\u4433\u4423\u4413\u4403\u43f3\u43e3\u43d3\u43c3\u43b3\u43a3" + + "\u4393\u4383\u4373\u4363\u4353\u4343\u4333\u4323\u4313\u4303\u42f3" + + "\u42e3\u42d3\u42c3\u42b3\u42a3\u4293\u4283\u4273\u4263\u4253\u4243" + + "\u4233\u4223\u4213\u4203\u41f3\u41e3\u41d3\u41c3\u41b3\u41a3\u4193" + + "\u4183\u4173\u4163\u4153\u4143\u4133\u4123\u4113\u4103\u40f3\u40e3" + + "\u40d3\u40c3\u40b3\u40a3\u4093\u4083\u4073\u4063\u4053\u4043\u4033" + + "\u4023\u4013\u4003\u3ff3\u3fe3\u3fd3\u3fc3\u3fb3\u3fa3\u3f93\u3f83" + + "\u3f73\u3f63\u3f53\u3f43\u3f33\u3f23\u3f13\u3f03\u3ef3\u3ee3\u3ed3" + + "\u3ec3\u3eb3\u3ea3\u3e93\u3e83\u3e73\u3e63\u3e53\u3e43\u3e33\u3e23" + + "\u3e13\u3e03\u3df3\u3de3\u3dd3\u3dc3\u3db3\u3da3\u3d93\u3d83\u3d73" + + "\u3d63\u3d53\u3d43\u3d33\u3d23\u3d13\u3d03\u3cf3\u3ce3\u3cd3\u3cc3" + + "\u3cb3\u3ca3\u3c93\u3c83\u3c73\u3c63\u3c53\u3c43\u3c33\u3c23\u3c13" + + "\u3c03\u3bf3\u3be3\u3bd3\u3bc3\u3bb3\u3ba3\u3b93\u3b83\u3b73\u3b63" + + "\u3b53\u3b43\u3b33\u3b23\u3b13\u3b03\u3af3\u3ae3\u3ad3\u3ac3\u3ab3" + + "\u3aa3\u3a93\u3a83\u3a73\u3a63\u3a53\u3a43\u3a33\u3a23\u3a13\u3a03" + + "\u39f3\u39e3\u39d3\u39c3\u39b3\u39a3\u3993\u3983\u3973\u3963\u3953" + + "\u3943\u3933\u3923\u3913\u3903\u38f3\u38e3\u38d3\u38c3\u38b3\u38a3" + + "\u3893\u3883\u3873\u3863\u3853\u3843\u3833\u3823\u3813\u3803\u37f3" + + "\u37e3\u37d3\u37c3\u37b3\u37a3\u3793\u3783\u3773\u3763\u3753\u3743" + + "\u3733\u3723\u3713\u3703\u36f3\u36e3\u36d3\u36c3\u36b3\u36a3\u3693" + + "\u3683\u3673\u3663\u3653\u3643\u3633\u3623\u3613\u3603\u35f3\u35e3" + + "\u35d3\u35c3\u35b3\u35a3\u3593\u3583\u3573\u3563\u3553\u3543\u3533" + + "\u3523\u3513\u3503\u34f3\u34e3\u34d3\u34c3\u34b3\u34a3\u3493\u3483" + + "\u3473\u3463\u3453\u3443\u3433\u3423\u3413\u3403\u33f3\u33e3\u33d3" + + "\u33c3\u33b3\u33a3\u3393\u3383\u3373\u3363\u3353\u3343\u3333\u3323" + + "\u3313\u3303\u32f3\u32e3\u32d3\u32c3\u32b3\u32a3\u3293\u3283\u3273" + + "\u3263\u3253\u3243\u3233\u3223\u3213\u3203\u31f3\u31e3\u31d3\u31c3" + + "\u31b3\u31a3\u3193\u3183\u3173\u3163\u3153\u3143\u3133\u3123\u3113" + + "\u3103\u30f3\u30e3\u30d3\u30c3\u30b3\u30a3\u3093\u3083\u3073\u3063" + + "\u3053\u3043\u3033\u3023\u3013\u3003\u2ff3\u2fe3\u2fd3\u2fc3\u2fb3" + + "\u2fa3\u2f93\u2f83\u2f73\u2f63\u2f53\u2f43\u2f33\u2f23\u2f13\u2f03" + + "\u2ef3\u2ee3\u2ed3\u2ec3\u2eb3\u2ea3\u2e93\u2e83\u2e73\u2e63\u2e53" + + "\u2e43\u2e33\u2e23\u2e13\u2e03\u2df3\u2de3\u2dd3\u2dc3\u2db3\u2da3" + + "\u2d93\u2d83\u2d73\u2d63\u2d53\u2d43\u2d33\u2d23\u2d13\u2d03\u2cf3" + + "\u2ce3\u2cd3\u2cc3\u2cb3\u2ca3\u2c93\u2c83\u3247\u2b6c\u2b5c\u2b4c" + + "\u2b3c\u2b2c\u36e2\u36d2\u36c2\u36b2\u36a2\u3692\u3682\u3672\u3662" + + "\u3652\u3642\u3632\u3622\u3612\u3602\u35f2\u35e2\u35d2\u35c2\u35b2" + + "\u35a2\u3592\u3582\u3572\u3562\u3552\u3542\u3532\u3522\u3512\u3502" + + "\u34f2\u34e2\u34d2\u34c2\u34b2\u34a2\u3492\u3482\u3472\u3462\u3452" + + "\u3442\u3432\u3422\u3412\u3402\u33f2\u33e2\u33d2\u33c2\u33b2\u33a2" + + "\u3392\u3382\u3372\u3362\u3352\u3342\u3332\u3322\u3312\u3302\u32f2" + + "\u32e2\u32d2\u32c2\u32b2\u32a2\u3292\u3282\u3272\u3262\u3252\u3242" + + "\u3232\u3222\u3212\u3202\u31f2\u31e2\u31d2\u31c2\u31b2\u31a2\u3192" + + "\u3182\u3172\u3162\u3152\u3142\u3132\u3122\u3112\u3102\u30f2\u30e2" + + "\u30d2\u30c2\u30b2\u30a2\u3092\u3082\u3072\u3062\u3052\u3042\u3032" + + "\u3022\u3012\u3002\u2ff2\u2fe2\u2fd2\u2fc2\u2fb2\u2fa2\u2f92\u2f82" + + "\u2f72\u2f62\u2f52\u2f42\u2f32\u2f22\u2f12\u2f02\u2ef2\u2ef2\u2ee2" + + "\u2ed2\u2ec2\u2eb2\u2ea2\u2e92\u2e82\u2e72\u2e62\u2e52\u2e42\u2e32" + + "\u2e22\u2e12\u2e02\u2df2\u2de2\u2dd2\u2dc2\u2db2\u2da2\u2d92\u2d82" + + "\u2d72\u2d62\u2d52\u2d42\u2d32\u2d22\u2d12\u2d02\u2cf2\u2ce2\u2cd2" + + "\u2cc2\u2cb2\u2ca2\u2c92\u2c82\u2c72\u2c62\u2c52\u2c42\u2c32\u2c22" + + "\u2c12\u2c02\u2bf2\u2be2\u2bd2\u2bc2\u2bb2\u2ba2\u2b92\u2b82\u2b72" + + "\u2b62\u2b52\u2b42\u2b32\u2b22\u2b12\u2b02\u2af2\u2ae2\u2ad2\u2ac2" + + "\u2ab2\u2aa2\u2a92\u2a82\u2a72\u2a62\u2a52\u2a42\u2a32\u2a22\u2a12" + + "\u2a02\u29f2\u29e2\u29d2\u29c2\u29b2\u29a2\u2992\u2982\u2972\u2962" + + "\u2952\u2942\u2932\u2922\u2912\u2902\u28f2\u28e2\u28d2\u28c2\u28b2" + + "\u28a2\u2892\u2882\u2872\u2862\u2852\u2842\u2832\u2822\u2812\u2802" + + "\u27f2\u27e2\u27d2\u27c2\u27b2\u27a2\u2792\u2782\u2772\u2762\u2752" + + "\u2742\u2732\u2722\u2712\u2702\u26f2\u26e2\u26d2\u26c2\u26b2\u26a2" + + "\u2692\u2682\u2672\u2662\u2652\u2642\u2632\u2622\u2612\u2602\u25f2" + + "\u25e2\u25d2\u25c2\u25b2\u25a2\u2592\u2582\u2572\u2562\u2552\u2542" + + "\u2532\u2522\u2512\u2502\u24f2\u24e2\u24d2\u24c2\u24b2\u24a2\u2492" + + "\u2482\u2472\u2462\u2452\u2442\u2432\u2422\u2412\u2402\u23f2\u23e2" + + "\u23d2\u23c2\u23b2\u23a2\u2392\u2382\u2372\u2362\u2352\u2342\u2332" + + "\u2322\u2312\u2302\u22f2\u22e2\u22d2\u22c2\u22b2\u22a2\u2292\u2282" + + "\u2272\u2262\u2252\u2242\u2232\u2222\u2212\u2202\u21f2\u21e2\u21d2" + + "\u21c2\u21b2\u21a2\u2192\u2182\u2172\u2162\u2152\u2142\u2132\u2122" + + "\u2112\u2102\u20f2\u20e2\u20d2\u20c2\u20b2\u20a2\u2092\u2082\u2072" + + "\u2062\u2052\u2042\u2032\u2022\u2012\u2002\u1ff2\u1fe2\u1fd2\u1fc2" + + "\u1fb2\u1fa2\u1f92\u1f82\u1f72\u1f62\u1f52\u1f42\u1f32\u1f22\u1f12" + + "\u1f02\u1ef2\u1ee2\u1ed2\u1ec2\u1eb2\u1ea2\u1e92\u1e82\u1e72\u1e62" + + "\u1e52\u1e42\u1e32\u1e22\u1e12\u1e02\u1df2\u1de2\u1dd2\u1dc2\u1db2" + + "\u1da2\u1d92\u1d82\u1d72\u1d62\u1d52\u1d42\u1d32\u1d22\u1d12\u1d02" + + "\u1cf2\u1ce2\u1cd2\u1cc2\u1cb2\u1ca2\u1c92\u1c82\u1c72\u1c62\u1c52" + + "\u1c42\u1c32\u1c22\u1c12\u1c02\u1bf2\u1be2\u1bd2\u1bc2\u1bb2\u1ba2" + + "\u1b92\u1b82\u1b72\u1b62\u1b52\u1b42\u1b32\u1b22\u1b12\u1b02\u1af2" + + "\u1ae2\u1ad2\u1ac2\u1ab2\u1aa2\u1a92\u1a82\u1a72\u1a62\u1a52\u1a42" + + "\u1a32\u1a22\u1a12\u1a02\u19f2\u19e2\u19d2\u19c2\u19b2\u19a2\u1992" + + "\u1982\u1972\u1962\u1952\u1942\u1932\u1922\u1912\u1902\u18f2\u18e2" + + "\u18d2\u18c2\u18b2\u18a2\u1892\u1882\u1872\u1862\u1852\u1842\u1832" + + "\u1822\u1812\u1802\u17f2\u17e2\u17d2\u17c2\u17b2\u17a2\u1792\u1782" + + "\u1772\u1762\u1752\u1742\u1732\u1722\u1712\u1702\u16f2\u16e2\u16d2" + + "\u16c2\u16b2\u16a2\u1692\u1682\u1672\u1662\u1652\u1642\u1632\u1622" + + "\u1612\u1602\u0b13\u0b03\u0af3\u0ae3\u0ad3\u0ac3\u0ab3\u0aa3\u0a93" + + "\u0a83\u0a73\u0a63\u0a53\u0a43\u0a33\u0a23\u0a13\u0a03\u0dd8\u09e3" + + "\u09d3\u09c3\u0d9b\u08ac\u089c\u088c\u087c\u086c\u085c\u084c\u083c" + + "\u082c\u1402\u0b35\u13f2\u13ec\u0b14\u083f\u082f\u081f\u080f\u07ff" + + "\u07ef\u0b82\u075c\u07bc\u07af\u079f\u078f\u077f\u076f\u075f\u074f" + + "\u073f\u072f\u071f\u070f\u06ff\u06ef\u06df\u06cf\u06bf\u06af\u069f" + + "\u068f\u067f\u066f\u0661\u05dc\u063f\u062f\u061f\u060f\u05fd\u05ef" + + "\u05df\u096c\u054c\u053c\u09a9\u0666\u050c\u0818\u10fc\u10f8\u0e1e" + + "\u10e8\u08b3\u050f\u04ff\u04ef\u04df\u04cf\u04bf\u04af\u087c\u0795" + + "\u0127\u0154\u0154\u017a\u1008\u0859\u08ad\u0493\u0485\u0473\u0453" + + "\u01c3\u038b\u0f88\u0333", + + "\000\uffff?\004\004\u00fd\u00bd}=\ufffd\uffbd" + + "\uff7d\uff7d\ufef2\uff2d\ufe7d\ufc7f\ufc6f\ufe6d\ufd7d\ufd3d\ufcfd" + + "\ufcbd\ufc7d\ufc3d\ufbfd\ufbbd\ufb7d\ufb3d\ufafd\ufabd\ufa7d\ufb2d" + + "\uf9fd\uf9bd\uf97d\uf93d\uf8fd\uf8bd\uf87d\uf83d\uf7fd\uf7bd\uf77d" + + "\uf73d\uf6fd\uf6bd\uf67d\uf63d\uf5fd\uf5bd\uf57d\uf53d\uf4fd\uf4bd" + + "\uf47d\uf43d\uf3fd\uf3bd\uf37d\uf33d\uf2fd\uf2bd\uf27d\uf23d\uf1fd" + + "\uf1bd\uf17d\uf13d\uf0fd\uf0bd\uf07d\uf03d\ueffd\uefbd\uef7d\uef3d" + + "\ueefd\ueebd\uee7d\uee3d\uedfd\uedbd\ued7d\ued3d\uecfd\uecbd\uec7d" + + "\uec3d\uebfd\uebbd\ueb7d\ueb3d\ueafd\ueabd\uea7d\uea3d\ue9fd\ue9bd" + + "\ue97d\ue93d\ue8fd\ue8bd\ue87d\ue83d\ue7fd\ue7bd\ue77d\ue73d\ue6fd" + + "\ue6bd\ue67d\ue63d\ue5fd\ue5bd\ue57d\ue53d\ue4fd\ue4bd\ue47d\ue43d" + + "\ue3fd\ue3bd\ue37d\ue33d\ue2fd\ue2bd\ue27d\ue23d\ue1fd\ue1bd\ue17d" + + "\ue13d\ue0fd\ue0bd\ue07d\ue03d\udffd\udfbd\udf7d\udf3d\udefd\udebd" + + "\ude7d\ude3d\uddfd\uddbd\udd7d\udd3d\udcfd\udcbd\udc7d\udc3d\udbfd" + + "\udbbd\udb7d\udb3d\udafd\udabd\uda7d\uda3d\ud9fd\ud9bd\ud97d\ud93d" + + "\ud8fd\ud8bd\ud87d\ud83d\ud7fd\ud7bd\ud77d\ud73d\ud6fd\ud6bd\ud67d" + + "\ud63d\ud5fd\ud5bd\ud57d\ud53d\ud4fd\ud4bd\ud47d\ud43d\ud3fd\ud3bd" + + "\ud37d\ud33d\ud2fd\ud2bd\ud27d\ud23d\ud1fd\ud1bd\ud17d\ud13d\ud0fd" + + "\ud0bd\ud07d\ud03d\ucffd\ucfbd\ucf7d\ucf3d\ucefd\ucebd\uce7d\uce3d" + + "\ucdfd\ucdbd\ucd7d\ucd3d\uccfd\uccbd\ucc7d\ucc3d\ucbfd\ucbbd\ucb7d" + + "\ucb3d\ucafd\ucabd\uca7d\uca3d\uc9fd\uc9bd\uc97d\uc93d\uc8fd\uc8bd" + + "\uc87d\uc83d\uc7fd\uc7bd\uc77d\uc73d\uc6fd\uc6bd\uc67d\uc63d\uc5fd" + + "\uc5bd\uc57d\uc53d\uc4fd\uc4bd\uc47d\uc43d\uc3fd\uc3bd\uc37d\uc33d" + + "\uc2fd\uc2bd\uc27d\uc23d\uc1fd\uc1bd\uc17d\uc13d\uc0fd\uc0bd\uc07d" + + "\uc03d\ubffd\ubfbd\ubf7d\ubf3d\ubefd\ubebd\ube7d\ube3d\ubdfd\ubdbd" + + "\ubd7d\ubd3d\ubcfd\ubcbd\ubc7d\ubc3d\ubbfd\ubbbd\ubb7d\ubb3d\ubafd" + + "\ubabd\uba7d\uba3d\ub9fd\ub9bd\ub97d\ub93d\ub8fd\ub8bd\ub87d\ub83d" + + "\ub7fd\ub7bd\ub77d\ub73d\ub6fd\ub6bd\ub67d\ub63d\ub5fd\ub5bd\ub57d" + + "\ub53d\ub4fd\ub4bd\ub47d\ub43d\ub3fd\ub3bd\ub37d\ub33d\ub2fd\ub2bd" + + "\ub27d\ub23d\ub1fd\ub1bd\ub17d\ub13d\ub0fd\ub0bd\ub07d\ub03d\uaffd" + + "\uafbd\uaf7d\uaf3d\uaefd\uaebd\uae7d\uae3d\uadfd\uadbd\uad7d\uad3d" + + "\uacfd\uacbd\uac7d\uac3d\uabfd\uabbd\uab7d\uab3d\uaafd\uaabd\uaa7d" + + "\uaa3d\ua9fd\ua9bd\ua97d\ua93d\ua8fd\ua8bd\ua87d\ua83d\ua7fd\ua7bd" + + "\ua77d\ua73d\ua6fd\ua6bd\ua67d\ua63d\ua5fd\ua5bd\ua57d\ua53d\ua4fd" + + "\ua4bd\ua47d\ua43d\ua3fd\ua3bd\ua37d\ua33d\ua2fd\ua2bd\ua27d\ua23d" + + "\ua1fd\ua1bd\ua17d\ua13d\ua0fd\ua0bd\ua07d\ua03d\u9ffd\u9fbd\u9f7d" + + "\u9f3d\u9efd\u9ebd\u9e7d\u9e3d\u9dfd\u9dbd\u9d7d\u9d3d\u9cfd\u9cbd" + + "\u9c7d\u9c3d\u9bfd\u9bbd\u9b7d\u9b3d\u9afd\u9abd\u9a7d\u9a3d\u99fd" + + "\u99bd\u997d\u993d\u98fd\u98bd\u987d\u983d\u97fd\u97bd\u977d\u973d" + + "\u96fd\u96bd\u967d\u963d\u95fd\u95bd\u957d\u953d\u94fd\u94bd\u947d" + + "\u943d\u93fd\u93bd\u937d\u933d\u92fd\u92bd\u927d\u923d\u91fd\u91bd" + + "\u917d\u913d\u90fd\u90bd\u907d\u903d\u8ffd\u8fbd\u8f7d\u8f3d\u8efd" + + "\u8ebd\u8e7d\u8e3d\u8dfd\u8dbd\u8d7d\u8d3d\u8cfd\u8cbd\u8c7d\u8c3d" + + "\u8bfd\u8bbd\u8b7d\u8b3d\u8afd\u8abd\u8a7d\u8a3d\u89fd\u89bd\u897d" + + "\u893d\u88fd\u88bd\u887d\u883d\u87fd\u87bd\u877d\u873d\u86fd\u86bd" + + "\u867d\u863d\u85fd\u85bd\u857d\u853d\u84fd\u84bd\u847d\u843d\u83fd" + + "\u83bd\u837d\u833d\u82fd\u82bd\u827d\u823d\u81fd\u81bd\u817d\u813d" + + "\u80fd\u80bd\u807d\u803d\u7ffd\u7fbd\u7f7d\u7f3d\u7efd\u7ebd\u7e7d" + + "\u7e3d\u7dfd\u7dbd\u7d7d\u7d3d\u7cfd\u7cbd\u7c7d\u7c3d\u7bfd\u7bbd" + + "\u7b7d\u7b3d\u7afd\u7abd\u7a7d\u7a3d\u79fd\u79bd\u797d\u793d\u78fd" + + "\u78bd\u787d\u783d\u77fd\u77bd\u777d\u773d\u76fd\u76bd\u767d\u763d" + + "\u75fd\u75bd\u757d\u753d\u74fd\u74bd\u747d\u743d\u73fd\u73bd\u737d" + + "\u733d\u72fd\u72bd\u727d\u723d\u71fd\u71bd\u717d\u713d\u70fd\u70bd" + + "\u707d\u703d\u6ffd\u6fbd\u6f7d\u6f3d\u6efd\u6ebd\u6e7d\u6e3d\u6dfd" + + "\u6dbd\u6d7d\u6d3d\u6cfd\u6cbd\u6c7d\u6c3d\u6bfd\u6bbd\u6b7d\u6b3d" + + "\u6afd\u6abd\u6a7d\u6a3d\u69fd\u69bd\u697d\u693d\u68fd\u68bd\u687d" + + "\u683d\u67fd\u67bd\u677d\u673d\u66fd\u66bd\u667d\u663d\u65fd\u65bd" + + "\u657d\u653d\u64fd\u64bd\u647d\u643d\u63fd\u63bd\u637d\u633d\u62fd" + + "\u62bd\u627d\u623d\u61fd\u61bd\u617d\u613d\u60fd\u60bd\u607d\u603d" + + "\u5ffd\u5fbd\u5f7d\u5f3d\u5efd\u5ebd\u5e7d\u5e3d\u5dfd\u5dbd\u5d7d" + + "\u5d3d\u5cfd\u5cbd\u5c7d\u5c3d\u5bfd\u5bbd\u5b7d\u5b3d\u5afd\u5abd" + + "\u5a7d\u5a3d\u59fd\u59bd\u597d\u593d\u58fd\u58bd\u587d\u583d\u57fd" + + "\u57bd\u577d\u573d\u56fd\u56bd\u567d\u563d\u55fd\u55bd\u557d\u553d" + + "\u54fd\u54bd\u547d\u543d\u53fd\u53bd\u537d\u533d\u52fd\u52bd\u527d" + + "\u523d\u51fd\u51bd\u517d\u513d\u50fd\u50bd\u507d\u503d\u4ffd\u4fbd" + + "\u4f7d\u4f3d\u4efd\u4ebd\u4e7d\u4e3d\u4dfd\u4dbd\u4d7d\u4d3d\u4cfd" + + "\u4cbd\u4c7d\u4c3d\u4bfd\u4bbd\u4b7d\u4b3d\u4afd\u4abd\u4a7d\u4a3d" + + "\u49fd\u49bd\u497d\u493d\u48fd\u48bd\u487d\u483d\u47fd\u47bd\u477d" + + "\u473d\u46fd\u46bd\u467d\u463d\u45fd\u45bd\u457d\u453d\u44fd\u44bd" + + "\u447d\u443d\u43fd\u43bd\u437d\u433d\u42fd\u42bd\u427d\u423d\u41fd" + + "\u41bd\u417d\u413d\u40fd\u40bd\u407d\u403d\u3ffd\u3fbd\u3f7d\u3f3d" + + "\u3efd\u3ebd\u3e7d\u3e3d\u3dfd\u3dbd\u3d7d\u3d3d\u3cfd\u3cbd\u3c7d" + + "\u3c3d\u3bfd\u3bbd\u3b7d\u3b3d\u3afd\u3abd\u3a7d\u3a3d\u39fd\u39bd" + + "\u397d\u393d\u38fd\u38bd\u387d\u383d\u37fd\u37bd\u377d\u373d\u36fd" + + "\u36bd\u367d\u363d\u35fd\u35bd\u357d\u353d\u34fd\u34bd\u347d\u343d" + + "\u33fd\u33bd\u337d\u333d\u32fd\u32bd\u327d\u31d0\u3190\u3150\u311a" + + "\u30a6\u2ffb\u2ff8\u3032\u303d\u2ffd\u2fbd\u2f7d\u306d\u3056\u2ebd" + + "\u2e7d\u3034\u306a\u30a3\u2f64\u3060\u2fa5\u2ec8\u2e94\u2e2c\u2df8" + + "\u2df8\u2d16\u2cdc\u2ca2\u2c68\u2de0\u2a3d\u29fd\u29bd\u297d\u293d" + + "\u28fd\u28bd\u287d\u283d\u27fd\u27bd\u277d\u273d\u26fd\u26bd\u267d" + + "\u263d\u25fd\u25bd\u257d\u253d\u24fd\u24bd\u247d\u243d\u23fd\u23bd" + + "\u237d\u233d\u22fd\u22bd\u227d\u223d\u21fd\u21bd\u217d\u213d\u20fd" + + "\u20bd\u207d\u203d\u1ffd\u1fbd\u1f7d\u1f3d\u1efd\u1ebd\u1e7d\u1e3d" + + "\u1dfd\u1dbd\u1d7d\u1d3d\u1cfd\u1cbd\u1c7d\u1c3d\u1bfd\u1bbd\u1b7d" + + "\u1b3d\u1afd\u1abd\u1a7d\u1a3d\u19fd\u19bd\u197d\u193d\u18fd\u18bd" + + "\u187d\u183d\u17fd\u17bd\u177d\u173d\u16fd\u16bd\u167d\u163d\u15fd" + + "\u15bd\u157d\u153d\u14fd\u14bd\u147d\u143d\u13fd\u13bd\u137d\u133d" + + "\u12fd\u12bd\u127d\u123d\u11fd\u11bd\u117d\u113d\u10fd\u10bd\u107d" + + "\u103d\u0ffd\u0fbd\u0f7d\u0f3d\u0efd\u0ebd\u0e7d\u0e3d\u0dfd\u0dbd" + + "\u0d7d\u0d3d\u0cfd\u0cbd\u0c7d\u0c3d\u0bfd\u0bbd\u0b7d\u0b3d\u0afd" + + "\u0abd\u0a7d\u0a3d\u09fd\u09bd\u097d\u093d\u08fd\u08bd\u087d\u083d" + + "\u07fd\u07bd\u077d\u073d\u06fd\u06bd\u067d\u063d\u05fd\u05bd\u057d" + + "\u053d\u04fd\u04bd\u047d\u043d\u03fd\u03bd\u037d\u033d\u02fd\u02bd" + + "\u027d", + + "\000\uff80\uff00\ufe80\ufe00\ufd80\ufd00\ufc80\ufc00\ufb80\ufb00" + + "\ufa80\ufa00\uf980\uf900\uf880\uf800\uf780\uf700\uf680\uf600\uf580" + + "\uf500\uf480\uf400\uf380\uf300\uf280\uf200\uf180\uf100\uf080\uf000" + + "\uef80\uef00\uee80\uee00\ued80\ued00\uec80\uec00\ueb80\ueb00\uea80" + + "\uea00\ue980\ue900\ue880\ue800\ue780\ue700\ue680\ue600\ue580\ue500" + + "\ue480\ue400\ue380\ue300\ue280\ue200\ue180\ue100\ue080\ue000\udf80" + + "\udf00\ude80\ude00\udd80\udd00\udc80\udc00\udb80\udb00\uda80\uda00" + + "\ud980\ud900\ud880\ud800\ud780\ud700\ud680\ud600\ud580\ud500\ud480" + + "\ud400\ud380\ud300\ud280\ud200\ud180\ud100\ud080\ud000\ucf80\ucf00" + + "\uce80\uce00\ucd80\ucd00\ucc80\ucc00\ucb80\ucb00\uca80\uca00\uc980" + + "\uc900\uc880\uc800\uc780\uc700\uc680\uc600\uc580\uc500\uc480\uc400" + + "\uc380\uc300\uc280\uc200\uc180\uc100\uc080\uc000\ubf80\ubf00\ube80" + + "\ube00\ubd80\ubd00\ubc80\ubc00\ubb80\ubb00\uba80\uba00\ub980\ub900" + + "\ub880\ub800\ub780\ub700\ub680\ub600\ub580\ub500\ub480\ub400\ub380" + + "\ub300\ub280\ub200\ub180\ub100\ub080\ub000\uaf80\uaf00\uae80\uae00" + + "\uad80\uad00\uac80\uac00\uab80\uab00\uaa80\uaa00\ua980\ua900\ua880" + + "\ua800\ua780\ua700\ua680\ua600\ua580\ua500\ua480\ua400\ua380\ua300" + + "\ua280\ua200\ua180\ua100\ua080\ua000\u9f80\u9f00\u9e80\u9e00\u9d80" + + "\u9d00\u9c80\u9c00\u9b80\u9b00\u9a80\u9a00\u9980\u9900\u9880\u9800" + + "\u9780\u9700\u9680\u9600\u9580\u9500\u9480\u9400\u9380\u9300\u9280" + + "\u9200\u9180\u9100\u9080\u9000\u8f80\u8f00\u8e80\u8e00\u8d80\u8d00" + + "\u8c80\u8c00\u8b80\u8b00\u8a80\u8a00\u8980\u8900\u8880\u8800\u8780" + + "\u8700\u8680\u8600\u8580\u8500\u8480\u8400\u8380\u8300\u8280\u8200" + + "\u8180\u8100\u8080\u8000\u7f80\u7f00\u7e80\u7e00\u7d80\u7d00\u7c80" + + "\u7c00\u7b80\u7b00\u7a80\u7a00\u7980\u7900\u7880\u7800\u7780\u7700" + + "\u7680\u7600\u7580\u7500\u7480\u7400\u7380\u7300\u7280\u7200\u7180" + + "\u7100\u7080\u7000\u6f80\u6f00\u6e80\u6e00\u6d80\u6d00\u6c80\u6c00" + + "\u6b80\u6b00\u6a80\u6a00\u6980\u6900\u6880\u6800\u6780\u6700\u6680" + + "\u6600\u6580\u6500\u6480\u6400\u6380\u6300\u6280\u6200\u6180\u6100" + + "\u6080\u6000\u5f80\u5f00\u5e80\u5e00\u5d80\u5d00\u5c80\u5c00\u5b80" + + "\u5b00\u5a80\u5a00\u59a9\u5980\u5900\u5880\u5800\u5780\u5700\u5680" + + "\u5600\u5580\u5500\u5480\u5400\u5380\u5300\u5280\u5200\u5180\u5100" + + "\u5080\u5000\u4f80\u4f00\u4e80\u4e00\u4d80\u4d00\u4c80\u4c00\u4b80" + + "\u4b00\u4a80\u4a00\u4980\u4900\u4880\u4800\u4780\u4700\u4680\u4600" + + "\u4580\u4500\u4480\u4400\u4380\u4300\u4280\u4200\u4180\u4100\u4080" + + "\u4000\u3f80\u3f00\u3e80\u3e00\u3d80\u3d00\u3c80\u3c00\u3b80\u3b00" + + "\u3a80\u3a00\u3980\u3900\u3880\u3800\u3780\u3700\u3680\u3600\u3580" + + "\u3500\u3480\u3400\u3380\u3300\u3280\u3200\u3180\u3100\u3080\u3000" + + "\u2f80\u2f00\u2e80\u2e00\u2d80\u2d00\u2c80\u2c00\u2b80\u2b00\u2a80" + + "\u2a00\u2980\u2900\u2880\u2800\u2780\u2700\u2680\u2600\u2580\u2500" + + "\u2480\u2400\u2380\u2300\u2280\u2200\u2180\u2100\u2080\u2000\u1f80" + + "\u1f00\u1e80\u1e00\u1d80\u1d00\u1c80\u1c00\u1b80\u1b00\u1a80\u1a00" + + "\u1980\u1900\u1880\u1800\u1780\u1700\u1680\u1600\u1580\u1500\u1480" + + "\u1400\u1380\u1300\u1280\u1200\u1180\u1100\u1080\u1000\u0f80\u0f00" + + "\u0e80\u0e00\u0d80\u0d00\u0c80\u0c00\u0b80\u0b00\u0a80\u0a00\u0980" + + "\u0900\u0800\u0780\u0700\u0680\u0662\u0600\u0580\u0500\u0480\u0400" + + "\u0380\u0300\u0280\u0200\u0180\u0100", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "\u00ff\000\uff00\ufe90\ufe80\ufe00\ufd80\ufd00\ufc80\ufc00\ufb80" + + "\ufb00\ufa80\ufa00\uf980\uf900\uf880\uf800\uf780\uf700\uf680\uf600" + + "\uf580\uf500\uf480\uf400\uf380\uf300\uf280\uf200\uf180\uf100\uf080" + + "\uf000\uef80\uef00\uee80\uee00\ued80\ued00\uec80\uec00\ueb80\ueb00" + + "\uea80\uea00\ue980\ue900\ue880\ue800\ue780\ue700\ue680\ue600\ue580" + + "\ue500\ue480\ue400\ue380\ue300\ue280\ue200\ue180\ue100\ue080\ue000" + + "\udf80\udf00\ude80\ude00\udd80\udd00\udc80\udc00\udb80\udb00\uda80" + + "\uda00\ud980\ud900\ud880\ud800\ud780\ud700\ud680\ud600\ud580\ud500" + + "\ud480\ud400\ud380\ud300\ud280\ud200\ud180\ud100\ud080\ud000\ucf80" + + "\ucf00\uce80\uce00\ucd80\ucd00\ucc80\ucc00\ucb80\ucb00\uca80\uca00" + + "\uc980\uc900\uc880\uc800\uc780\uc700\uc680\uc600\uc580\uc500\uc480" + + "\uc400\uc380\uc300\uc280\uc200\uc180\uc100\uc080\uc000\ubf80\ubf00" + + "\ube80\ube00\ubd80\ubd00\ubc80\ubc00\ubb80\ubb00\uba80\uba00\ub980" + + "\ub900\ub880\ub800\ub780\ub700\ub680\ub600\ub580\ub500\ub480\ub400" + + "\ub380\ub300\ub280\ub200\ub180\ub100\ub080\ub000\uaf80\uaf00\uae80" + + "\uae00\uad80\uad00\uac80\uac00\uab80\uab00\uaa80\uaa00\ua980\ua900" + + "\ua880\ua800\ua780\ua700\ua680\ua600\ua580\ua500\ua480\ua400\ua380" + + "\ua300\ua280\ua200\ua180\ua100\ua080\ua000\u9f80\u9f00\u9e80\u9e00" + + "\u9d80\u9d00\u9c80\u9c00\u9b80\u9b00\u9a80\u9a00\u9980\u9900\u9880" + + "\u9800\u9780\u9700\u9680\u9600\u9580\u9500\u9480\u9400\u9380\u9300" + + "\u9280\u9200\u9180\u9100\u9080\u9000\u8f80\u8f00\u8e80\u8e00\u8d80" + + "\u8d00\u8c80\u8c00\u8b80\u8b00\u8a80\u8a00\u8980\u8900\u8880\u8800" + + "\u8780\u8700\u8680\u8600\u8580\u8500\u8480\u8400\u8380\u8300\u8280" + + "\u8200\u8180\u8100\u8080\u8000\u7f80\u7f00\u7e80\u7e00\u7d80\u7d00" + + "\u7c80\u7c00\u7b80\u7b00\u7a80\u7a00\u7980\u7900\u7880\u7800\u7780" + + "\u7700\u7680\u7600\u7580\u7500\u7480\u7400\u7380\u7300\u7280\u7200" + + "\u7180\u7100\u7080\u7000\u6f80\u6f00\u6e80\u6e00\u6d80\u6d00\u6c80" + + "\u6c00\u6b80\u6b00\u6a80\u6a00\u6980\u6900\u6880\u6800\u6780\u6700" + + "\u6680\u6600\u6580\u6500\u6480\u6400\u6380\u6300\u6280\u6200\u6180" + + "\u6100\u6080\u6000\u5f80\u5f00\u5e80\u5e00\u5d80\u5d00\u5c80\u5c00" + + "\u5b80\u5b00\u5a80\u5a00\u5980\u5900\u5880\u5800\u5780\u5700\u5680" + + "\u5600\u5580\u5500\u5480\u5400\u5380\u5300\u5280\u5200\u5180\u5100" + + "\u5080\u5000\u4f80\u4f00\u4e80\u4e00\u4d80\u4d00\u4c80\u4c00\u4b80" + + "\u4b00\u4a80\u4a00\u4980\u4900\u4880\u4800\u4780\u4700\u4680\u4600" + + "\u4580\u4500\u4480\u4400\u4380\u4300\u4280\u4200\u4180\u4100\u4080" + + "\u4000\u3f80\u3f00\u3e80\u3e00\u3d80\u3d00\u3c80\u3c00\u3b80\u3b00" + + "\u3a80\u3a00\u3980\u3900\u3880\u3800\u3780\u3700\u3680\u3600\u3580" + + "\u3500\u3480\u3400\u3380\u3300\u3280\u3200\u3180\u3100\u3080\u3000" + + "\u2f80\u2f00\u2e80\u2e00\u2d80\u2d00\u2c80\u2c00\u2b80\u2b00\u2a80" + + "\u2a00\u2980\u2900\u2880\u2800\u2780\u2700\u2680\u2600\u2580\u2500" + + "\u2480\u2400\u2380\u2300\u2280\u2200\u2180\u2100\u2080\u2000\u1f80" + + "\u1f00\u1e80\u1e00\u1d80\u1d00\u1c80\u1c00\u1b80\u1b00\u1a80\u1a00" + + "\u1980\u1900\u1880\u1800\u1780\u1700\u1680\u1600\u1580\u1500\u1480" + + "\u1400\u1380\u1300\u1280\u1200\u1180\u1100\u1080\u1000\u0f80\u0f00" + + "\u0e80\u0e00\u0d80\u0d00\u0c80\u0c00\u0b80\u0b00\u0a80\u0a00\u0980" + + "\u0900\u0880\u0800\u0780\u0700\u0680\u0600\u0580\u0500\u0480\u0400" + + "\u0380\u0300\u0280\u0200\u0180\u0100", + + "", + + ""}; + + /** + * The array containing the numeric values that are too large to be stored as + * chars in NUM_VALUE. NUM_VALUE in this case will contain a negative integer + * N such that LARGENUMS[-N - 3] contains the correct numeric value. + */ + int[] LARGENUMS + = new int[] {40000, 50000, 60000, 70000, 80000, 90000}; /** * Information about each character. The low order 5 bits form the @@ -282,496 +700,594 @@ public interface CharData * next bit is a flag for mirrored directionality. The high order 9 bits * form the offset into the attribute tables. Note that this limits the * number of unique character attributes to 512, which is not a problem - * as of Unicode version 3.2.0, but may soon become one. + * as of Unicode version 4.0.0, but may soon become one. */ - String DATA - = "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001" - + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082" - + "\u3e80\u3e80\u3001\u3082\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85" - + "\u3a85\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85" - + "\u3e80\u3e80\u3e80\u3e80\u5b88\u5b88\u3e80\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80" - + "\u3e80\u3e80\u3e80\u5198\u3e80\u3e80\u3e80\u3e80\u4606\u3e80\u3e80" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u3a85" - + "\u3a85\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u3e80\u3e80\u3e80\u3e80\u5202\u5202\u5202\u5202" - + "\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202" - + "\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202" - + "\u5202\u5202\u5202\u5202\u5202\u2e82\u3e80\u5198\u2a14\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u4606\u4606\u4606\u4606\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4686\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u1a1b\u1a1b\u3e80\u3e80\u3e80\u3e80\u4584\u3e80\u3e80" - + "\u3e80\u0298\u3e80\u0298\u6615\u6696\u0298\u1a97\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u4584\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u4584\u4584\u1a1b\u1a1b\u1a1b\u1a1b" - + "\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u4584" - + "\u4584\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b" - + "\u1a1b\u1a1b\u1a1b\u1a1b\u2e82\u7282\u2e82\u3e80\u2e82\u4902\u7481" - + "\u7481\u7481\u7481\u7383\u1a1b\u1a1b\u1a1b\u6d82\u6d82\u4902\u4902" - + "\u3e80\u3e80\u2e82\u4902\u6e01\u6e01\u7501\u7501\u3e80\u1a1b\u1a1b" - + "\u1a1b\u1b02\u1b82\u1c02\u1c82\u1d02\u1d82\u1e02\u1e82\u1f02\u1f82" - + "\u2002\u2082\u2102\u2182\u2202\u2282\u2302\u2382\u2402\u2482\u2502" - + "\u2582\u2602\u2682\u2702\u2782\u0455\u0c99\u04d6\u0c99\017\017" - + "\017\017\017\u010f\017\017\017\017\017\017\017" - + "\017\017\017\017\017\017\017\017\017\017\017" - + "\017\017\017\017\017\017\017\017\u008f\u010f\u008f" - + "\u018f\u010f\017\017\017\017\017\017\017\017\017" - + "\017\017\017\017\017\u010f\u010f\u010f\u008f\u020c\u0298" - + "\u0298\u0318\u039a\u0318\u0298\u0298\u0455\u04d6\u0298\u0519\u0598" - + "\u0614\u0598\u0698\u0709\u0789\u0809\u0889\u0909\u0989\u0a09\u0a89" - + "\u0b09\u0b89\u0598\u0298\u0c59\u0c99\u0c59\u0298\u0d01\u0d81\u0e01" - + "\u0e81\u0f01\u0f81\u1001\u1081\u1101\u1181\u1201\u1281\u1301\u1381" - + "\u1401\u1481\u1501\u1581\u1601\u1681\u1701\u1781\u1801\u1881\u1901" - + "\u1981\u0455\u0298\u04d6\u1a1b\u1a97\u0298\u0298\u0298\u0c99\u0455" - + "\u04d6\u3e80\u0298\u0298\u0298\u0298\u0298\u0298\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u282c\u0298\u039a\u039a\u039a\u039a\u289c" - + "\u289c\u1a1b\u289c\u2902\u29dd\u0c99\u2a14\u289c\u1a1b\u2a9c\u0519" - + "\u2b0b\u2b8b\u1a1b\u2c02\u289c\u0298\u1a1b\u2c8b\u2902\u2d5e\u2d8b" - + "\u2d8b\u2d8b\u0298\u0298\u0519\u0614\u0c99\u0c99\u0c99\u3e80\u0298" - + "\u039a\u0318\u0298\u3e80\u3e80\u3e80\u3e80\u5405\u5405\u5405\u3e80" - + "\u5405\u3e80\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u5405\u3e80\u3e80\u3e80\u4606\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u3e80\u501c\u501c\u4f81\u4f81" - + "\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81" - + "\u4f81\u4f81\u4f81\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01" - + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01" - + "\u2e01\u2e01\u2e01\u2e01\u0c99\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01" - + "\u2e01\u2e82\u2e82\u2e82\u4902\u4902\u2e82\u2e82\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u2e82\u2e82" - + "\u2e82\u2e82\u2e82\u3e80\u3e80\u3e80\u3e80\u3e80\u5305\u4606\u5305" - + "\u5305\u3e80\u5305\u5305\u3e80\u5305\u5305\u5305\u5305\u5305\u5305" - + "\u5305\u5305\u5305\u5305\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5398\u5405\u4606\u4606\u4606\u4606\u4606\u4606\u4606" - + "\u5087\u5087\u4606\u5087\u5087\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b" - + "\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u840b\u3082\u3001\u3082\u3001\u3082" - + "\u3001\u3082\u3001\u3082\u2e82\u3001\u3082\u3001\u3082\u3001\u3082" - + "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001" - + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082" - + "\u3001\u3082\u3001\u3082\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5c09" - + "\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u4606\u4606" - + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u1a1b\u1a1b\u4701\u0298\u4781\u4781\u4781\u3e80" - + "\u4801\u3e80\u4881\u4881\u4902\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01" - + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2f02" - + "\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02" + String[] DATA = new String[]{ + "\u2282\u2302\u2382\u2402\u2482\u2502\u2582\u2602\u2682\u2702\u2782" + + "\u0455\u0c99\u04d6\u0c99\017\017\017\017\017\017\017" + + "\017\017\u008f\u010f\u008f\u018f\u010f\017\017\017\017" + + "\017\u010f\017\017\017\017\017\017\017\017\017" + + "\017\017\017\017\017\017\017\u010f\u010f\u010f\u008f" + + "\u0709\u0789\u0809\u0889\u0909\u0989\u0a09\u0a89\u0b09\u0b89\u0598" + + "\u0298\u0c59\u0c99\u0c59\u0298\u0298\u0c99\u0298\u1a97\u3f80\u3f80" + + "\u0298\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u020c\u0298\u0298" + + "\u0318\u039a\u0318\u0298\u0298\u0455\u04d6\u0298\u0519\u0598\u0614" + + "\u0598\u0698\u2a9c\u0519\u2b0b\u2b8b\u1a1b\u2c02\u289c\u0298\u1a1b" + + "\u2c8b\u2902\u2d5e\u2d8b\u2d8b\u2d8b\u0298\u0d01\u0d81\u0e01\u0e81" + + "\u0f01\u0f81\u1001\u1081\u1101\u1181\u1201\u1281\u1301\u1381\u1401" + + "\u1481\u1501\u1581\u1601\u1681\u1701\u1781\u1801\u1881\u1901\u1981" + + "\u0455\u0298\u04d6\u1a1b\u1a97\u0298\u0298\u0298\u0c99\u0455\u04d6" + + "\u0298\u0298\u0298\u0298\u0298\u0298\u0298\u0298\u0298\u858d\u860e" + + "\u8690\u8710\u8790\u8810\u8890\u82ac\u282c\u0298\u039a\u039a\u039a" + + "\u039a\u289c\u289c\u1a1b\u289c\u2902\u29dd\u0c99\u2a10\u289c\u1a1b" + + "\u1b02\u1b82\u1c02\u1c82\u1d02\u1d82\u1e02\u1e82\u1f02\u1f82\u2002" + + "\u2082\u2102\u2182\u2202\u4a82\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01" + + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u0c99" + + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e82\u3c01\u3c83\u3d02" + + "\u3001\u3082\u3e01\u3e81\u3001\u3082\u3001\u3082\u3001\u3082\u3001" + + "\u3082\u3201\u3001\u3082\u3001\u3082\u3001\u3082\u3282\u4a82\u2f02" + "\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02" - + "\u0c99\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f82\u2f02\u2f02" - + "\u4a82\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u4b02" - + "\u4b82\u4b82\u3e80\u4c02\u4c82\u4d01\u4d01\u4d01\u4d82\u4e02\u2902" - + "\u3e80\u3e80\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001" - + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u2e82\u3b81\u3c03\u3c82" - + "\u3001\u3082\u3d81\u3e01\u3001\u3082\u3001\u3082\u3001\u3082\u3001" - + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3101\u3182" - + "\u3001\u3082\u3001\u3082\u3001\u3082\u2902\u3001\u3082\u3001\u3082" - + "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001" - + "\u3082\u4e82\u4f02\u3d02\u2902\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5b10\u5b10\u5b10\u5b10\u5b10" - + "\u5b10\u7f0b\u3e80\u3e80\u3e80\u7f8b\u800b\u808b\u810b\u818b\u820b" - + "\u0519\u0519\u0c99\u0455\u04d6\u2902\u3301\u3001\u3082\u3001\u3082" - + "\u3381\u3001\u3082\u3401\u3401\u3001\u3082\u2902\u3481\u3501\u3581" - + "\u3001\u3082\u3401\u3601\u3682\u3701\u3781\u3001\u3082\u2902\u2902" - + "\u3701\u3801\u2902\u3881\u3a85\u3a85\u3a85\u3a85\u3b81\u3c03\u3c82" - + "\u3b81\u3c03\u3c82\u3b81\u3c03\u3c82\u3001\u3082\u3001\u3082\u3001" - + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082" - + "\u3d02\u3001\u3082\u501c\u4606\u4606\u4606\u4606\u3e80\u5087\u5087" - + "\u3e80\u3e80\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001" - + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082" - + "\u3001\u3082\u3001\u3082\u3201\u3001\u3082\u3001\u3082\u3001\u3082" - + "\u3282\u3001\u3082\u3001\u3082\u3001\u3082\u3901\u3001\u3082\u3901" - + "\u2902\u2902\u3001\u3082\u3901\u3001\u3082\u3981\u3981\u3001\u3082" - + "\u3001\u3082\u3a01\u3001\u3082\u2902\u3a85\u3001\u3082\u2902\u3b02" - + "\u4d01\u3001\u3082\u3001\u3082\u3e80\u3e80\u3001\u3082\u3e80\u3e80" - + "\u3001\u3082\u3e80\u3e80\u3e80\u3001\u3082\u3001\u3082\u3001\u3082" - + "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001" - + "\u3082\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u0598\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5398\u3e80\u3e80\u3e80\u5398" - + "\u5398\u5398\u5398\u5398\u5398\u5398\u5398\u5398\u5398\u5398\u5398" - + "\u5398\u5398\u3e80\u5b10\u5405\u4606\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u3e80\u3e80\u5b10\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01" - + "\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01" - + "\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01" - + "\u4d01\u4d01\u4d01\u4d01\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89" - + "\u5f09\u5f89\u6009\u6089\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u2902\u2902\u2902\u3f02\u3f82\u2902\u4002" - + "\u4002\u2902\u4082\u2902\u4102\u2902\u2902\u2902\u2902\u4002\u2902" - + "\u2902\u4182\u2902\u2902\u2902\u2902\u4202\u4282\u2902\u2902\u2902" - + "\u2902\u2902\u4282\u2902\u2902\u4302\u2902\u2902\u4382\u2902\u2902" - + "\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u4402\u2902\u2902" - + "\u4402\u2902\u2902\u2902\u2902\u4402\u2902\u4482\u4482\u2902\u2902" - + "\u2902\u2902\u2902\u2902\u4502\u2902\u2902\u2902\u2902\u2902\u2902" - + "\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u3e80\u3e80\u4584" - + "\u4584\u4584\u4584\u4584\u4584\u4584\u4584\u4584\u1a1b\u1a1b\u4584" - + "\u4584\u4584\u4584\u4584\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b" - + "\u1a1b\u1a1b\u4584\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5101\u5101" - + "\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101" - + "\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u3e80" - + "\u3e80\u4584\u5198\u5198\u5198\u5198\u5198\u5198\u2e01\u2e01\u3e80" - + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u4982\u4a02" - + "\u4a02\u4a02\u4902\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02" - + "\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u4f02\u4f02\u4f02" - + "\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02" - + "\u4f02\u4f02\u4606\u4606\u4606\u4606\u4606\u5198\u4606\u4606\u3a85" - + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u4606\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u3e80\u4606\u4606\u4606\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u3e80\u4606\u4606\u4606\u5298" - + "\u4606\u4606\u5298\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u5305\u5305\u5305\u5305\u5305\u5305\u5305" - + "\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u5305\u5305\u5305\u5298\u5298\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5c89\u5d09\u5d89" - + "\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u640b\u648b\u650b\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u4606\u5b88\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80" - + "\u3e80\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80" - + "\u3e80\u3a85\u3a85\u3e80\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3e80" - + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606" - + "\u4606\u5b88\u5b88\u5b88\u5b88\u3e80\u4606\u4606\u4606\u3e80\u4606" - + "\u4606\u4606\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u4606" - + "\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u4606" - + "\u5b88\u5b88\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3e80\u3e80\u3a85\u3a85\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80" - + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3e80\u3e80\u3e80\u3e80\u5b88\u5b88\u3e80\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3a85\u3a85\u3a85" - + "\u3e80\u3e80\u3e80\u3e80\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09" - + "\u5f89\u6009\u6089\u501c\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5509\u5589\u5609" - + "\u5689\u5709\u5789\u5809\u5889\u5909\u5989\u0318\u5a18\u5a18\u5398" - + "\u3e80\u3e80\u4606\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u3e80\u3e80\u5405" - + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u5405\u6615\u6696\u5484\u5405\u5405\u5405\u5405" - + "\u5405\u5405\u5405\u5405\u5405\u5405\u4606\u4606\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u5b88\u5b88\u5198\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u4606\u4606\u5b88" - + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3e80" - + "\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u5198\u5198\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u4606\u4606\u4606\u4606\u4606\u5484\u5484\u4606" - + "\u4606\u289c\u4606\u4606\u4606\u4606\u3e80\u3e80\u0709\u0789\u0809" - + "\u0889\u0909\u0989\u0a09\u0a89\u0b09\u0b89\u5405\u5405\u5405\u5a9c" - + "\u5a9c\u3e80\u3a85\u3a85\u3a85\u3e80\u3a85\u3e80\u3a85\u3e80\u3e80" - + "\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u4606\u3a85\u3a85\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u3e80\u4606\u4606\u3a85\u3e80\u3e80" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u4606\u4606\u5b88" - + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3e80\u3e80\u4606\u3a85\u5b88\u5b88\u5b88\u5b88\u5b88\u3e80\u4606" - + "\u5b88\u5b88\u3e80\u5b88\u5b88\u4606\u4606\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u5b88\u5b88\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3a85\u3e80\u5198\u5198\u5198\u5198\u5198\u5198\u5198\u5198" - + "\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u640b\u670b" - + "\u678b\u680b\u688b\u690b\u698b\u6a0b\u6a8b\u648b\u6b0b\u3e80\u3e80" - + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3e80" - + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u4606\u3a85\u5b88\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u5b88\u5b88\u5b88\u5b88" - + "\u4606\u3e80\u3e80\u3a85\u4606\u4606\u4606\u4606\u3e80\u3e80\u3e80" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3e80\u3e80\u3e80" - + "\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u4606\u3e80\u5b88\u5b88\u5b88" - + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85" - + "\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3e80\u3a85" - + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3e80\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u4606\u3a85\u3a85\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u3e80\u3e80\u3e80\u3e80\u039a\u039a\u039a" - + "\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a" - + "\u039a\u039a\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u4606\u4606" - + "\u5198\u5198\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009" - + "\u6089\u5198\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u0298\u0298\u0318\u039a\u0318" - + "\u0298\u0298\u6615\u6696\u0298\u0519\u0598\u0614\u0598\u0698\u0709" - + "\u0789\u0809\u0889\u0909\u0989\u0a09\u0a89\u0b09\u0b89\u0598\u0298" - + "\u0c99\u0c99\u0c99\u0298\u0298\u0298\u0298\u0298\u0298\u2a14\u0298" - + "\u0298\u0298\u0298\u5b10\u5b10\u5b10\u5b10\u3e80\u5c09\u5c89\u5d09" - + "\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u5b88" - + "\u4606\u4606\u4606\u4606\u3e80\u3e80\u5b88\u5b88\u3e80\u3e80\u5b88" - + "\u5b88\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u5b88\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u3e80\u3a85\u3e80\u3e80" - + "\u3a85\u3a85\u3e80\u3a85\u3e80\u3e80\u3a85\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3e80\u3a85\u3a85\u3e80\u3a85\u3a85\u3e80\u3a85\u3a85" - + "\u3e80\u3e80\u4606\u3e80\u5b88\u5b88\u4606\u4606\u3e80\u3e80\u3e80" - + "\u3e80\u4606\u4606\u3e80\u3e80\u4606\u4606\u4606\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85" - + "\u3a85\u3e80\u3a85\u3e80\u3a85\u3a85\u4606\u4606\u3e80\u3e80\u5c09" - + "\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u3a85\u3a85" - + "\u039a\u039a\u610b\u618b\u620b\u628b\u630b\u638b\u501c\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85" - + "\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u4606\u3a85" - + "\u5b88\u5b88\u4606\u4606\u4606\u4606\u4606\u3e80\u4606\u4606\u5b88" - + "\u3e80\u5b88\u5b88\u4606\u3e80\u3e80\u3a85\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u630b" - + "\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u501c\u4606" - + "\u501c\u4606\u501c\u4606\u6615\u6696\u6615\u6696\u5b88\u5b88\u4606" - + "\u4606\u4606\u3e80\u3e80\u3e80\u5b88\u5b88\u3e80\u3e80\u5b88\u5b88" - + "\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u4606\u5b88" - + "\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3e80\u3a85\u3a85\u3e80\u5b88\u4606\u4606\u4606\u4606\u5b88" - + "\u4606\u3e80\u3e80\u3e80\u4606\u4606\u5b88\u4606\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u5b88\u5b88\u5b88\u4606\u4606\u4606\u4606\u4606\u4606\u4606" - + "\u5b88\u5b88\u3e80\u3e80\u3e80\u5b88\u5b88\u5b88\u3e80\u5b88\u5b88" - + "\u5b88\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u5b88\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3e80\u4584\u3e80\u4606\u4606\u4606\u4606\u4606" - + "\u4606\u3e80\u3e80\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89" - + "\u6009\u6089\u3e80\u3e80\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u5c09" - + "\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u5087\u5087\u5087\u5b88\u4606\u4606" - + "\u4606\u3e80\u3e80\u5b88\u5b88\u5b88\u3e80\u5b88\u5b88\u5b88\u4606" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5b88\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u4606\u3e80\u3e80\u3e80\u3e80" - + "\u5b88\u5b88\u5b88\u4606\u4606\u4606\u3e80\u4606\u3e80\u5b88\u5b88" - + "\u5b88\u5b88\u5b88\u5b88\u5b88\u5b88\u4606\u5b88\u5b88\u4606\u4606" - + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u5198\u5198" - + "\u5198\u5198\u5198\u5198\u5198\u039a\u5198\u3e80\u3e80\u3e80\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u4584\u4606\u4606\u4606\u4606\u4606" - + "\u4606\u4606\u4606\u5198\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09" - + "\u5f89\u6009\u6089\u5198\u5198\u3e80\u3e80\u3e80\u3e80\u3a85\u501c" - + "\u501c\u501c\u5198\u5198\u5198\u5198\u5198\u5198\u5198\u5198\u65b8" - + "\u5198\u5198\u5198\u5198\u5198\u5198\u501c\u501c\u501c\u501c\u501c" - + "\u4606\u4606\u501c\u501c\u501c\u501c\u501c\u501c\u4606\u501c\u501c" - + "\u501c\u501c\u501c\u501c\u3e80\u3e80\u501c\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u1a97\u4584\u4584\u4584" - + "\u3e80\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089" - + "\u5198\u5198\u5198\u5198\u5198\u5198\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u5b88\u5b88\u4606\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u020c\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u6615\u6696\u3e80\u3e80\u3e80\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u5198" - + "\u5198\u5198\u6b8b\u6c0b\u6c8b\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u4606\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3001\u3082\u3001" - + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082" - + "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u2e82\u2e82\u2e82" - + "\u2e82\u2e82\u6d02\u3e80\u3e80\u3e80\u3e80\u6d82\u6d82\u6d82\u6d82" - + "\u6d82\u6d82\u6d82\u6d82\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01" - + "\u6e01\u6d82\u6d82\u6d82\u6d82\u6d82\u6d82\u6d82\u6d82\u6e01\u6e01" - + "\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u6d82\u6d82\u6d82\u6d82\u6d82" - + "\u6d82\u3e80\u3e80\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u3e80\u3e80" - + "\u2e82\u6d82\u4902\u6d82\u4902\u6d82\u4902\u6d82\u3e80\u6e01\u3e80" - + "\u6e01\u3e80\u6e01\u3e80\u6e01\u6d82\u6d82\u6d82\u6d82\u6d82\u6d82" - + "\u6d82\u6d82\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u6e82" - + "\u6e82\u6f02\u6f02\u6f02\u6f02\u6f82\u6f82\u7002\u7002\u7082\u7082" - + "\u7102\u7102\u3e80\u3e80\u7182\u7182\u7182\u7182\u7182\u7182\u7182" - + "\u7182\u7203\u7203\u7203\u7203\u7203\u7203\u7203\u7203\u7182\u7182" - + "\u7182\u7182\u7182\u7182\u7182\u7182\u7203\u7203\u7203\u7203\u7203" - + "\u7203\u7203\u7203\u6d82\u6d82\u2e82\u7282\u2e82\u3e80\u2e82\u4902" - + "\u6e01\u6e01\u7301\u7301\u7383\u1a1b\u7402\u1a1b\u1b02\u1b82\u1c02" - + "\u1c82\u1d02\u1d82\u1e02\u1e82\u1f02\u1f82\u2002\u2082\u2102\u2182" - + "\u2202\u2282\u2302\u2382\u2402\u2482\u2502\u2582\u2602\u2682\u2702" - + "\u2782\u6615\u0c99\u6696\u0c99\u3e80\u6d82\u6d82\u4902\u4902\u2e82" - + "\u7582\u2e82\u4902\u6e01\u6e01\u7601\u7601\u7681\u1a1b\u1a1b\u1a1b" - + "\u3e80\u3e80\u2e82\u7282\u2e82\u3e80\u2e82\u4902\u7701\u7701\u7781" - + "\u7781\u7383\u1a1b\u1a1b\u3e80\u020c\u020c\u020c\u020c\u020c\u020c" - + "\u020c\u782c\u020c\u020c\u020c\u788c\u5b10\u5b10\u7910\u7990\u2a14" - + "\u7a34\u2a14\u2a14\u2a14\u2a14\u0298\u0298\u7a9d\u7b1e\u6615\u7a9d" - + "\u7a9d\u7b1e\u6615\u7a9d\u0298\u0298\u0298\u0298\u0298\u0298\u0298" - + "\u0298\u7b8d\u7c0e\u7c90\u7d10\u7d90\u7e10\u7e90\u782c\u0318\u0318" - + "\u0318\u0318\u0318\u0298\u0298\u0298\u0298\u29dd\u2d5e\u0298\u0298" - + "\u0298\u0298\u1a97\u7f0b\u2c8b\u2b0b\u2b8b\u7f8b\u800b\u808b\u810b" - + "\u818b\u820b\u0519\u0519\u0c99\u0455\u04d6\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u3e80\u3e80\u3e80\u3e80\u3e80\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u4d01\u289c\u289c\u289c\u289c" - + "\u4d01\u289c\u289c\u2902\u4d01\u4d01\u4d01\u2902\u2902\u4d01\u4d01" - + "\u4d01\u2902\u289c\u4d01\u289c\u289c\u289c\u4d01\u4d01\u4d01\u4d01" - + "\u4d01\u289c\u289c\ua20a\ua28a\ua30a\ua38a\ua40a\ua48a\ua50a\ua58a" - + "\ua60a\u4606\u4606\u4606\u4606\u4606\u4606\u2a14\u4584\u4584\u4584" - + "\u4584\u4584\u289c\u289c\ua68a\ua70a\ua78a\u3e80\u3e80\u3e80\u289c" - + "\u289c\u289c\u289c\u3e80\u289c\u289c\u289c\u289c\u3e80\u3e80\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u0c99\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u0c99\u0c99\u289c\u289c\u0c99\u289c\u0c99" + + "\u2f02\u2f02\u2f02\u2f02\u0c99\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02" + + "\u2f02\u2f82\u3f01\u2902\u3001\u3082\u3001\u3082\u3001\u3082\u3001" + + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3d82\u3001" + + "\u3082\u539c\u4786\u4786\u4786\u4786\u3f80\u5407\u5407\u3001\u3082" + + "\u3001\u3082\u3001\u3082\u3f80\u3f80\u3001\u3082\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u4786\u6008\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05" + + "\u3f80\u3b05\u3f80\u3f80\u3b05\u3b05\u3f80\u3b05\u3f80\u3f80\u3b05" + + "\u3f80\u3f80\u2e82\u7e02\u2e82\u3f80\u2e82\u4a82\u8181\u8181\u8201" + + "\u8201\u7f03\u1a1b\u1a1b\u3f80\u4786\u4786\u6008\u3f80\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3f80\u3b05" + + "\u3b05\u3b05\u3b05\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80" + + "\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u5518\u5518\u3b05\u3b05\u3b05\u3b05\u3c01\u3c83" + + "\u3d02\u3c01\u3c83\u3d02\u3c01\u3c83\u3d02\u3001\u3082\u3001\u3082" + + "\u2902\u2902\u2902\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3f80\u3b05\u3b05\u3f80" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u4786\u3b05\u6008\u6008" + + "\u4786\u4786\u4786\u3f80\u3f80\u3f80\u6008\u6008\u3f80\u3f80\u6008" + + "\u6008\u4786\u3f80\u3f80\u3101\u3182\u3001\u3082\u3001\u3082\u3001" + + "\u3082\u2902\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u2e82" + + "\u2e82\u2e82\u2e82\u2e82\u7882\u3f80\u3f80\u3f80\u3f80\u1a1b\u1a1b" + + "\u3f80\u3f80\u3f80\u3f80\u4684\u3f80\u3f80\u3f80\u0298\u3f80\u5481" + + "\u5481\u5481\u5481\u5481\u5481\u5481\u5481\u5481\u5481\u5481\u5481" + + "\u5481\u5481\u5481\u5481\u3f80\u3f80\u4684\u5518\u5518\u5518\u5518" + + "\u5518\u5518\u539c\u539c\u539c\u539c\u539c\u4786\u4786\u539c\u539c" + + "\u539c\u539c\u539c\u539c\u4786\u539c\u539c\u539c\u539c\u539c\u539c" + + "\u3f80\u3f80\u539c\u3b05\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u4d82\u4e02\u4e81" + + "\u4e81\u4e81\u4f02\u4f82\u2902\u3001\u3082\u3001\u3082\u3001\u3082" + + "\u3001\u3082\u3001\u3082\u2e82\u3001\u3082\u3001\u3082\u3001\u3082" + + "\u3981\u3001\u3082\u3981\u2902\u2902\u3001\u3082\u3981\u3001\u4502" + + "\u2902\u2902\u4502\u2902\u2902\u2902\u2902\u4502\u2902\u4582\u4582" + + "\u2902\u2902\u2902\u2902\u4402\u2902\u2902\u4482\u2902\u2902\u2902" + + "\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u4002\u4082\u2902\u4102" + + "\u4102\u2902\u4182\u2902\u4202\u2902\u2902\u2902\u2902\u3301\u3001" + + "\u3082\u3001\u3082\u3381\u3001\u3082\u3401\u3401\u3001\u3082\u2902" + + "\u3481\u3501\u3581\u3001\u3082\u3401\u3601\u3682\u3701\u3781\u3001" + + "\u3082\u2902\u2902\u3701\u3801\u3882\u3901\u3082\u3a01\u3a01\u3001" + + "\u3082\u3001\u3082\u3a81\u3001\u3082\u2902\u3b05\u3001\u3082\u2902" + + "\u3b82\u4786\u4786\u4786\u4786\u4786\u4806\u4786\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u3f80\u4786\u4786\u4786\u5698" + + "\u4786\u4786\u5698\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u6008\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05" + + "\u3f80\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u3b05\u3b05\u3f80" + + "\u3b05\u3f80\u3b05\u3b05\u3f80\u3b05\u3b05\u3f80\u3b05\u3b05\u3f80" + + "\u3f80\u4786\u3f80\u6008\u6008\u6008\u3f80\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80" + + "\u3f80\u6008\u6008\u5518\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u5f90\u5f90" + + "\u5f90\u289c\u289c\u3f80\u3f80\u3f80\u0298\u0298\u6089\u6109\u6189" + + "\u6209\u6289\u6309\u6389\u6409\u6489\u6509\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u4786\u3b05\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3f80\u3f80\u3f80\u3b05\u3b05\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05" + + "\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80" + + "\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u5582\u5582\u5582\u5582\u5582" + + "\u5582\u5582\u5582\u5582\u5582\u5582\u5582\u5582\u5582\u5582\u5582" + + "\u2e82\u3f80\u5518\u5614\u3f80\u3f80\u3f80\u3f80\u3f80\u4786\u4786" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u5885\u5885" + + "\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885" + + "\u5885\u5885\u5885\u6b95\u6c16\u4102\u2902\u2902\u4282\u2902\u2902" + + "\u2902\u2902\u4302\u4382\u2902\u2902\u2902\u2902\u2902\u4382\u5790" + + "\u5790\u5790\u5790\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u0598\u5818\u289c\u289c\u4e81\u289c\u289c\u289c\u289c\u4e81\u289c" + + "\u289c\u2902\u4e81\u4e81\u4e81\u2902\u2902\u4602\u2902\u2902\u2902" + + "\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902" + + "\u2902\u2902\u4684\u4684\u4684\u4684\u4684\u4684\u4684\u4684\u4684" + + "\u4684\u4684\u4684\u4684\u4684\u4684\u4684\u4704\u4704\u4684\u4684" + + "\u4684\u4684\u4684\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b" + + "\u1a1b\u4684\u1a1b\u5614\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u4684\u4684\u1a1b\u1a1b\u1a1b\u1a1b\u4704\u4704" + + "\u4704\u4704\u4704\u4704\u4704\u4704\u4704\u4704\u4684\u4684\u1a1b" + + "\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b" + + "\u1a1b\u1a1b\u1a1b\u1a1b\u2e82\u7e02\u2e82\u3f80\u2e82\u4a82\u8001" + + "\u8001\u8001\u8001\u7f03\u1a1b\u1a1b\u1a1b\u289c\uac8a\uad0a\uad8a" + + "\uae0a\uae8a\uaf0a\uaf8a\ub00a\ub08a\u4786\u4786\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u3f80\u4786\u4786\u4786\u4786\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u3f80\u539c" + + "\u539c\u658b\u660b\u668b\u670b\u539c\u539c\u539c\u539c\u539c\u539c" + + "\u539c\u539c\u539c\u539c\u539c\u289c\u0c99\u289c\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u3f80\u289c\u3f80" + + "\u289c\u289c\u289c\u289c\u3f80\u289c\u289c\u289c\u289c\u3f80\u3f80" + + "\u289c\u289c\u289c\u289c\u289c\u539c\u289c\u289c\u289c\u289c\u289c" + + "\u0c99\u0c99\u0c99\u0c99\u0c99\u6b95\u6c16\u0298\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u3f80\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455" + + "\u04d6\u738b\u740b\u748b\u750b\u758b\u760b\u768b\u770b\u778b\uab8b" + + "\u738b\u740b\u748b\u750b\u758b\u760b\u4786\u4786\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786" + + "\u6008\u6008\u3f80\u3f80\u3f80\u6008\u6008\u6008\u3f80\u6008\u6008" + + "\u6008\u4786\u3f80\u3f80\u4786\u6008\u6008\u3f80\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u3b05\u3b05\u3b05\u3f80" + + "\u3b05\u3f80\u3b05\u3f80\u3f80\u3b05\u3b05\u3f80\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3f80\u3b05\u3b05\u3f80\u6008\u4786\u4786\u4786\u4786" + + "\u3f80\u3f80\u6008\u6008\u3f80\u3f80\u6008\u6008\u4786\u3f80\u3f80" + + "\u5002\u5082\u5102\u2902\u5181\u5202\u0c99\u3001\u3082\u5281\u3001" + + "\u3082\u3f80\u3f80\u3f80\u3f80\u1a1b\u1a1b\u4881\u0298\u4901\u4901" + + "\u4901\u3f80\u4981\u3f80\u4a01\u4a01\u2e01\u2e01\u3f80\u2e01\u2e01" + + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u4b02\u4b82\u4b82\u4b82" + + "\u2f02\u2f02\u4c02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02" + + "\u2f02\u4c82\u4d02\u4d02\u3f80\u4786\u4786\u6008\u3f80\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05" + + "\u3b05\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3f80\u3b05\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80" + + "\u4786\u3b05\u6008\u6008\u4786\u6008\u6008\u6008\u6008\u6008\u6008" + + "\u4786\u4786\u4786\u3f80\u3f80\u3f80\u3f80\u5301\u5301\u5301\u5301" + + "\u5301\u5301\u5301\u5301\u5301\u5301\u5301\u5301\u5301\u5301\u5301" + + "\u5301\u5082\u5082\u5082\u5082\u5082\u5082\u5082\u5082\u5082\u5082" + + "\u5082\u5082\u5082\u5082\u5082\u5082\u4e81\u3001\u3082\u3001\u3082" + + "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u6089\u6109\u6189\u6209\u6289\u6309" + + "\u6389\u6409\u6489\u6509\u6b0b\u6b0b\u6b0b\u6b0b\u6b0b\u6b0b\u539c" + + "\u4786\u539c\u4786\u539c\u4786\u6b95\u6c16\u6b95\u6c16\u6008\u6008" + + "\u4786\u4786\u4786\u3f80\u4786\u3f80\u6008\u6008\u6008\u6008\u6008" + + "\u6008\u6008\u6008\u4786\u6008\u6008\u4786\u4786\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u6008\u6008\u6008\u6008\u4786\u3f80\u3f80\u5518" + + "\u5518\u5518\u5518\u5518\u5518\u5518\u5518\u6109\u6189\u6209\u6289" + + "\u6309\u6389\u6409\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786" + + "\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u2e82\u2e82\u2e82\u2e82\u2e82\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u5705\u4786\u5705\u5705\u3f80\u5705\u5705\u3f80\u5705\u5705" + + "\u5705\u5705\u5705\u5705\u5705\u5705\u5705\u5705\u5705\u5705\u5705" + + "\u5705\u5705\u5705\u3f80\u3f80\u3f80\u3f80\u3f80\u6008\u6008\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05\u3f80\u3b05\u3b05\u3f80" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u4786\u3b05\u6008\u4786" + + "\u4786\u4786\u4786\u4786\u3f80\u4786\u4786\u6008\u3f80\u6008\u6008" + + "\u4786\u3f80\u3f80\u0298\u0298\u0318\u039a\u0318\u0298\u0298\u0455" + + "\u04d6\u0298\u0519\u0598\u0614\u0598\u0698\u5705\u5705\u5705\u5698" + + "\u5698\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u6008\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u2d8b" + + "\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b" + + "\u738b\u5989\u5a09\u5a89\u5b09\u5b89\u5c09\u5c89\u5d09\u5d89\u5e09" + + "\u0318\u5e98\u5e98\u5818\u5885\u5885\u5885\u5885\u5818\u5885\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u5790\u5407\u4786\u5407\u5407" + + "\u5407\u4786\u4786\u4786\u4786\u4786\u4786\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u5818\u3f80\u3f80\u3f80\u5818\u5818\u5818\u5818\u5818\u5818" + + "\u5818\u5818\u5818\u5818\u5818\u5818\u5818\u5818\u3f80\u5f90\u5904" + + "\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u3f80" + + "\u3f80\u5885\u5885\u5885\u5885\u5885\u3f80\u5885\u5885\u5885\u5885" + + "\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u6109" + + "\u6189\u6209\u6289\u6309\u6389\u6409\u6489\u6509\u688b\u6c8b\u6d0b" + + "\u6d8b\u6e0b\u6e8b\u6f0b\u6f8b\u700b\u690b\u708b\u3f80\u3f80\u3f80" + + "\u0709\u0789\u0809\u0889\u0909\u0989\u0a09\u0a89\u0b09\u0b89\u5885" + + "\u5885\u5885\u5f1c\u5f1c\u5885\u4786\u5885\u5885\u5885\u5885\u5885" + + "\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u3f80" + + "\u3f80\u5f90\u5f90\u5f90\u5f90\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u5f90\u5f90\u5f90\u5f90\u5f90\u5f90\u4786\u4786\u4786\u4786\u4786" + + "\u5904\u5904\u4786\u4786\u289c\u4786\u4786\u4786\u4786\u5885\u5885" + + "\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\uc51a" + + "\u289c\u3f80\u3f80\u4786\u5885\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u04d6\u0298\u0455" + + "\u04d6\u0298\u1a97\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3f80\u3f80\u3f80\u3f80\u6008\u6008\u3f80\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3f80\u3f80\u3f80\u3f80\u4786\u4786\u6008\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u6b95\u6c16" + + "\u3f80\u3f80\u3f80\u020c\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u1a97\u4684\u4684\u4684\u3b05\u3b05\u3b05\u4684\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3f80\u3f80\u4786\u3b05\u6008\u6008\u6008\u6008" + + "\u6008\u3f80\u6a06\u6008\u6008\u3f80\u6008\u6008\u4786\u4786\u3f80" + + "\u3f80\u3f80\u3f80\u4786\u4786\u3f80\u3f80\u4786\u4786\u4786\u3f80" + + "\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u4786" + + "\u4786\u1a1b\u1a1b\u4684\u4684\u3b05\u4786\u4786\u4786\u4786\u3f80" + + "\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3f80\u3f80\u5518\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05\u4786\u4786" + + "\u5518\u5518\u6089\u6109\u6189\u6209\u6289\u6309\u6389\u6409\u6489" + + "\u6509\u5518\u5518\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05\u4786\u4786" + + "\u3f80\u3f80\u6089\u6109\u6189\u6209\u6289\u6309\u6389\u6409\u6489" + + "\u6509\u3f80\u3f80\u3b05\u3b05\u3f80\u3f80\u3b05\u3b05\u039a\u039a" + + "\u658b\u660b\u668b\u670b\u678b\u680b\u539c\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u4786\u4786\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05\u4786\u3b05\u3b05\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u3f80\u3f80\u3f80\u3f80\u039a" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u4684\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u5518\u4786\u4786\u3b05" + + "\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u3f80\u6089\u6109\u6189\u6209" + + "\u6289\u6309\u6389\u6409\u6489\u6509\u5518\u5518\u5518\u5518\u5518" + + "\u5518\u688b\u690b\u698b\u289c\u289c\u289c\u289c\u289c\u289c\u039a" + + "\u289c\u3f80\u3f80\u3f80\u3f80\u3f80\u4786\u6008\u6008\u6008\u6008" + + "\u3f80\u4786\u4786\u4786\u3f80\u4786\u4786\u4786\u4786\u3f80\u3f80" + + "\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80" + + "\u3f80\u4786\u3b05\u6008\u6a06\u6008\u4786\u4786\u4786\u3f80\u3f80" + + "\u6008\u6008\u6008\u3f80\u6008\u6008\u6008\u4786\u3f80\u3f80\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u4786\u3f80" + + "\u3f80\u3f80\u3f80\u6008\u6008\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u5518\u5518\u5518\u710a\u718a" + + "\u3b05\u4786\u3b05\u3b05\u4786\u4786\u4786\u4786\u4786\u4786\u3f80" + + "\u4786\u4786\u3b05\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80" + + "\u4684\u3f80\u4786\u4786\u4786\u4786\u4786\u4786\u3f80\u3f80\u3b05" + + "\u539c\u539c\u539c\u5518\u5518\u5518\u5518\u5518\u5518\u5518\u5518" + + "\u6ab8\u5518\u5518\u5518\u4786\u6008\u4786\u3f80\u3f80\u3f80\u4786" + + "\u4786\u6008\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u6008\u6008\u4786\u4786\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u4e81\u4e81\u289c\u4e81\u2902\u3b05\u3b05\u3b05" + + "\u3b05\u2902\u289c\u289c\u3f80\u2902\u4e81\u4e81\u4e81\u4e81\u4e81" + + "\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u720a" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05\u4786\u4786\u4786\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05" + + "\u4786\u4786\u4786\u5518\u5518\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3b05\u3b05\u4786\u4786\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05\u3f80\u4786" + + "\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u7290\u7290\u6008\u4786\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u6008\u6008\u6008\u6008\u4786\u4786" + + "\u7808\u7808\u7808\u3f80\u3f80\u3f80\u3f80\u4786\u4786\u4786\u4786" + + "\u5518\u5518\u5518\u4684\u5518\u5518\u5518\u039a\u3b05\u4786\u3f80" + + "\u3f80\ua90b\ua98b\uaa0b\uaa8b\uab0b\u738b\u740b\u748b\u750b\u758b" + + "\u760b\u768b\u770b\u778b\uab8b\u730b\u738b\u740b\u748b\u750b\u758b" + + "\u760b\u768b\u770b\u778b\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u0298" + + "\u0298\u0298\u0298\u0298\u0298\u5614\u0298\u0298\u0298\u0298\u4786" + + "\u4786\u4786\u020c\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u4e81\u4e81" + + "\u4e81\u2902\u289c\u4e81\u289c\u289c\u289c\u4e81\u4e81\u4e81\u4e81" + + "\u4e81\u289c\u289c\u0c99\u289c\u0c99\u289c\u289c\u289c\u289c\u289c" + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u0c99\u289c\u289c\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u948a" - + "\u950a\u958a\u960a\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u0c99\u0c99\u0c99\u0c99\u0c99\u289c\u289c" - + "\u289c\u289c\u289c\u0c99\u0c99\u289c\u289c\u289c\u289c\u4d01\u289c" - + "\u8281\u289c\u4d01\u289c\u8301\u8381\u4d01\u4d01\u2a9c\u2902\u4d01" - + "\u4d01\u289c\u4d01\u2902\u3a85\u3a85\u3a85\u3a85\u2902\u289c\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u848a\u850a\u858a\u860a\u868a\u870a\u878a" - + "\u880a\u888a\u890a\u898a\u8a0a\u8a8a\u8b0a\u8b8a\u8c0a\u8c8a\u8d0a" - + "\u8d8a\u8e0a\u8e8a\u8f0a\u8f8a\u900a\u908a\u910a\u918a\u920a\u928a" - + "\u930a\u938a\u940a\u0c99\u0c99\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59" + + "\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99" + + "\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59" + + "\u0c99\u0c99\u0455\u04d6\u0c99\u0c99\u0c99\u0455\u04d6\u0455\u04d6" + + "\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0c99" + + "\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99" + + "\u0c59\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99" + + "\u0c99\u0c99\u0c99\u0c59\u0c99\u0c59\u0c99\u0c59\u0c59\u0c59\u0c59" + + "\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59" + + "\u0c59\u0c59\u0c59\u0c99\u0c59\u0c99\u0c59\u0c59\u0c59\u0c99\u0c99" + + "\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c99\u0c99" + + "\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c59\u0c99\u0c99\u0c59" + + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59" + + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c99" + + "\u0c59\u0c99\u0c99\u0c59\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99" + + "\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c59" + + "\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99" + + "\u0c99\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c99" + + "\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c99\u0c99\u0c99" + + "\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99" + + "\u0c99\u0c99\u289c\u289c\u289c\u289c\u289c\u0c99\u0c99\u289c\u289c" + + "\u289c\u289c\u4e81\u289c\u8c81\u289c\u4e81\u289c\u8d01\u8d81\u4e81" + + "\u4e81\u2a9c\u2902\u4684\u4684\u2902\u2902\u2902\u2902\u2902\u2902" + + "\u2902\u2902\u2902\u2902\u3f80\u3f80\u3f80\u3f80\u7902\u7902\u7902" + + "\u7902\u7902\u7902\u7902\u7902\u7981\u7981\u7981\u7981\u7981\u7981" + + "\u7981\u7981\u7902\u7902\u7902\u7902\u7902\u7902\u3f80\u3f80\u7981" + + "\u7981\u7981\u7981\u7981\u7981\u3f80\u3f80\u2e82\u7902\u4a82\u7902" + + "\u4a82\u7902\u4a82\u7902\u3f80\u7981\u3f80\u7981\u3f80\u7981\u3f80" + + "\u7981\u7a02\u7a02\u7a82\u7a82\u7a82\u7a82\u7b02\u7b02\u7b82\u7b82" + + "\u7c02\u7c02\u7c82\u7c82\u3f80\u3f80\u7d02\u7d02\u7d02\u7d02\u7d02" + + "\u7d02\u7d02\u7d02\u7d83\u7d83\u7d83\u7d83\u7d83\u7d83\u7d83\u7d83" + + "\u7902\u7902\u2e82\u7e02\u2e82\u3f80\u2e82\u4a82\u7981\u7981\u7e81" + + "\u7e81\u7f03\u1a1b\u7f82\u1a1b\u7902\u7902\u4a82\u4a82\u3f80\u3f80" + + "\u2e82\u4a82\u7981\u7981\u8081\u8081\u3f80\u1a1b\u1a1b\u1a1b\u7902" + + "\u7902\u4a82\u4a82\u2e82\u5102\u2e82\u4a82\u7981\u7981\u8101\u8101" + + "\u5281\u1a1b\u1a1b\u1a1b\u020c\u020c\u020c\u020c\u020c\u020c\u020c" + + "\u82ac\u020c\u020c\u020c\u830c\u5f90\u5f90\u7290\u8390\u5614\u8434" + + "\u5614\u5614\u5614\u5614\u0298\u0298\u849d\u851e\u6b95\u849d\u849d" + + "\u851e\u6b95\u849d\u0598\u0298\u0598\u3f80\u0298\u0598\u0298\u0298" + + "\u5614\u6b95\u6c16\u6b95\u6c16\u6b95\u6c16\u0318\u0318\u0318\u0318" + + "\u0318\u0298\u0298\u0298\u0298\u29dd\u2d5e\u0298\u0298\u0298\u0298" + + "\u1a97\u890b\u2902\u3f80\u3f80\u898b\u8a0b\u8a8b\u8b0b\u8b8b\u8c0b" + + "\u0519\u0519\u0c99\u0455\u04d6\u2902\u890b\u2c8b\u2b0b\u2b8b\u898b" + + "\u8a0b\u8a8b\u8b0b\u8b8b\u8c0b\u0519\u0519\u0c99\u0455\u04d6\u3f80" + + "\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a" + + "\u039a\u039a\u039a\u039a\u039a\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u5407" + + "\u5407\u5407\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99" + + "\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59\u0c59" + + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59" + + "\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59" + + "\u0c59\u0c99\u0c99\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59" + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59" - + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99" - + "\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99" - + "\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59" - + "\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59" - + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59\u0c59" - + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c99\u0c99\u0c99\u0c99" - + "\u0c99\u0c99\u0c99\u289c\u289c\u0c99\u289c\u289c\u0c99\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u0c99\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u3e80\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59" - + "\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c59\u0519\u0519\u0c99\u0c59" + + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c99\u0c99\u0c99" + + "\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c59\u0519\u0519\u0c99\u0c59" + "\u0c59\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c59\u0c99" + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59" - + "\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c99\u0c59" - + "\u0c59\u0c59\u0c59\u0c59\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u0455\u04d6\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c" - + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c" - + "\u501c\u501c\u501c\u3e80\u3e80\u3e80\u3e80\u501c\u501c\u501c\u501c" - + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c" - + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u9c1c\u9c1c\u9c1c\u9c1c" - + "\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c" - + "\u9c1c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c" - + "\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u7f0b\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u0c59\u0c99\u0c59\u0c99\u0c59" - + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59" - + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59" - + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u039a\u039a\u0c99\u1a1b\u289c\u039a\u039a\u3e80\u289c\u0c99" - + "\u0c99\u0c99\u0c99\u289c\u289c\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u5b10\u5b10\u5b10\u289c\u289c\u3e80\u3e80" + + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c59\u0c59\u0c99" + + "\u0c99\u0455\u04d6\u0455\u04d6\u0c59\u0c99\u0c99\u0c99\u0c99\u4e81" + + "\u2902\u2902\u2902\u2902\u289c\u0c99\u3f80\u3f80\u3f80\u3f80\u8e0a" + + "\u8e8a\u8f0a\u8f8a\u900a\u908a\u910a\u918a\u920a\u928a\u930a\u938a" + + "\u940a\u948a\u950a\u958a\u960a\u968a\u970a\u978a\u980a\u988a\u990a" + + "\u998a\u9a0a\u9a8a\u9b0a\u9b8a\u9c0a\u9c8a\u9d0a\u9d8a\u9e0a\u9e8a" + + "\u9f0a\u9f8a\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u0c99\u289c\u289c\u0c99\u289c\u289c\u0c99\u289c" + + "\u289c\u289c\u289c\u289c\u289c\u289c\u0c99\u289c\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u0c59\u0c59\u0c59\u0c59\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u0455\u04d6\u289c\u289c\u289c\u289c\u289c" + + "\u289c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c" + + "\u539c\u539c\u539c\u539c\u539c\u539c\u289c\u289c\u3f80\u539c\ubc8b" + + "\ubd0b\ubd8b\ube0b\ube8b\ubf0b\ubf8b\uc00b\uc08b\uc10b\uc18b\uc20b" + + "\uc28b\uc30b\uc38b\u768b\u770b\u778b\uab8b\u289c\u3f80\u3f80\u3f80" + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u3e80\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u3e80\u289c" - + "\u3e80\u289c\u289c\u289c\u289c\u3e80\u3e80\u3e80\u289c\u3e80\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u840b\u9d0b" - + "\u9d8b\u9e0b\u9e8b\u9f0b\u9f8b\ua00b\ua08b\ua10b\u840b\u9d0b\u9d8b" - + "\u9e0b\u9e8b\u9f0b\u9f8b\ua00b\ua08b\ua10b\u289c\u3e80\u3e80\u3e80" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u0c59\u0c59\u0c59" - + "\u0c59\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" - + "\u501c\u289c\u289c\u289c\u289c\u289c\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u501c" - + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c" - + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c" - + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u3e80\u3e80" - + "\u3e80\u501c\u610b\u618b\u620b\u628b\ua80b\ua88b\ua90b\ua98b\uaa0b" - + "\u640b\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c" - + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c" - + "\u501c\u501c\u501c\u501c\u501c\u501c\u289c\u3e80\u289c\u289c\u289c" - + "\u3e80\u289c\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u2c8b\u2b0b\u2b8b\u7f8b\u800b\u808b" - + "\u810b\u818b\u820b\u968b\u970b\u978b\u980b\u988b\u990b\u998b\u9a0b" - + "\u9a8b\u9b0b\u9b8b\u2c8b\u2b0b\u2b8b\u7f8b\u800b\u808b\u810b\u818b" - + "\u820b\u968b\u970b\u978b\u980b\u988b\u990b\u998b\u9a0b\u9a8b\u9b0b" - + "\u9b8b\u501c\u501c\u501c\u501c\u020c\u0298\u0298\u0298\u289c\u4584" - + "\u3a85\ua18a\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455" - + "\u04d6\u289c\u289c\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455\u04d6" - + "\u2a14\u6615\u6696\u6696\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u4606\u4606\u1a1b\u1a1b" - + "\u4584\u4584\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85" - + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u501c\u501c\u630b" - + "\u630b\u630b\u630b\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c" - + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93" - + "\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93" - + "\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93" - + "\uaa93\uaa93\uaa93\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12" - + "\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12" - + "\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12" - + "\uab12\uab12\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305" - + "\u0519\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305" - + "\u5305\u5305\u5305\u3e80\u5305\u5305\u5305\u5305\u5305\u3e80\u5305" - + "\u3e80\u4606\u4606\u4606\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80" - + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u0298\u2a14\u2a14\u1a97\u1a97" - + "\u6615\u6696\u6615\u6696\u6615\u6696\u6615\u6696\u6615\u6696\u6615" - + "\u6696\u3e80\u3e80\u3e80\u3e80\u0298\u0298\u0298\u0298\u1a97\u1a97" - + "\u1a97\u0598\u0298\u0598\u3e80\u0298\u0598\u0298\u0298\u2a14\u6615" - + "\u6696\u6615\u6696\u6615\u6696\u0318\u0298\u0d01\u0d81\u0e01\u0e81" - + "\u0f01\u0f81\u1001\u1081\u1101\u1181\u1201\u1281\u1301\u1381\u1401" - + "\u1481\u1501\u1581\u1601\u1681\u1701\u1781\u1801\u1881\u1901\u1981" - + "\u6615\u0298\u6696\u1a1b\u1a97"; + + "\u289c\u289c\u289c\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\ua18b\ua20b\ua28b\ua30b" + + "\ua38b\ua40b\ua48b\ua50b\u2c8b\u2b0b\u2b8b\u898b\u8a0b\u8a8b\u8b0b" + + "\u8b8b\u8c0b\ua00b\ua08b\ua10b\ua18b\ua20b\ua28b\ua30b\ua38b\ua40b" + + "\ua48b\ua50b\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c" + + "\u539c\u539c\u539c\u289c\u289c\u289c\u289c\u539c\u539c\u539c\u539c" + + "\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u658b\u660b\u668b\u670b\ub28b\ub30b\ub38b\ub40b\ub48b\u688b" + + "\u539c\u539c\u539c\u539c\u539c\u539c\ua59c\ua59c\ua59c\ua59c\ua59c" + + "\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c" + + "\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c" + + "\ua61c\ua61c\ua61c\ua61c\ua61c\u890b\ua68b\ua70b\ua78b\ua80b\ua88b" + + "\u5614\u4684\u4684\u4684\u4684\u4684\u289c\u289c\ub10a\ub18a\ub20a" + + "\u4684\u3b05\u0298\u289c\u289c\u289c\u3f80\u3f80\u3f80\u289c\u3f80" + + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u3f80\u0c99\u0c99\u0c59" + + "\u0c59\u0c59\u0c59\u0455\u04d6\u0455\u04d6\u0455\u04d6\u3f80\u3f80" + + "\u3f80\u3f80\u020c\u0298\u0298\u0298\u289c\u4684\u3b05\uac0a\u0455" + + "\u04d6\u0455\u04d6\u0455\u04d6\u0455\u04d6\u289c\u289c\u0455\u04d6" + + "\u0455\u04d6\u0455\u04d6\u0455\u04d6\u5614\u6b95\u6c16\u6c16\u289c" + + "\ub50b\ub58b\ub60b\ub68b\ub70b\ub78b\ub80b\ub88b\ub90b\ub98b\uba0b" + + "\uba8b\ubb0b\ubb8b\ubc0b\uc413\uc413\uc413\uc413\uc413\uc413\uc413" + + "\uc413\uc413\uc413\uc413\uc413\uc413\uc413\uc413\uc413\uc492\uc492" + + "\uc492\uc492\uc492\uc492\uc492\uc492\uc492\uc492\uc492\uc492\uc492" + + "\uc492\uc492\uc492\u2e82\u2e82\u2e82\u4a82\u4a82\u2e82\u2e82\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u5705\u5705\u5705" + + "\u5705\u5705\u5705\u5705\u5705\u5705\u0519\u5705\u5705\u5705\u5705" + + "\u5705\u5705\u5705\u3f80\u5705\u5705\u5705\u5705\u5705\u3f80\u5705" + + "\u3f80\u0298\u5614\u5614\u1a97\u1a97\u6b95\u6c16\u6b95\u6c16\u6b95" + + "\u6c16\u6b95\u6c16\u6b95\u6c16\u6b95\u6c16\u0298\u0298\u6b95\u6c16" + + "\u0298\u0298\u0298\u0298\u1a97\u1a97\u1a97\u0298\u0298\u0519\u0614" + + "\u0c99\u0c99\u0c99\u3f80\u0298\u039a\u0318\u0298\u3f80\u3f80\u3f80" + + "\u3f80\u2282\u2302\u2382\u2402\u2482\u2502\u2582\u2602\u2682\u2702" + + "\u2782\u0455\u0c99\u04d6\u0c99\u0455\u039a\u039a\u0c99\u1a1b\u289c" + + "\u039a\u039a\u3f80\u289c\u0c99\u0c99\u0c99\u0c99\u289c\u289c\u3f80", + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\u0080\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\u0080\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\u0080\005\005\u0080\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\u0080\u0080\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u1981\u1981\u1981\u1981\u1981" + + "\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981" + + "\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981" + + "\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981" + + "\u1981\u1981\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02" + + "\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02" + + "\u1a02\u1a02\u1a02\u1a02\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\u0080\u0080\u0080\u0080\u0080\u0118\u0198\u021c\u0080" + + "\u0080\u0080\u0080\u028b\u030b\u038b\u040b\u048b\u050b\u058b\u060b" + + "\u068b\u070b\u078b\u080b\u088b\u090b\u098b\u0a0b\u0a8b\u0b0b\u0b8b" + + "\u0c0b\u0c8b\u0d0b\u0d8b\u0e0b\u0e8b\u0f0b\u0f8b\u100b\u108b\u110b" + + "\u118b\u120b\u128b\u130b\u138b\u140b\u148b\u150b\u158b\u160b\u168b" + + "\u170b\u178b\u180b\u188b\u0080\u0080\u0080\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u2008\u2008\u2086\u2086\u2086\u021c\u021c\u021c\u2008\u2008\u2008" + + "\u2008\u2008\u2008\u2110\u2110\u2110\u2110\u2110\u2110\u2110\u2110" + + "\u2086\u2086\u2086\u2086\u2086\u021c\u021c\u2086\u2086\u2086\u2086" + + "\u2086\u2086\u2086\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u2086\u2086\u2086\u2086\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u0080" + + "\u0080\u0080\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\005\005\005\005\005\005\005\005\005\005" + + "\u190a\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\u0080\u028b\u048b" + + "\u070b\u090b\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\u0080\u0118\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\u0080\u0080" + + "\u1a89\u1b09\u1b89\u1c09\u1c89\u1d09\u1d89\u1e09\u1e89\u1f09\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u1f85" + + "\u1f85\u1f85\u1f85\u1f85\u1f85\u0080\u0080\u1f85\u0080\u1f85\u1f85" + + "\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85" + + "\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85" + + "\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85" + + "\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u0080\u1f85" + + "\u1f85\u0080\u0080\u0080\u1f85\u0080\u0080\u1f85\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u2201\u2319\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2319\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2319\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u0080\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u0080\u0080\u0080\u0080\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u0080\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u0080\u2201\u0080\u0080\u0080\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u0080\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2201\u0080\u2201\u2201\u0080\u0080\u2201\u0080\u0080\u2201" + + "\u2201\u0080\u0080\u2201\u2201\u2201\u2201\u0080\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2282\u2282\u2282\u2282\u0080\u2282" + + "\u0080\u2282\u2282\u2282\u2282\u2201\u2201\u0080\u2201\u2201\u2201" + + "\u2201\u0080\u0080\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u0080\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u0080\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2201\u2201\u0080\u2201\u2201\u2201\u2201\u0080\u2282" + + "\u2282\u2282\u2319\u2282\u2282\u2282\u2282\u2282\u2282\u0080\u0080" + + "\u0080\u0080\u2389\u2409\u2489\u2509\u2589\u2609\u2689\u2709\u2789" + + "\u2809\u2389\u2409\u2489\u2509\u2589\u2609\u2689\u2709\u2789\u2809" + + "\u2389\u2409\u2489\u2509\u2589\u2609\u2689\u2709\u2789\u2809\u2389" + + "\u2409\u2489\u2509\u2589\u2609\u2689\u2709\u2789\u2809\u2389\u2409" + + "\u2489\u2509\u2589\u2609\u2689\u2709\u2789\u2809", + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\u0090\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090", + + "", + + ""}; /** * This is the attribute table for computing the numeric value of a @@ -780,8 +1296,8 @@ public interface CharData * Note that this is a signed value, but stored as an unsigned char * since this is a String literal. */ - String NUM_VALUE - = "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + String[] NUM_VALUE = new String[]{ + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + "\uffff\uffff\uffff\000\001\002\003\004\005\006\007" + "\010\011\uffff\uffff\012\013\014\015\016\017\020" + "\021\022\023\024\025\026\027\030\031\032\033" @@ -796,23 +1312,66 @@ public interface CharData + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" - + "\uffff\uffff\uffff\uffff\uffff\000\001\002\003\004\005" - + "\006\007\010\011\uffff\uffff\uffff\uffff\000\001\002" - + "\003\004\005\006\007\010\011\001\002\003\004" - + "\uffff\020\012d\u03e8\uffff\uffff\uffff\024\036(" - + "2 127) - throw new MalformedURLException(str + " : Invalid character"); if (c == '%') { if (i + 2 >= str.length()) @@ -160,6 +157,15 @@ public class Connection extends URLConnection throw new MalformedURLException(str + " : Invalid quoted character"); buf[pos++] = (byte) (hi * 16 + lo); } + else if (c > 127) { + try { + byte [] c_as_bytes = Character.toString(c).getBytes("utf-8"); + System.arraycopy(c_as_bytes, 0, buf, pos, c_as_bytes.length); + } + catch (java.io.UnsupportedEncodingException x2) { + throw (Error) new InternalError().initCause(x2); + } + } else buf[pos++] = (byte) c; } diff --git a/gnu/java/net/protocol/ftp/ActiveModeDTP.java b/gnu/java/net/protocol/ftp/ActiveModeDTP.java index 3755e8beb..aa3c412b6 100644 --- a/gnu/java/net/protocol/ftp/ActiveModeDTP.java +++ b/gnu/java/net/protocol/ftp/ActiveModeDTP.java @@ -84,6 +84,7 @@ final class ActiveModeDTP } this.connectionTimeout = connectionTimeout; acceptThread = new Thread(this, "ActiveModeDTP"); + acceptThread.setDaemon(true); acceptThread.start(); } diff --git a/gnu/java/net/protocol/ftp/FTPURLConnection.java b/gnu/java/net/protocol/ftp/FTPURLConnection.java index 62c40f19e..e30d3f4ac 100644 --- a/gnu/java/net/protocol/ftp/FTPURLConnection.java +++ b/gnu/java/net/protocol/ftp/FTPURLConnection.java @@ -1,5 +1,5 @@ /* FTPURLConnection.java -- - Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,8 +38,8 @@ exception statement from your version. */ package gnu.java.net.protocol.ftp; +import gnu.classpath.SystemProperties; import gnu.java.net.GetLocalHostAction; -import gnu.java.security.action.GetPropertyAction; import java.io.FileNotFoundException; import java.io.FilterInputStream; @@ -113,11 +113,9 @@ public class FTPURLConnection else { username = "anonymous"; - PrivilegedAction a = new GetPropertyAction("user.name"); - String systemUsername =(String) AccessController.doPrivileged(a); - a = new GetLocalHostAction(); + GetLocalHostAction a = new GetLocalHostAction(); InetAddress localhost =(InetAddress) AccessController.doPrivileged(a); - password = systemUsername + "@" + + password = SystemProperties.getProperty("user.name") + "@" + ((localhost == null) ? "localhost" : localhost.getHostName()); } connection = new FTPConnection(host, port); @@ -167,24 +165,13 @@ public class FTPURLConnection connect(); } String path = url.getPath(); - String filename = null; - int lsi = path.lastIndexOf('/'); - if (lsi != -1) + if (connection.changeWorkingDirectory(path)) { - filename = path.substring(lsi + 1); - path = path.substring(0, lsi); - if (!connection.changeWorkingDirectory(path)) - { - throw new FileNotFoundException(path); - } - } - if (filename != null && filename.length() > 0) - { - return this.new ClosingInputStream(connection.retrieve(filename)); + return this.new ClosingInputStream(connection.list(null)); } else { - return this.new ClosingInputStream(connection.list(null)); + return this.new ClosingInputStream(connection.retrieve(path)); } } @@ -198,20 +185,8 @@ public class FTPURLConnection { connect(); } - String dir = url.getPath(); - String filename = url.getFile(); - if (!connection.changeWorkingDirectory(dir)) - { - throw new FileNotFoundException(dir); - } - if (filename != null) - { - return this.new ClosingOutputStream(connection.store(filename)); - } - else - { - throw new FileNotFoundException(filename); - } + String path = url.getPath(); + return this.new ClosingOutputStream(connection.store(path)); } public String getRequestProperty(String key) diff --git a/gnu/java/net/protocol/http/ChunkedInputStream.java b/gnu/java/net/protocol/http/ChunkedInputStream.java index a4487d146..58cd2d681 100644 --- a/gnu/java/net/protocol/http/ChunkedInputStream.java +++ b/gnu/java/net/protocol/http/ChunkedInputStream.java @@ -1,5 +1,5 @@ /* ChunkedInputStream.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -55,9 +55,16 @@ public class ChunkedInputStream private static final byte CR = 0x0d; private static final byte LF = 0x0a; + /** Size of the chunk we're reading. */ int size; + /** Number of bytes we've read in this chunk. */ int count; + /** + * True when we should read meta-information, false when we should + * read data. + */ boolean meta; + /** True when we've hit EOF. */ boolean eof; Headers headers; @@ -84,12 +91,7 @@ public class ChunkedInputStream { return -1; } - int ret = (int) buf[0]; - if (ret < 0) - { - ret += 0x100; - } - return ret; + return 0xff & buf[0]; } public int read(byte[] buffer) @@ -142,17 +144,22 @@ public class ChunkedInputStream } else { - int diff = length - offset; - int max = size - count; - max = (diff < max) ? diff : max; - int len = (max > 0) ? in.read(buffer, offset, max) : 0; + int canRead = Math.min(size - count, length); + int len = in.read(buffer, offset, canRead); + if (len == -1) + { + // This is an error condition but it isn't clear what we + // should do with it. + eof = true; + return -1; + } count += len; if (count == size) { // Read CRLF int c1 = in.read(); int c2 = in.read(); - if (c1 == -1 && c2 == -1) + if (c1 == -1 || c2 == -1) { // EOF before CRLF: bad, but ignore eof = true; diff --git a/gnu/java/net/protocol/http/HTTPConnection.java b/gnu/java/net/protocol/http/HTTPConnection.java index 573a7918d..4ad87f8c0 100644 --- a/gnu/java/net/protocol/http/HTTPConnection.java +++ b/gnu/java/net/protocol/http/HTTPConnection.java @@ -1,5 +1,5 @@ /* HTTPConnection.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -53,7 +53,8 @@ import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.ListIterator; import java.util.List; import java.util.Map; @@ -164,7 +165,7 @@ public class HTTPConnection /** * The pool that this connection is a member of (if any). */ - private LinkedHashMap pool; + private Pool pool; /** * Creates a new HTTP connection. @@ -330,28 +331,227 @@ public class HTTPConnection return cookieManager; } + /** + * Manages a pool of HTTPConections. The pool will have a maximum + * size determined by the value of the maxConn parameter passed to + * the {@link #get} method. This value inevitably comes from the + * http.maxConnections system property. If the + * classpath.net.http.keepAliveTTL system property is set, that will + * be the maximum time (in seconds) that an idle connection will be + * maintained. + */ + static class Pool + { + /** + * Singleton instance of the pool. + */ + static Pool instance = new Pool(); + + /** + * The pool + */ + final LinkedList connectionPool = new LinkedList(); + + /** + * Maximum size of the pool. + */ + int maxConnections; + + /** + * If greater than zero, the maximum time a connection will remain + * int the pool. + */ + int connectionTTL; + + /** + * A thread that removes connections older than connectionTTL. + */ + class Reaper + implements Runnable + { + public void run() + { + synchronized (Pool.this) + { + try + { + do + { + while (connectionPool.size() > 0) + { + long currentTime = System.currentTimeMillis(); + + HTTPConnection c = + (HTTPConnection)connectionPool.getFirst(); + + long waitTime = c.timeLastUsed + + connectionTTL - currentTime; + + if (waitTime <= 0) + removeOldest(); + else + try + { + Pool.this.wait(waitTime); + } + catch (InterruptedException _) + { + // Ignore the interrupt. + } + } + // After the pool is empty, wait TTL to see if it + // is used again. This is because in the + // situation where a single thread is making HTTP + // requests to the same server it can remove the + // connection from the pool before the Reaper has + // a chance to start. This would cause the Reaper + // to exit if it were not for this extra delay. + // The result would be starting a Reaper thread + // for each HTTP request. With the delay we get + // at most one Reaper created each TTL. + try + { + Pool.this.wait(connectionTTL); + } + catch (InterruptedException _) + { + // Ignore the interrupt. + } + } + while (connectionPool.size() > 0); + } + finally + { + reaper = null; + } + } + } + } + + Reaper reaper; + + /** + * Private constructor to ensure singleton. + */ + private Pool() + { + } + + /** + * Tests for a matching connection. + * + * @param c connection to match. + * @param h the host name. + * @param p the port. + * @param sec true if using https. + * + * @return true if c matches h, p, and sec. + */ + private static boolean matches(HTTPConnection c, + String h, int p, boolean sec) + { + return h.equals(c.hostname) && (p == c.port) && (sec == c.secure); + } + + /** + * Get a pooled HTTPConnection. If there is an existing idle + * connection to the requested server it is returned. Otherwise a + * new connection is created. + * + * @param hostname the name of the host to connect to + * @param port the port on the host to connect to + * @param secure whether to use a secure connection + * + * @return the HTTPConnection. + */ + synchronized HTTPConnection get(String host, + int port, + boolean secure) + { + String ttl = + SystemProperties.getProperty("classpath.net.http.keepAliveTTL"); + connectionTTL = (ttl != null && ttl.length() > 0) ? + 1000 * Math.max(1, Integer.parseInt(ttl)) : 10000; + + String mc = SystemProperties.getProperty("http.maxConnections"); + maxConnections = (mc != null && mc.length() > 0) ? + Math.max(Integer.parseInt(mc), 1) : 5; + if (maxConnections < 1) + maxConnections = 1; + + HTTPConnection c = null; + + ListIterator it = connectionPool.listIterator(0); + while (it.hasNext()) + { + HTTPConnection cc = (HTTPConnection)it.next(); + if (matches(cc, host, port, secure)) + { + c = cc; + break; + } + } + if (c == null) + { + c = new HTTPConnection(host, port, secure); + c.setPool(this); + } + return c; + } + + /** + * Put an idle HTTPConnection back into the pool. If this causes + * the pool to be come too large, the oldest connection is removed + * and closed. + * + */ + synchronized void put(HTTPConnection c) + { + c.timeLastUsed = System.currentTimeMillis(); + connectionPool.addLast(c); + + // maxConnections must always be >= 1 + while (connectionPool.size() >= maxConnections) + removeOldest(); + + if (connectionTTL > 0 && null == reaper) { + // If there is a connectionTTL, then the reaper has removed + // any stale connections, so we don't have to check for stale + // now. We do have to start a reaper though, as there is not + // one running now. + reaper = new Reaper(); + Thread t = new Thread(reaper, "HTTPConnection.Reaper"); + t.setDaemon(true); + t.start(); + } + } + + /** + * Remove the oldest connection from the pool and close it. + */ + void removeOldest() + { + HTTPConnection cx = (HTTPConnection)connectionPool.removeFirst(); + try + { + cx.closeConnection(); + } + catch (IOException ioe) + { + // Ignore it. We are just cleaning up. + } + } + } + /** * The number of times this HTTPConnection has be used via keep-alive. */ int useCount; /** - * Generates a key for connections in the connection pool. - * - * @param h the host name. - * @param p the port. - * @param sec true if using https. - * - * @return the key. + * If this HTTPConnection is in the pool, the time it was put there. */ - static Object getPoolKey(String h, int p, boolean sec) - { - StringBuilder buf = new StringBuilder(sec ? "https://" : "http://"); - buf.append(h); - buf.append(':'); - buf.append(p); - return buf.toString(); - } + long timeLastUsed; /** * Set the connection pool that this HTTPConnection is a member of. @@ -360,7 +560,7 @@ public class HTTPConnection * * @param p the pool. */ - void setPool(LinkedHashMap p) + void setPool(Pool p) { pool = p; } @@ -374,25 +574,20 @@ public class HTTPConnection { if (pool != null) { - synchronized (pool) + useCount++; + pool.put(this); + + } + else + { + // If there is no pool, just close. + try { - useCount++; - Object key = HTTPConnection.getPoolKey(hostname, port, secure); - pool.put(key, this); - while (pool.size() >= HTTPURLConnection.maxConnections) - { - // maxConnections must always be >= 1 - Object lru = pool.keySet().iterator().next(); - HTTPConnection c = (HTTPConnection)pool.remove(lru); - try - { - c.closeConnection(); - } - catch (IOException ioe) - { - // Ignore it. We are just cleaning up. - } - } + closeConnection(); + } + catch (IOException ioe) + { + // Ignore it. We are just cleaning up. } } } diff --git a/gnu/java/net/protocol/http/HTTPURLConnection.java b/gnu/java/net/protocol/http/HTTPURLConnection.java index d5da7d61a..b28c3809d 100644 --- a/gnu/java/net/protocol/http/HTTPURLConnection.java +++ b/gnu/java/net/protocol/http/HTTPURLConnection.java @@ -1,5 +1,5 @@ /* HTTPURLConnection.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -70,13 +70,6 @@ public class HTTPURLConnection extends HttpsURLConnection implements HandshakeCompletedListener { - - /** - * Pool of reusable connections, used if keepAlive is true. - */ - private static final LinkedHashMap connectionPool = new LinkedHashMap(); - static int maxConnections; - /* * The underlying connection. */ @@ -134,9 +127,6 @@ public class HTTPURLConnection agent = System.getProperty("http.agent"); String ka = System.getProperty("http.keepAlive"); keepAlive = !(ka != null && "false".equals(ka)); - String mc = System.getProperty("http.maxConnections"); - maxConnections = (mc != null && mc.length() > 0) ? - Math.max(Integer.parseInt(mc), 1) : 5; return null; } @@ -254,8 +244,24 @@ public class HTTPURLConnection } } - if (response.getCodeClass() == 3 && getInstanceFollowRedirects()) + if (response.isRedirect() && getInstanceFollowRedirects()) { + // Read the response body, if there is one. If the + // redirect points us back at the same server, we will use + // the cached connection, so we must make sure there is no + // pending data in it. + InputStream body = response.getBody(); + if (body != null) + { + byte[] ignore = new byte[1024]; + while (true) + { + int n = body.read(ignore, 0, ignore.length); + if (n == -1) + break; + } + } + // Follow redirect String location = response.getHeader("Location"); if (location != null) @@ -333,16 +339,13 @@ public class HTTPURLConnection { responseSink = response.getBody(); - if (response.getCode() == 404) - { - errorSink = responseSink; - throw new FileNotFoundException(url.toString()); - } + if (response.isError()) + errorSink = responseSink; } } while (retry); connected = true; - } + } /** * Returns a connection, from the pool if necessary. @@ -353,16 +356,7 @@ public class HTTPURLConnection HTTPConnection connection; if (keepAlive) { - Object key = HTTPConnection.getPoolKey(host, port, secure); - synchronized (connectionPool) - { - connection = (HTTPConnection) connectionPool.remove(key); - if (connection == null) - { - connection = new HTTPConnection(host, port, secure); - connection.setPool(connectionPool); - } - } + connection = HTTPConnection.Pool.instance.get(host, port, secure); } else { @@ -427,21 +421,31 @@ public class HTTPURLConnection public String getRequestProperty(String key) { + if (key == null) + return null; + return requestHeaders.getValue(key); } public Map getRequestProperties() { + if (connected) + throw new IllegalStateException("Already connected"); + return requestHeaders; } public void setRequestProperty(String key, String value) { + super.setRequestProperty(key, value); + requestHeaders.put(key, value); } public void addRequestProperty(String key, String value) { + super.addRequestProperty(key, value); + String old = requestHeaders.getValue(key); if (old == null) { @@ -493,6 +497,17 @@ public class HTTPURLConnection { throw new ProtocolException("doInput is false"); } + + if (response.isError()) + { + int code = response.getCode(); + if (code == 404 || code == 410) + throw new FileNotFoundException(url.toString()); + + throw new IOException("Server returned HTTP response code " + code + + " for URL " + url.toString()); + } + return responseSink; } diff --git a/gnu/java/net/protocol/http/Request.java b/gnu/java/net/protocol/http/Request.java index b9441b3f7..ea18b7d42 100644 --- a/gnu/java/net/protocol/http/Request.java +++ b/gnu/java/net/protocol/http/Request.java @@ -1,5 +1,5 @@ /* Request.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -93,11 +93,6 @@ public class Request */ protected RequestBodyWriter requestBodyWriter; - /** - * Request body negotiation threshold for 100-continue expectations. - */ - protected int requestBodyNegotiationThreshold; - /** * Map of response header handlers. */ @@ -127,7 +122,6 @@ public class Request this.path = path; requestHeaders = new Headers(); responseHeaderHandlers = new HashMap(); - requestBodyNegotiationThreshold = 4096; } /** @@ -250,21 +244,6 @@ public class Request this.authenticator = authenticator; } - /** - * Sets the request body negotiation threshold. - * If this is set, it determines the maximum size that the request body - * may be before body negotiation occurs(via the - * 100-continue expectation). This ensures that a large - * request body is not sent when the server wouldn't have accepted it - * anyway. - * @param threshold the body negotiation threshold, or <=0 to disable - * request body negotation entirely - */ - public void setRequestBodyNegotiationThreshold(int threshold) - { - requestBodyNegotiationThreshold = threshold; - } - /** * Dispatches this request. * A request can only be dispatched once; calling this method a second @@ -291,10 +270,10 @@ public class Request if (requestBodyWriter != null) { contentLength = requestBodyWriter.getContentLength(); - if (contentLength > requestBodyNegotiationThreshold) + String expect = getHeader("Expect"); + if (expect != null && expect.equals("100-continue")) { expectingContinue = true; - setHeader("Expect", "100-continue"); } else { @@ -528,6 +507,9 @@ public class Request throw new ProtocolException("Unsupported Content-Encoding: " + contentCoding); } + // Remove the Content-Encoding header because the content is + // no longer compressed. + responseHeaders.remove("Content-Encoding"); } return in; } diff --git a/gnu/java/net/protocol/http/Response.java b/gnu/java/net/protocol/http/Response.java index 58d74542c..76fac9344 100644 --- a/gnu/java/net/protocol/http/Response.java +++ b/gnu/java/net/protocol/http/Response.java @@ -1,5 +1,5 @@ /* Response.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -188,6 +188,28 @@ public class Response { return headers.getDateValue(name); } + + /** + * Tests whether this response indicates a redirection. + * + * @return true if, false otherwise. + */ + public boolean isRedirect() + { + return (code != 304 && getCodeClass() == 3); + } + + /** + * Tests whether this response indicates an error. + * Errors are the response codes 4xx - Client error and + * 5xx - Server error. + * + * @return true if, false otherwise. + */ + public boolean isError() + { + return (getCodeClass() == 4 || getCodeClass() == 5); + } /** * Returns an InputStream that returns the body of the response. diff --git a/gnu/java/nio/charset/Provider.java b/gnu/java/nio/charset/Provider.java index 01c2650a8..ad3b1da84 100644 --- a/gnu/java/nio/charset/Provider.java +++ b/gnu/java/nio/charset/Provider.java @@ -81,7 +81,8 @@ public final class Provider extends CharsetProvider */ private boolean extendedLoaded; - private Provider () + // Package private to avoid an accessor method in PrivilegedAction below. + Provider () { extendedLoaded = false; canonicalNames = new HashMap (); diff --git a/gnu/java/rmi/registry/RegistryImpl.java b/gnu/java/rmi/registry/RegistryImpl.java index 0c94434d8..7dcca612a 100644 --- a/gnu/java/rmi/registry/RegistryImpl.java +++ b/gnu/java/rmi/registry/RegistryImpl.java @@ -111,7 +111,7 @@ public static void version() { + System.getProperty("java.vm.name") + ") " + System.getProperty("java.vm.version")); - System.out.println("Copyright 2005 Free Software Foundation, Inc."); + System.out.println("Copyright 2006 Free Software Foundation, Inc."); System.out.println("This is free software; see the source for copying conditions. There is NO"); System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); System.exit(0); diff --git a/gnu/java/rmi/server/CombinedClassLoader.java b/gnu/java/rmi/server/CombinedClassLoader.java new file mode 100644 index 000000000..3d2e37d53 --- /dev/null +++ b/gnu/java/rmi/server/CombinedClassLoader.java @@ -0,0 +1,149 @@ +/* CombinedClassLoader.java -- Multiple class loader support for proxy. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.rmi.server; + +import java.io.IOException; +import java.net.URL; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.ArrayList; + +/** + * This class supports the multiple class loaders to load the resources. It is + * used for constructing proxy classes that implement interfaces, loaded by + * the several different class loaders. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CombinedClassLoader extends ClassLoader +{ + /** + * The class loader array. + */ + ClassLoader[] loaders; + + /** + * Create a new combined class loader that uses the given collection of + * loaders to load the classes and resources. The loader order is equal to + * the order, returned by the collection interator. The duplicate loaders + * are discarded and the system class loader is added as the last loader. + * + * @param a_loaders the loadery collection (may contain duplicate instances + * that will be discarded. + */ + public CombinedClassLoader(Collection a_loaders) + { + ArrayList sLoaders = new ArrayList(a_loaders.size()); + + Iterator iter = a_loaders.iterator(); + Object cl; + while (iter.hasNext()) + { + cl = iter.next(); + if (!sLoaders.contains(cl)) + sLoaders.add(iter.next()); + } + + loaders = new ClassLoader[sLoaders.size()]; + + for (int i = 0; i < loaders.length; i++) + loaders[i] = (ClassLoader) sLoaders.get(i); + } + + /** + * Find the class with the given name. + */ + protected Class findClass(String name) throws ClassNotFoundException + { + for (int i = 0; i < loaders.length; i++) + { + try + { + return findClass(name); + } + catch (ClassNotFoundException e) + { + // try another. + } + } + return super.findClass(name); + } + + /** + * Find the library with the given name + */ + protected String findLibrary(String name) + { + for (int i = 0; i < loaders.length; i++) + { + String lib = findLibrary(name); + if (lib != null) + return lib; + } + return super.findLibrary(name); + } + + /** + * Find resource with the given name. + */ + protected URL findResource(String name) + { + for (int i = 0; i < loaders.length; i++) + { + URL resource = findResource(name); + if (resource != null) + return resource; + } + return super.findResource(name); + } + + /** + * Find resources with the given name. + */ + protected Enumeration findResources(String name) throws IOException + { + for (int i = 0; i < loaders.length; i++) + { + Enumeration resource = findResources(name); + if (resource != null) + return resource; + } + return super.findResources(name); } +} diff --git a/gnu/java/rmi/server/RMIObjectInputStream.java b/gnu/java/rmi/server/RMIObjectInputStream.java index 587d57fc7..e76535447 100644 --- a/gnu/java/rmi/server/RMIObjectInputStream.java +++ b/gnu/java/rmi/server/RMIObjectInputStream.java @@ -46,6 +46,7 @@ import java.io.ObjectStreamClass; import java.lang.reflect.Proxy; import java.net.MalformedURLException; import java.rmi.server.RMIClassLoader; +import java.util.ArrayList; public class RMIObjectInputStream extends ObjectInputStream { @@ -76,28 +77,51 @@ protected Object getAnnotation() return readObject(); } -protected Class resolveProxyClass(String intfs[]) - throws IOException, ClassNotFoundException -{ - String annotation = (String)getAnnotation(); - + + protected Class resolveProxyClass(String intfs[]) throws IOException, + ClassNotFoundException + { + String annotation = (String) getAnnotation(); + Class clss[] = new Class[intfs.length]; - if(annotation == null) - clss[0] = RMIClassLoader.loadClass(intfs[0]); - else - clss[0] = RMIClassLoader.loadClass(annotation, intfs[0]); - - //assume all interfaces can be loaded by the same classloader - ClassLoader loader = clss[0].getClassLoader(); + for (int i = 0; i < intfs.length; i++) - clss[i] = Class.forName(intfs[i], false, loader); - - try { - return Proxy.getProxyClass(loader, clss); - } catch (IllegalArgumentException e) { - throw new ClassNotFoundException(null, e); - } -} + { + if (annotation == null) + clss[i] = RMIClassLoader.loadClass(intfs[i]); + else + clss[i] = RMIClassLoader.loadClass(annotation, intfs[i]); + } + + ClassLoader loader; + + if (clss.length > 0) + { + // Chain all class loaders (they may differ). + ArrayList loaders = new ArrayList(intfs.length); + ClassLoader cx; + for (int i = 0; i < clss.length; i++) + { + cx = clss[i].getClassLoader(); + if (!loaders.contains(cx)) + { + loaders.add(0, cx); + } + } + loader = new CombinedClassLoader(loaders); + } + else + loader = ClassLoader.getSystemClassLoader(); + + try + { + return Proxy.getProxyClass(loader, clss); + } + catch (IllegalArgumentException e) + { + throw new ClassNotFoundException(null, e); + } + } protected Object readValue(Class valueClass) throws IOException, ClassNotFoundException { if(valueClass.isPrimitive()){ diff --git a/gnu/java/rmi/server/UnicastServerRef.java b/gnu/java/rmi/server/UnicastServerRef.java index 1f6eedec6..dcb12a53b 100644 --- a/gnu/java/rmi/server/UnicastServerRef.java +++ b/gnu/java/rmi/server/UnicastServerRef.java @@ -1,5 +1,5 @@ /* UnicastServerRef.java -- - Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 2004 + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,263 +43,433 @@ import java.io.ObjectInputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.server.ObjID; import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.RemoteObjectInvocationHandler; import java.rmi.server.RemoteRef; import java.rmi.server.RemoteServer; import java.rmi.server.RemoteStub; import java.rmi.server.ServerNotActiveException; -import java.rmi.server.ServerRef; import java.rmi.server.Skeleton; +import java.util.HashSet; import java.util.Hashtable; +import java.util.Iterator; public class UnicastServerRef - extends UnicastRef - implements ServerRef{ //SHOULD implement ServerRef + extends UnicastRef +{ + + /** + * Use GNU Classpath v 0.20 SVUID for interoperability + */ + private static final long serialVersionUID = - 5585608108300801246L; + + /** + * The class array, defining parameters of the jdk 1.2 RMI stub constructor. + */ + private static final Class[] stubprototype = new Class[] { RemoteRef.class }; + + /** + * The exported remote object itself. + */ + Remote myself; // save the remote object itself + + /** + * The skeleton (if any), associated with the exported remote object. + */ + private Skeleton skel; + + /** + * The stub, associated with the exported remote object (may be proxy class). + */ + private Remote stub; + + /** + * The method table (RMI hash code to method) of the methods of the + * exported object. + */ + private Hashtable methods = new Hashtable(); + + /** + * Used by serialization. + */ + UnicastServerRef() + { + } + + public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) + throws RemoteException + { + super(id); + manager = UnicastConnectionManager.getInstance(port, ssf); + } + + /** + * Export the object and return its remote stub. The method tries to locate + * existing stubs and skeletons. If this fails, the method instantiates the + * proxy stub class. + * + * Stubs and skeletons are always ignored (even if present) if the + * java.rmi.server.ignoreStubClasses property is set to true. + * + * @param obj the object being exported. + * @return the stub (existing class or proxy) of the exported object. + * @throws RemoteException if the export failed due any reason + */ + public Remote exportObject(Remote obj) throws RemoteException + { + if (myself == null) + { + myself = obj; + // Save it to server manager, to let client calls in the same VM to + // issue + // local call + manager.serverobj = obj; + + String ignoreStubs; + + ClassLoader loader =obj.getClass().getClassLoader(); + + // Stubs are always searched for the bootstrap classes that may have + // obsolete pattern and may still need also skeletons. + if (loader==null) + ignoreStubs = "false"; + else + ignoreStubs = System.getProperty("java.rmi.server.ignoreStubClasses", + "false"); + + if (! ignoreStubs.equals("true")) + { + // Find and install the stub + Class cls = obj.getClass(); + + // where ist the _Stub? (check superclasses also) + Class expCls = expCls = findStubSkelClass(cls); + + if (expCls != null) + { + stub = (RemoteStub) getHelperClass(expCls, "_Stub"); + // Find and install the skeleton (if there is one) + skel = (Skeleton) getHelperClass(expCls, "_Skel"); + } + } + + if (stub == null) + stub = createProxyStub(obj.getClass(), this); + + // Build hash of methods which may be called. + buildMethodHash(obj.getClass(), true); + + // Export it. + UnicastServer.exportObject(this); + } -final static private Class[] stubprototype = new Class[] { RemoteRef.class }; - -Remote myself; //save the remote object itself -private Skeleton skel; -private RemoteStub stub; -private Hashtable methods = new Hashtable(); - -/** - * Used by serialization. - */ -UnicastServerRef() -{ -} - -public UnicastServerRef(ObjID id, int port, RMIServerSocketFactory ssf) throws RemoteException { - super(id); - manager = UnicastConnectionManager.getInstance(port, ssf); -} - -public RemoteStub exportObject(Remote obj) throws RemoteException { - if (myself == null) { - myself = obj; - // Save it to server manager, to let client calls in the same VM to issue - // local call - manager.serverobj = obj; - - // Find and install the stub - Class cls = obj.getClass(); - Class expCls; - try { - // where ist the _Stub? (check superclasses also) - expCls = findStubSkelClass(cls); - } catch (Exception ex) { - throw new RemoteException("can not find stubs for class: " + cls, ex); - } - - stub = (RemoteStub)getHelperClass(expCls, "_Stub"); - if (stub == null) { - throw new RemoteException("failed to export: " + cls); - } - - // Find and install the skeleton (if there is one) - skel = (Skeleton)getHelperClass(expCls, "_Skel"); - - // Build hash of methods which may be called. - buildMethodHash(obj.getClass(), true); - - // Export it. - UnicastServer.exportObject(this); - } - - return (stub); -} - -public RemoteStub exportObject(Remote remote, Object obj) - throws RemoteException -{ - //FIX ME - return exportObject(remote); -} - -public RemoteStub getStub(){ return stub; -} - - -public boolean unexportObject(Remote obj, boolean force) { + } + + /** + * Get the stub (actual class or proxy) of the exported remote object. + * + * @return the remote stub (null if exportObject has not been called). + */ + public Remote getStub() + { + return stub; + } + + /** + * Unexport the object (remove methods from the method hashcode table + * and call UnicastServer.unexportObject. + * + * @param obj the object being unexported + * @param force passed to the UnicastServer.unexportObject. + * @return value, returned by the UnicastServer.unexportObject. + */ + public boolean unexportObject(Remote obj, boolean force) + { // Remove all hashes of methods which may be called. buildMethodHash(obj.getClass(), false); return UnicastServer.unexportObject(this, force); -} - -/** -* -* The Subs/Skels might not there for the actual class, but maybe -* for one of the superclasses. -* -*/ -private Class findStubSkelClass(Class startCls) throws Exception { - Class cls = startCls; - - while (true) { - try { - String stubClassname = cls.getName() + "_Stub"; - ClassLoader cl = cls.getClassLoader(); - Class scls = cl == null ? Class.forName(stubClassname) - : cl.loadClass(stubClassname); - return cls; // found it - } catch (ClassNotFoundException e) { - Class superCls = cls.getSuperclass(); - if (superCls == null - || superCls == java.rmi.server.UnicastRemoteObject.class) - { - throw new Exception("Neither " + startCls - + " nor one of their superclasses (like" + cls + ")" - + " has a _Stub"); - } - cls = superCls; - } - } -} - - - -private Object getHelperClass(Class cls, String type) { - try { - String classname = cls.getName(); - ClassLoader cl = cls.getClassLoader(); - Class scls = cl == null ? Class.forName(classname + type) - : cl.loadClass(classname + type); - if (type.equals("_Stub")) { - try { - // JDK 1.2 stubs - Constructor con = scls.getConstructor(stubprototype); - return (con.newInstance(new Object[]{this})); - } - catch (NoSuchMethodException e) { - } - catch (InstantiationException e) { - } - catch (IllegalAccessException e) { - } - catch (IllegalArgumentException e) { - } - catch (InvocationTargetException e) { - } - // JDK 1.1 stubs - RemoteStub stub = (RemoteStub)scls.newInstance(); - UnicastRemoteStub.setStubRef(stub, this); - return (stub); - } - else { - // JDK 1.1 skel - return (scls.newInstance()); - } - } - catch (ClassNotFoundException e) { - } - catch (InstantiationException e) { - } - catch (IllegalAccessException e) { - } - return (null); -} - - - -public String getClientHost() throws ServerNotActiveException { - return RemoteServer.getClientHost(); -} - -private void buildMethodHash(Class cls, boolean build) { - Method[] meths = cls.getMethods(); - for (int i = 0; i < meths.length; i++) { - /* Don't need to include any java.xxx related stuff */ - if (meths[i].getDeclaringClass().getName().startsWith("java.")) { - continue; - } - long hash = RMIHashes.getMethodHash(meths[i]); - if(build) - methods.put(new Long (hash), meths[i]); - else - methods.remove(new Long (hash)); -//System.out.println("meth = " + meths[i] + ", hash = " + hash); - } -} - -Class getMethodReturnType(int method, long hash) throws Exception -{ - if (method == -1) { - Method meth = (Method)methods.get(new Long (hash)); + } + + /** + * Return the class in the hierarchy for that the stub class is defined. + * The Subs/Skels might not there for the actual class, but maybe for one of + * the superclasses. + * + * @return the class having stub defined, null if none. + */ + private Class findStubSkelClass(Class startCls) + { + Class cls = startCls; + + while (true) + { + try + { + String stubClassname = cls.getName() + "_Stub"; + ClassLoader cl = cls.getClassLoader(); + Class scls = cl == null ? Class.forName(stubClassname) + : cl.loadClass(stubClassname); + return cls; // found it + } + catch (ClassNotFoundException e) + { + Class superCls = cls.getSuperclass(); + if (superCls == null + || superCls == java.rmi.server.UnicastRemoteObject.class) + { + return null; + } + cls = superCls; + } + } + } + + /** + * Get the helper (assisting) class with the given type. + * + * @param cls the class, for that the helper class is requested. This class + * and the requested helper class must share the same class loader. + * + * @param type the type of the assisting helper. The only currently supported + * non deprecated value is "_Stub" (load jdk 1.1 or 1.2 RMI stub). Another + * (deprecated) value is "_Skel" (load skeleton). + * + * @return the instantiated instance of the helper class or null if the + * helper class cannot be found or instantiated. + */ + private Object getHelperClass(Class cls, String type) + { + try + { + String classname = cls.getName(); + ClassLoader cl = cls.getClassLoader(); + Class scls = cl == null ? Class.forName(classname + type) + : cl.loadClass(classname + type); + if (type.equals("_Stub")) + { + try + { + // JDK 1.2 stubs + Constructor con = scls.getConstructor(stubprototype); + return (con.newInstance(new Object[] { this })); + } + catch (NoSuchMethodException e) + { + } + catch (InstantiationException e) + { + } + catch (IllegalAccessException e) + { + } + catch (IllegalArgumentException e) + { + } + catch (InvocationTargetException e) + { + } + // JDK 1.1 stubs + RemoteStub stub = (RemoteStub) scls.newInstance(); + UnicastRemoteStub.setStubRef(stub, this); + return (stub); + } + else + { + // JDK 1.1 skel + return (scls.newInstance()); + } + } + catch (ClassNotFoundException e) + { + } + catch (InstantiationException e) + { + } + catch (IllegalAccessException e) + { + } + return (null); + } + + public String getClientHost() throws ServerNotActiveException + { + return RemoteServer.getClientHost(); + } + + /** + * Build the method has code table and put it into {@link #methods} + * (mapping RMI hashcode tos method). The same method is used to remove + * the table. + * + * @param cls the class for that the method table is built. + * @param build if true, the class methods are added to the table. If + * false, they are removed from the table. + */ + private void buildMethodHash(Class cls, boolean build) + { + Method[] meths = cls.getMethods(); + for (int i = 0; i < meths.length; i++) + { + /* Don't need to include any java.xxx related stuff */ + if (meths[i].getDeclaringClass().getName().startsWith("java.")) + { + continue; + } + long hash = RMIHashes.getMethodHash(meths[i]); + if (build) + methods.put(new Long(hash), meths[i]); + else + methods.remove(new Long(hash)); + // System.out.println("meth = " + meths[i] + ", hash = " + hash); + } + } + + Class getMethodReturnType(int method, long hash) throws Exception + { + if (method == - 1) + { + Method meth = (Method) methods.get(new Long(hash)); return meth.getReturnType(); - }else - return null; -} - -public Object incomingMessageCall(UnicastConnection conn, int method, long hash) throws Exception { -//System.out.println("method = " + method + ", hash = " + hash); - // If method is -1 then this is JDK 1.2 RMI - so use the hash - // to locate the method - if (method == -1) { - Method meth = (Method)methods.get(new Long (hash)); -//System.out.println("class = " + myself.getClass() + ", meth = " + meth); - if (meth == null) { - throw new NoSuchMethodException(); - } - - ObjectInputStream in = conn.getObjectInputStream(); - int nrargs = meth.getParameterTypes().length; - Object[] args = new Object[nrargs]; - for (int i = 0; i < nrargs; i++) { - /** - * For debugging purposes - we don't handle CodeBases - * quite right so we don't always find the stubs. This - * lets us know that. - */ - try { - // need to handle primitive types - args[i] = ((RMIObjectInputStream)in).readValue(meth.getParameterTypes()[i]); - - } - catch (Exception t) { - t.printStackTrace(); - throw t; - } - } - //We must reinterpret the exception thrown by meth.invoke() - //return (meth.invoke(myself, args)); - Object ret = null; - try{ - ret = meth.invoke(myself, args); - }catch(InvocationTargetException e){ - Throwable cause = e.getTargetException(); - if (cause instanceof Exception) { - throw (Exception)cause; - } - else if (cause instanceof Error) { - throw (Error)cause; - } - else { - throw new Error("The remote method threw a java.lang.Throwable that is neither java.lang.Exception nor java.lang.Error.", e); - } - } - return ret; - } - // Otherwise this is JDK 1.1 style RMI - we find the skeleton - // and invoke it using the method number. We wrap up our - // connection system in a UnicastRemoteCall so it appears in a - // way the Skeleton can handle. - else { - if (skel == null) { - throw new NoSuchMethodException(); - } - UnicastRemoteCall call = new UnicastRemoteCall(conn); - skel.dispatch(myself, call, method, hash); - if (!call.isReturnValue()) - return RMIVoidValue.INSTANCE; - else - return (call.returnValue()); - } -} + } + else + return null; + } + + public Object incomingMessageCall(UnicastConnection conn, int method, + long hash) throws Exception + { + // System.out.println("method = " + method + ", hash = " + hash); + // If method is -1 then this is JDK 1.2 RMI - so use the hash + // to locate the method + if (method == - 1) + { + Method meth = (Method) methods.get(new Long(hash)); + // System.out.println("class = " + myself.getClass() + ", meth = " + + // meth); + if (meth == null) + { + throw new NoSuchMethodException(); + } + + ObjectInputStream in = conn.getObjectInputStream(); + int nrargs = meth.getParameterTypes().length; + Object[] args = new Object[nrargs]; + for (int i = 0; i < nrargs; i++) + { + /** + * For debugging purposes - we don't handle CodeBases quite right so + * we don't always find the stubs. This lets us know that. + */ + try + { + // need to handle primitive types + args[i] = ((RMIObjectInputStream) in) + .readValue(meth.getParameterTypes()[i]); + + } + catch (Exception t) + { + t.printStackTrace(); + throw t; + } + } + //We must reinterpret the exception thrown by meth.invoke() + //return (meth.invoke(myself, args)); + Object ret = null; + try + { + ret = meth.invoke(myself, args); + } + catch (InvocationTargetException e) + { + Throwable cause = e.getTargetException(); + if (cause instanceof Exception) + { + throw (Exception) cause; + } + else if (cause instanceof Error) + { + throw (Error) cause; + } + else + { + throw new Error( + "The remote method threw a java.lang.Throwable that"+ + " is neither java.lang.Exception nor java.lang.Error.", + e); + } + } + return ret; + } + // Otherwise this is JDK 1.1 style RMI - we find the skeleton + // and invoke it using the method number. We wrap up our + // connection system in a UnicastRemoteCall so it appears in a + // way the Skeleton can handle. + else + { + if (skel == null) + { + throw new NoSuchMethodException(); + } + UnicastRemoteCall call = new UnicastRemoteCall(conn); + skel.dispatch(myself, call, method, hash); + if (! call.isReturnValue()) + return RMIVoidValue.INSTANCE; + else + return (call.returnValue()); + } + } + + /** + * Create the 1.2 proxy stub in the case when the pre-generated stub is not + * available of the system is explicitly instructed to use proxy stubs. + * + * @param stubFor the class for that the proxy class must be constructed. + * @param reference the remote reference, used to find the given object + * + * @return the applicable proxy stub. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ + Remote createProxyStub(Class stubFor, RemoteRef reference) + { + // Collect all interfaces, implemented by stubFor and derived from + // Remote (also Remote itself): + HashSet interfaces = new HashSet(); + Class c = stubFor; + Class[] intfs; + + while (c != null) + { + intfs = c.getInterfaces(); + for (int i = 0; i < intfs.length; i++) + { + if (Remote.class.isAssignableFrom(intfs[i])) + interfaces.add(intfs[i]); + } + c = c.getSuperclass(); + } + + intfs = new Class[interfaces.size()]; + Iterator it = interfaces.iterator(); + + for (int i = 0; i < intfs.length; i++) + intfs[i] = (Class) it.next(); + + RemoteObjectInvocationHandler handler = + new RemoteObjectInvocationHandler(reference); + + Object proxy = + Proxy.newProxyInstance(stubFor.getClassLoader(), intfs, handler); + + return (Remote) proxy; + } + } diff --git a/gnu/java/security/Properties.java b/gnu/java/security/Properties.java new file mode 100644 index 000000000..813888c20 --- /dev/null +++ b/gnu/java/security/Properties.java @@ -0,0 +1,374 @@ +/* Properties.java -- run-time configuration properties. + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.PropertyPermission; + +/** + *

A global object containing build-specific properties that affect the + * behaviour of the generated binaries from this library.

+ */ +public final class Properties +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "Properties"; + + private static final boolean DEBUG = false; + + // private static final int debuglevel = 9; + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(final String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String VERSION = "gnu.crypto.version"; + + public static final String PROPERTIES_FILE = "gnu.crypto.properties.file"; + + public static final String REPRODUCIBLE_PRNG = "gnu.crypto.with.reproducible.prng"; + + public static final String CHECK_WEAK_KEYS = "gnu.crypto.with.check.for.weak.keys"; + + public static final String DO_RSA_BLINDING = "gnu.crypto.with.rsa.blinding"; + + private static final String TRUE = Boolean.TRUE.toString(); + + private static final String FALSE = Boolean.FALSE.toString(); + + private static final HashMap props = new HashMap(); + + private static Properties singleton = null; + + private boolean reproducible = false; + + private boolean checkForWeakKeys = true; + + private boolean doRSABlinding = true; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private Properties() + { + super(); + init(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns the string representation of the library global configuration + * property with the designated key.

+ * + * @param key the case-insensitive, non-null and non-empty name of a + * configuration property. + * @return the string representation of the designated property, or + * null if such property is not yet set, or key is + * empty. + */ + public static final synchronized String getProperty(String key) + { + if (key == null) + return null; + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(key, "read")); + key = key.trim().toLowerCase(); + if ("".equals(key)) + return null; + return (String) props.get(key); + } + + /** + *

Sets the value of a designated library global configuration property, + * to a string representation of what should be a legal value.

+ * + * @param key the case-insensitive, non-null and non-empty name of a + * configuration property. + * @param value the non-null, non-empty string representation of a legal + * value of the configuration property named by key. + */ + public static final synchronized void setProperty(String key, String value) + { + if (key == null || value == null) + return; + key = key.trim().toLowerCase(); + if ("".equals(key)) + return; + if (key.equals(VERSION)) + return; + value = value.trim(); + if ("".equals(value)) + return; + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(key, "write")); + if (key.equals(REPRODUCIBLE_PRNG) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) + setReproducible(Boolean.valueOf(value).booleanValue()); + else if (key.equals(CHECK_WEAK_KEYS) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) + setCheckForWeakKeys(Boolean.valueOf(value).booleanValue()); + else if (key.equals(DO_RSA_BLINDING) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) + setDoRSABlinding(Boolean.valueOf(value).booleanValue()); + else + props.put(key, value); + } + + /** + *

A convenience method that returns, as a boolean, the library global + * configuration property indicating if the default Pseudo Random Number + * Generator produces, or not, the same bit stream when instantiated.

+ * + * @return true if the default PRNG produces the same bit stream + * with every VM instance. Returns false if the default PRNG is + * seeded with the time of day of its first invocation. + */ + public static final synchronized boolean isReproducible() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(REPRODUCIBLE_PRNG, "read")); + return instance().reproducible; + } + + /** + *

A convenience method that returns, as a boolean, the library global + * configuration property indicating if the implementations of symmetric + * key block ciphers check, or not, for possible/potential weak and semi-weak + * keys that may be produced in the course of generating round encryption + * and/or decryption keys.

+ * + * @return true if the cipher implementations check for weak and + * semi-weak keys. Returns false if the cipher implementations + * do not check for weak or semi-weak keys. + */ + public static final synchronized boolean checkForWeakKeys() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(CHECK_WEAK_KEYS, "read")); + return instance().checkForWeakKeys; + } + + /** + *

A convenience method that returns, as a boolean, the library global + * configuration property indicating if RSA decryption (RSADP primitive), + * does, or not, blinding against timing attacks.

+ * + * @return true if the RSA decryption primitive includes a + * blinding operation. Returns false if the RSA decryption + * primitive does not include the additional blinding operation. + */ + public static final synchronized boolean doRSABlinding() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(DO_RSA_BLINDING, "read")); + return instance().doRSABlinding; + } + + /** + *

A convenience method to set the global property for reproducibility of + * the default PRNG bit stream output.

+ * + * @param value if true then the default PRNG bit stream output + * is the same with every invocation of the VM. + */ + public static final synchronized void setReproducible(final boolean value) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(REPRODUCIBLE_PRNG, "write")); + instance().reproducible = value; + props.put(REPRODUCIBLE_PRNG, String.valueOf(value)); + } + + /** + *

A convenience method to set the global property for checking for weak + * and semi-weak cipher keys.

+ * + * @param value if true then the cipher implementations will + * invoke additional checks for weak and semi-weak key values that may get + * generated. + */ + public static final synchronized void setCheckForWeakKeys(final boolean value) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(CHECK_WEAK_KEYS, "write")); + instance().checkForWeakKeys = value; + props.put(CHECK_WEAK_KEYS, String.valueOf(value)); + } + + /** + *

A convenience method to set the global property fo adding a blinding + * operation when executing the RSA decryption primitive.

+ * + * @param value if true then the code for performing the RSA + * decryption primitive will include a blinding operation. + */ + public static final synchronized void setDoRSABlinding(final boolean value) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(DO_RSA_BLINDING, "write")); + instance().doRSABlinding = value; + props.put(DO_RSA_BLINDING, String.valueOf(value)); + } + + private static final synchronized Properties instance() + { + if (singleton == null) + singleton = new Properties(); + return singleton; + } + + // Instance methods + // ------------------------------------------------------------------------- + private void init() + { + // default values + props.put(REPRODUCIBLE_PRNG, (reproducible ? "true" : "false")); + props.put(CHECK_WEAK_KEYS, (checkForWeakKeys ? "true" : "false")); + props.put(DO_RSA_BLINDING, (doRSABlinding ? "true" : "false")); + + // 1. allow site-wide override by reading a properties file + String propFile = null; + try + { + propFile = (String) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return System.getProperty(PROPERTIES_FILE); + } + }); + } + catch (SecurityException se) + { + if (DEBUG) + debug("Reading property " + PROPERTIES_FILE + + " not allowed. Ignored."); + } + if (propFile != null) + { + try + { + final java.util.Properties temp = new java.util.Properties(); + final FileInputStream fin = new FileInputStream(propFile); + temp.load(fin); + temp.list(System.out); + props.putAll(temp); + } + catch (IOException ioe) + { + if (DEBUG) + debug("IO error reading " + propFile + ": " + ioe.getMessage()); + } + catch (SecurityException se) + { + if (DEBUG) + debug("Security error reading " + propFile + ": " + + se.getMessage()); + } + } + + // 2. allow vm-specific override by allowing -D options in launcher + handleBooleanProperty(REPRODUCIBLE_PRNG); + handleBooleanProperty(CHECK_WEAK_KEYS); + handleBooleanProperty(DO_RSA_BLINDING); + + // re-sync the 'known' properties + reproducible = new Boolean((String) props.get(REPRODUCIBLE_PRNG)).booleanValue(); + checkForWeakKeys = new Boolean((String) props.get(CHECK_WEAK_KEYS)).booleanValue(); + doRSABlinding = new Boolean((String) props.get(DO_RSA_BLINDING)).booleanValue(); + + // This does not change. + props.put(VERSION, Registry.VERSION_STRING); + } + + private void handleBooleanProperty(final String name) + { + String s = null; + try + { + s = System.getProperty(name); + } + catch (SecurityException x) + { + if (DEBUG) + debug("SecurityManager forbids reading system properties. Ignored"); + } + if (s != null) + { + s = s.trim().toLowerCase(); + // we have to test for explicit "true" or "false". anything else may + // hide valid value set previously + if (s.equals(TRUE) || s.equals(FALSE)) + { + if (DEBUG) + debug("Setting " + name + " to '" + s + "'"); + props.put(name, s); + } + else + { + if (DEBUG) + debug("Invalid value for -D" + name + ": " + s + ". Ignored"); + } + } + } +} diff --git a/gnu/java/security/Registry.java b/gnu/java/security/Registry.java new file mode 100644 index 000000000..efb54e714 --- /dev/null +++ b/gnu/java/security/Registry.java @@ -0,0 +1,455 @@ +/* Registry.java -- + Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security; + +/** + * A placeholder for names and literals used throughout this + * library. + */ +public interface Registry +{ + + // Constants + // ------------------------------------------------------------------------- + + /** The name of our Providers. */ + String GNU_SECURITY = "GNU"; + String GNU_CRYPTO = "GNU-CRYPTO"; + String GNU_SASL = "GNU-SASL"; + + /** Our version number. */ + String VERSION_STRING = "2.1.0"; + + // Names of properties to use in Maps when initialising primitives ......... + + // Symmetric block cipher algorithms and synonyms........................... + + String ANUBIS_CIPHER = "anubis"; + + String BLOWFISH_CIPHER = "blowfish"; + + String DES_CIPHER = "des"; + + String KHAZAD_CIPHER = "khazad"; + + String RIJNDAEL_CIPHER = "rijndael"; + + String SERPENT_CIPHER = "serpent"; + + String SQUARE_CIPHER = "square"; + + String TRIPLEDES_CIPHER = "tripledes"; + + String TWOFISH_CIPHER = "twofish"; + + String CAST5_CIPHER = "cast5"; + + String NULL_CIPHER = "null"; + + /** AES is synonymous to Rijndael for 128-bit block size only. */ + String AES_CIPHER = "aes"; + + /** TripleDES is also known as DESede. */ + String DESEDE_CIPHER = "desede"; + + /** CAST5 is also known as CAST-128. */ + String CAST128_CIPHER = "cast128"; + + String CAST_128_CIPHER = "cast-128"; + + // Message digest algorithms and synonyms................................... + + String WHIRLPOOL_HASH = "whirlpool"; + + String RIPEMD128_HASH = "ripemd128"; + + String RIPEMD160_HASH = "ripemd160"; + + String SHA160_HASH = "sha-160"; + + String SHA256_HASH = "sha-256"; + + String SHA384_HASH = "sha-384"; + + String SHA512_HASH = "sha-512"; + + String TIGER_HASH = "tiger"; + + String HAVAL_HASH = "haval"; + + String MD5_HASH = "md5"; + + String MD4_HASH = "md4"; + + String MD2_HASH = "md2"; + + /** RIPEMD-128 is synonymous to RIPEMD128. */ + String RIPEMD_128_HASH = "ripemd-128"; + + /** RIPEMD-160 is synonymous to RIPEMD160. */ + String RIPEMD_160_HASH = "ripemd-160"; + + /** SHA-1 is synonymous to SHA-160. */ + String SHA_1_HASH = "sha-1"; + + /** SHA1 is synonymous to SHA-160. */ + String SHA1_HASH = "sha1"; + + /** SHA is synonymous to SHA-160. */ + String SHA_HASH = "sha"; + + // Symmetric block cipher modes of operations............................... + + /** Electronic CodeBook mode. */ + String ECB_MODE = "ecb"; + + /** Counter (NIST) mode. */ + String CTR_MODE = "ctr"; + + /** Integer Counter Mode (David McGrew). */ + String ICM_MODE = "icm"; + + /** Output Feedback Mode (NIST). */ + String OFB_MODE = "ofb"; + + /** Cipher block chaining mode (NIST). */ + String CBC_MODE = "cbc"; + + /** Cipher feedback mode (NIST). */ + String CFB_MODE = "cfb"; + + /** Authenticated-Encrypted mode. */ + String EAX_MODE = "eax"; + + // Padding scheme names and synonyms........................................ + + /** PKCS#7 padding scheme. */ + String PKCS7_PAD = "pkcs7"; + + /** Trailing Bit Complement padding scheme. */ + String TBC_PAD = "tbc"; + + /** EME-PKCS1-v1_5 padding as described in section 7.2 in RFC-3447. */ + String EME_PKCS1_V1_5_PAD = "eme-pkcs1-v1.5"; + + /** SSLv3 padding scheme. */ + String SSL3_PAD = "ssl3"; + + /** TLSv1 padding scheme. */ + String TLS1_PAD = "tls1"; + + // Pseudo-random number generators.......................................... + + /** (Apparently) RC4 keystream PRNG. */ + String ARCFOUR_PRNG = "arcfour"; + + /** We use "rc4" as an alias for "arcfour". */ + String RC4_PRNG = "rc4"; + + /** PRNG based on David McGrew's Integer Counter Mode. */ + String ICM_PRNG = "icm"; + + /** PRNG based on a designated hash function. */ + String MD_PRNG = "md"; + + /** PRNG based on UMAC's Key Derivation Function. */ + String UMAC_PRNG = "umac-kdf"; + + /** + * PRNG based on PBKDF2 from PKCS #5 v.2. This is suffixed with the name + * of a MAC to be used as a PRF. + */ + String PBKDF2_PRNG_PREFIX = "pbkdf2-"; + + /** The continuously-seeded pseudo-random number generator. */ + String CSPRNG_PRNG = "csprng"; + + /** The Fortuna PRNG. */ + String FORTUNA_PRNG = "fortuna"; + + /** The Fortuna generator PRNG. */ + String FORTUNA_GENERATOR_PRNG = "fortuna-generator"; + + // Asymmetric keypair generators............................................ + + String DSS_KPG = "dss"; + + String RSA_KPG = "rsa"; + + String DH_KPG = "dh"; + + String SRP_KPG = "srp"; + + /** DSA is synonymous to DSS. */ + String DSA_KPG = "dsa"; + + // Signature-with-appendix schemes.......................................... + + String DSS_SIG = "dss"; + + String RSA_SIG_PREFIX = "rsa-"; + + String RSA_PSS_ENCODING = "pss"; + + String RSA_PSS_SIG = RSA_SIG_PREFIX + RSA_PSS_ENCODING; + + String RSA_PKCS1_V1_5_ENCODING = "pkcs1-v1.5"; + + String RSA_PKCS1_V1_5_SIG = RSA_SIG_PREFIX + RSA_PKCS1_V1_5_ENCODING; + + /** DSA is synonymous to DSS. */ + String DSA_SIG = "dsa"; + + // Key agreement protocols ................................................. + + String DH_KA = "dh"; + + String ELGAMAL_KA = "elgamal"; + + String SRP6_KA = "srp6"; + + String SRP_SASL_KA = "srp-sasl"; + + String SRP_TLS_KA = "srp-tls"; + + // Keyed-Hash Message Authentication Code .................................. + + /** Name prefix of every HMAC implementation. */ + String HMAC_NAME_PREFIX = "hmac-"; + + // Other MAC algorithms .................................................... + + /** The One-key CBC MAC. */ + String OMAC_PREFIX = "omac-"; + + /** Message Authentication Code using Universal Hashing (Ted Krovetz). */ + String UHASH32 = "uhash32"; + + String UMAC32 = "umac32"; + + /** The Truncated Multi-Modular Hash Function -v1 (David McGrew). */ + String TMMH16 = "tmmh16"; + + // String TMMH32 = "tmmh32"; + + // Format IDs used to identify how we externalise asymmetric keys .......... + // fully-qualified names of the supported codecs + String RAW_ENCODING = "gnu.crypto.raw.format"; + String X509_ENCODING = "gnu.crypto.x509.format"; + String PKCS8_ENCODING = "gnu.crypto.pkcs8.format"; + String ASN1_ENCODING = "gnu.crypto.asn1.format"; + + // short names of the same. used by JCE adapters + String RAW_ENCODING_SHORT_NAME = "RAW"; + String X509_ENCODING_SORT_NAME = "X.509"; + String PKCS8_ENCODING_SHORT_NAME = "PKCS#8"; + String ASN1_ENCODING_SHORT_NAME = "ASN.1"; + + // unique identifiers of the same + int RAW_ENCODING_ID = 1; + int X509_ENCODING_ID = 2; + int PKCS8_ENCODING_ID = 3; + int ASN1_ENCODING_ID = 4; + + // OID strings used in encoding/decoding keys + String DSA_OID_STRING = "1.2.840.10040.4.1"; + String RSA_OID_STRING = "1.2.840.113549.1.1.1"; + String DH_OID_STRING = "1.2.840.10046.2.1"; + + // Magic bytes we generate/expect in externalised asymmetric keys .......... + // the four bytes represent G (0x47) for GNU, 1 (0x01) for Raw format, + // D (0x44) for DSS, R (0x52) for RSA, H (0x48) for Diffie-Hellman, or S + // (0x53) for SRP-6, and finally P (0x50) for Public, p (0x70) for private, + // or S (0x53) for signature. + byte[] MAGIC_RAW_DSS_PUBLIC_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x44, + 0x50 }; + + byte[] MAGIC_RAW_DSS_PRIVATE_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x44, + 0x70 }; + + byte[] MAGIC_RAW_DSS_SIGNATURE = new byte[] { 0x47, RAW_ENCODING_ID, 0x44, + 0x53 }; + + byte[] MAGIC_RAW_RSA_PUBLIC_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x52, + 0x50 }; + + byte[] MAGIC_RAW_RSA_PRIVATE_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x52, + 0x70 }; + + byte[] MAGIC_RAW_RSA_PSS_SIGNATURE = new byte[] { 0x47, RAW_ENCODING_ID, + 0x52, 0x53 }; + + byte[] MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE = new byte[] { 0x47, RAW_ENCODING_ID, + 0x52, 0x54 }; + + byte[] MAGIC_RAW_DH_PUBLIC_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x48, + 0x50 }; + + byte[] MAGIC_RAW_DH_PRIVATE_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x48, + 0x70 }; + + byte[] MAGIC_RAW_SRP_PUBLIC_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x53, + 0x50 }; + + byte[] MAGIC_RAW_SRP_PRIVATE_KEY = new byte[] { 0x47, RAW_ENCODING_ID, 0x53, + 0x70 }; + + // SASL Property names ..................................................... + + String SASL_PREFIX = "gnu.crypto.sasl"; + + /** Name of username property. */ + String SASL_USERNAME = SASL_PREFIX + ".username"; + + /** Name of password property. */ + String SASL_PASSWORD = SASL_PREFIX + ".password"; + + /** Name of authentication information provider packages. */ + String SASL_AUTH_INFO_PROVIDER_PKGS = SASL_PREFIX + + ".auth.info.provider.pkgs"; + + /** SASL authorization ID. */ + String SASL_AUTHORISATION_ID = SASL_PREFIX + ".authorisation.ID"; + + /** SASL protocol. */ + String SASL_PROTOCOL = SASL_PREFIX + ".protocol"; + + /** SASL Server name. */ + String SASL_SERVER_NAME = SASL_PREFIX + ".server.name"; + + /** SASL Callback handler. */ + String SASL_CALLBACK_HANDLER = SASL_PREFIX + ".callback.handler"; + + /** SASL channel binding. */ + String SASL_CHANNEL_BINDING = SASL_PREFIX + ".channel.binding"; + + // SASL data element size limits ........................................... + + /** The size limit, in bytes, of a SASL OS (Octet Sequence) element. */ + int SASL_ONE_BYTE_MAX_LIMIT = 255; + + /** + * The size limit, in bytes, of both a SASL MPI (Multi-Precision Integer) + * element and a SASL Text element. + */ + int SASL_TWO_BYTE_MAX_LIMIT = 65535; + + /** The size limit, in bytes, of a SASL EOS (Extended Octet Sequence) element. */ + int SASL_FOUR_BYTE_MAX_LIMIT = 2147483383; + + /** The size limit, in bytes, of a SASL Buffer. */ + int SASL_BUFFER_MAX_LIMIT = 2147483643; + + // Canonical names of SASL mechanisms ...................................... + + String SASL_ANONYMOUS_MECHANISM = "ANONYMOUS"; + + String SASL_CRAM_MD5_MECHANISM = "CRAM-MD5"; + + String SASL_PLAIN_MECHANISM = "PLAIN"; + + String SASL_SRP_MECHANISM = "SRP"; + + // Canonical names of Integrity Protection algorithms ...................... + + String SASL_HMAC_MD5_IALG = "HMACwithMD5"; + + String SASL_HMAC_SHA_IALG = "HMACwithSHA"; + + // Quality Of Protection string representations ............................ + + /** authentication only. */ + String QOP_AUTH = "auth"; + + /** authentication plus integrity protection. */ + String QOP_AUTH_INT = "auth-int"; + + /** authentication plus integrity and confidentiality protection. */ + String QOP_AUTH_CONF = "auth-conf"; + + // SASL mechanism strength string representation ........................... + + String STRENGTH_HIGH = "high"; + + String STRENGTH_MEDIUM = "medium"; + + String STRENGTH_LOW = "low"; + + // SASL Server Authentication requirement .................................. + + /** Server must authenticate to the client. */ + String SERVER_AUTH_TRUE = "true"; + + /** Server does not need to, or cannot, authenticate to the client. */ + String SERVER_AUTH_FALSE = "false"; + + // SASL mechanism reuse capability ......................................... + + String REUSE_TRUE = "true"; + + String REUSE_FALSE = "false"; + + // Keyrings ............................................................... + + byte[] GKR_MAGIC = new byte[] { 0x47, 0x4b, 0x52, 0x01 }; + + // Ring usage fields. + int GKR_PRIVATE_KEYS = 1 << 0; + + int GKR_PUBLIC_CREDENTIALS = 1 << 1; + + int GKR_CERTIFICATES = 1 << 2; + + // HMac types. + int GKR_HMAC_MD5_128 = 0; + + int GKR_HMAC_SHA_160 = 1; + + int GKR_HMAC_MD5_96 = 2; + + int GKR_HMAC_SHA_96 = 3; + + // Cipher types. + int GKR_CIPHER_AES_128_OFB = 0; + + int GKR_CIPHER_AES_128_CBC = 1; + + // Methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/der/DERValue.java b/gnu/java/security/der/DERValue.java index 9a597d724..d98ce78ec 100644 --- a/gnu/java/security/der/DERValue.java +++ b/gnu/java/security/der/DERValue.java @@ -38,6 +38,8 @@ exception statement from your version. */ package gnu.java.security.der; +import gnu.java.security.x509.Util; + import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -108,7 +110,9 @@ public class DERValue implements DER } catch (IOException ioe) { - encoded = new byte[0]; + IllegalArgumentException iae = new IllegalArgumentException (); + iae.initCause (ioe); + throw iae; } } return length; @@ -138,7 +142,9 @@ public class DERValue implements DER } catch (IOException ioe) { - encoded = new byte[0]; + IllegalArgumentException iae = new IllegalArgumentException (); + iae.initCause (ioe); + throw iae; } } return (byte[]) encoded.clone(); @@ -156,7 +162,9 @@ public class DERValue implements DER } catch (IOException ioe) { - encoded = new byte[0]; + IllegalArgumentException iae = new IllegalArgumentException (); + iae.initCause (ioe); + throw iae; } } return encoded.length; @@ -164,7 +172,18 @@ public class DERValue implements DER public String toString() { - return "DERValue [ tag=" + tag + ", class=" + tagClass + ", constructed=" - + constructed + ", value=" + value + " ]"; + String start = "DERValue ( ["; + if (tagClass == DER.UNIVERSAL) + start = start + "UNIVERSAL "; + else if (tagClass == DER.PRIVATE) + start = start + "PRIVATE "; + else if (tagClass == DER.APPLICATION) + start = start + "APPLICATION "; + start = start + tag + "] constructed=" + constructed + ", value="; + if (constructed) + start = start + "\n" + Util.hexDump(getEncoded(), "\t"); + else + start = start + value; + return start + " )"; } } diff --git a/gnu/java/security/der/DERWriter.java b/gnu/java/security/der/DERWriter.java index 78524fc94..0c2633605 100644 --- a/gnu/java/security/der/DERWriter.java +++ b/gnu/java/security/der/DERWriter.java @@ -84,6 +84,12 @@ public class DERWriter implements DER public static int write(OutputStream out, DERValue object) throws IOException { + if (DER.CONSTRUCTED_VALUE.equals (object.getValue ())) + { + out.write (object.getEncoded ()); + return object.getLength (); + } + out.write(object.getExternalTag()); Object value = object.getValue(); if (value == null) @@ -216,10 +222,10 @@ public class DERWriter implements DER throws IOException { byte[] buf = bs.getShiftedByteArray(); - out.write(buf.length + 1); + writeLength(out, buf.length + 1); out.write(bs.getIgnoredBits()); out.write(buf); - return buf.length; + return buf.length + 1; } private static int writeString(OutputStream out, int tag, String str) diff --git a/gnu/java/security/hash/BaseHash.java b/gnu/java/security/hash/BaseHash.java new file mode 100644 index 000000000..720b83539 --- /dev/null +++ b/gnu/java/security/hash/BaseHash.java @@ -0,0 +1,206 @@ +/* BaseHash.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +/** + *

A base abstract class to facilitate hash implementations.

+ */ +public abstract class BaseHash implements IMessageDigest +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The canonical name prefix of the hash. */ + protected String name; + + /** The hash (output) size in bytes. */ + protected int hashSize; + + /** The hash (inner) block size in bytes. */ + protected int blockSize; + + /** Number of bytes processed so far. */ + protected long count; + + /** Temporary input buffer. */ + protected byte[] buffer; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial constructor for use by concrete subclasses.

+ * + * @param name the canonical name prefix of this instance. + * @param hashSize the block size of the output in bytes. + * @param blockSize the block size of the internal transform. + */ + protected BaseHash(String name, int hashSize, int blockSize) + { + super(); + + this.name = name; + this.hashSize = hashSize; + this.blockSize = blockSize; + this.buffer = new byte[blockSize]; + + resetContext(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IMessageDigest interface implementation --------------------------------- + + public String name() + { + return name; + } + + public int hashSize() + { + return hashSize; + } + + public int blockSize() + { + return blockSize; + } + + public void update(byte b) + { + // compute number of bytes still unhashed; ie. present in buffer + int i = (int) (count % blockSize); + count++; + buffer[i] = b; + if (i == (blockSize - 1)) + { + transform(buffer, 0); + } + } + + public void update(byte[] b) + { + update(b, 0, b.length); + } + + public void update(byte[] b, int offset, int len) + { + int n = (int) (count % blockSize); + count += len; + int partLen = blockSize - n; + int i = 0; + + if (len >= partLen) + { + System.arraycopy(b, offset, buffer, n, partLen); + transform(buffer, 0); + for (i = partLen; i + blockSize - 1 < len; i += blockSize) + { + transform(b, offset + i); + } + n = 0; + } + + if (i < len) + { + System.arraycopy(b, offset + i, buffer, n, len - i); + } + } + + public byte[] digest() + { + byte[] tail = padBuffer(); // pad remaining bytes in buffer + update(tail, 0, tail.length); // last transform of a message + byte[] result = getResult(); // make a result out of context + + reset(); // reset this instance for future re-use + + return result; + } + + public void reset() + { // reset this instance for future re-use + count = 0L; + for (int i = 0; i < blockSize;) + { + buffer[i++] = 0; + } + + resetContext(); + } + + // methods to be implemented by concrete subclasses ------------------------ + + public abstract Object clone(); + + public abstract boolean selfTest(); + + /** + *

Returns the byte array to use as padding before completing a hash + * operation.

+ * + * @return the bytes to pad the remaining bytes in the buffer before + * completing a hash operation. + */ + protected abstract byte[] padBuffer(); + + /** + *

Constructs the result from the contents of the current context.

+ * + * @return the output of the completed hash operation. + */ + protected abstract byte[] getResult(); + + /** Resets the instance for future re-use. */ + protected abstract void resetContext(); + + /** + *

The block digest transformation per se.

+ * + * @param in the blockSize long block, as an array of bytes to digest. + * @param offset the index where the data to digest is located within the + * input buffer. + */ + protected abstract void transform(byte[] in, int offset); +} diff --git a/gnu/java/security/hash/HashFactory.java b/gnu/java/security/hash/HashFactory.java new file mode 100644 index 000000000..e52092123 --- /dev/null +++ b/gnu/java/security/hash/HashFactory.java @@ -0,0 +1,178 @@ +/* HashFactory.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + *

A Factory to instantiate message digest algorithm instances.

+ */ +public class HashFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private HashFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Return an instance of a hash algorithm given its name.

+ * + * @param name the name of the hash algorithm. + * @return an instance of the hash algorithm, or null if none found. + * @exception InternalError if the implementation does not pass its self- + * test. + */ + public static IMessageDigest getInstance(String name) + { + if (name == null) + { + return null; + } + + name = name.trim(); + IMessageDigest result = null; + if (name.equalsIgnoreCase(Registry.WHIRLPOOL_HASH)) + { + result = new Whirlpool(); + } + else if (name.equalsIgnoreCase(Registry.RIPEMD128_HASH) + || name.equalsIgnoreCase(Registry.RIPEMD_128_HASH)) + { + result = new RipeMD128(); + } + else if (name.equalsIgnoreCase(Registry.RIPEMD160_HASH) + || name.equalsIgnoreCase(Registry.RIPEMD_160_HASH)) + { + result = new RipeMD160(); + } + else if (name.equalsIgnoreCase(Registry.SHA160_HASH) + || name.equalsIgnoreCase(Registry.SHA_1_HASH) + || name.equalsIgnoreCase(Registry.SHA1_HASH) + || name.equalsIgnoreCase(Registry.SHA_HASH)) + { + result = new Sha160(); + } + else if (name.equalsIgnoreCase(Registry.SHA256_HASH)) + { + result = new Sha256(); + } + else if (name.equalsIgnoreCase(Registry.SHA384_HASH)) + { + result = new Sha384(); + } + else if (name.equalsIgnoreCase(Registry.SHA512_HASH)) + { + result = new Sha512(); + } + else if (name.equalsIgnoreCase(Registry.TIGER_HASH)) + { + result = new Tiger(); + } + else if (name.equalsIgnoreCase(Registry.HAVAL_HASH)) + { + result = new Haval(); + } + else if (name.equalsIgnoreCase(Registry.MD5_HASH)) + { + result = new MD5(); + } + else if (name.equalsIgnoreCase(Registry.MD4_HASH)) + { + result = new MD4(); + } + else if (name.equalsIgnoreCase(Registry.MD2_HASH)) + { + result = new MD2(); + } + else if (name.equalsIgnoreCase(Registry.HAVAL_HASH)) + { + result = new Haval(); + } + + if (result != null && !result.selfTest()) + { + throw new InternalError(result.name()); + } + + return result; + } + + /** + *

Returns a {@link Set} of names of hash algorithms supported by this + * Factory.

+ * + * @return a {@link Set} of hash names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(Registry.WHIRLPOOL_HASH); + hs.add(Registry.RIPEMD128_HASH); + hs.add(Registry.RIPEMD160_HASH); + hs.add(Registry.SHA160_HASH); + hs.add(Registry.SHA256_HASH); + hs.add(Registry.SHA384_HASH); + hs.add(Registry.SHA512_HASH); + hs.add(Registry.TIGER_HASH); + hs.add(Registry.HAVAL_HASH); + hs.add(Registry.MD5_HASH); + hs.add(Registry.MD4_HASH); + hs.add(Registry.MD2_HASH); + + return Collections.unmodifiableSet(hs); + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/hash/Haval.java b/gnu/java/security/hash/Haval.java new file mode 100644 index 000000000..f9f3282f2 --- /dev/null +++ b/gnu/java/security/hash/Haval.java @@ -0,0 +1,759 @@ +/* Haval.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

The HAVAL message-digest algorithm is a variable output length, + * with variable number of rounds. By default, this implementation allows + * HAVAL to be used as a drop-in replacement for MD5.

+ * + *

References:

+ * + *
    + *
  1. HAVAL - A One-Way Hashing Algorithm with Variable Length of Output
    + * Advances in Cryptology - AUSCRYPT'92, Lecture Notes in Computer Science,
    + * Springer-Verlag, 1993;
    + * Y. Zheng, J. Pieprzyk and J. Seberry.
  2. + *
+ */ +public class Haval extends BaseHash +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int HAVAL_VERSION = 1; + + public static final int HAVAL_128_BIT = 16; + + public static final int HAVAL_160_BIT = 20; + + public static final int HAVAL_192_BIT = 24; + + public static final int HAVAL_224_BIT = 28; + + public static final int HAVAL_256_BIT = 32; + + public static final int HAVAL_3_ROUND = 3; + + public static final int HAVAL_4_ROUND = 4; + + public static final int HAVAL_5_ROUND = 5; + + private static final int BLOCK_SIZE = 128; // inner block size in bytes + + private static final String DIGEST0 = "C68F39913F901F3DDF44C707357A7D70"; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** + * Number of HAVAL rounds. Allowed values are integers in the range 3 + * .. 5. The default is 3. + */ + private int rounds = HAVAL_3_ROUND; + + /** 128-bit interim result. */ + private int h0, h1, h2, h3, h4, h5, h6, h7; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Calls the constructor with two argument using {@link #HAVAL_128_BIT} as + * the value for the output size (i.e. 128 bits, and + * {@link #HAVAL_3_ROUND} for the value of number of rounds.

+ */ + public Haval() + { + this(HAVAL_128_BIT, HAVAL_3_ROUND); + } + + /** + *

Calls the constructor with two arguments using the designated output + * size, and {@link #HAVAL_3_ROUND} for the value of number of rounds.

+ * + * @param size the output size in bytes of this instance. + * @throws IllegalArgumentException if the designated output size is invalid. + * @see #HAVAL_128_BIT + * @see #HAVAL_160_BIT + * @see #HAVAL_192_BIT + * @see #HAVAL_224_BIT + * @see #HAVAL_256_BIT + */ + public Haval(int size) + { + this(size, HAVAL_3_ROUND); + } + + /** + *

Constructs a Haval instance with the designated output + * size (in bytes). Valid output size values are 16, + * 20, 24, 28 and 32. + * Valid values for rounds are in the range 3..5 + * inclusive.

+ * + * @param size the output size in bytes of this instance. + * @param rounds the number of rounds to apply when transforming data. + * @throws IllegalArgumentException if the designated output size is invalid, + * or if the number of rounds is invalid. + * @see #HAVAL_128_BIT + * @see #HAVAL_160_BIT + * @see #HAVAL_192_BIT + * @see #HAVAL_224_BIT + * @see #HAVAL_256_BIT + * @see #HAVAL_3_ROUND + * @see #HAVAL_4_ROUND + * @see #HAVAL_5_ROUND + */ + public Haval(int size, int rounds) + { + super(Registry.HAVAL_HASH, size, BLOCK_SIZE); + + if (size != HAVAL_128_BIT && size != HAVAL_160_BIT && size != HAVAL_192_BIT + && size != HAVAL_224_BIT && size != HAVAL_256_BIT) + { + throw new IllegalArgumentException("Invalid HAVAL output size"); + } + + if (rounds != HAVAL_3_ROUND && rounds != HAVAL_4_ROUND + && rounds != HAVAL_5_ROUND) + { + throw new IllegalArgumentException("Invalid HAVAL number of rounds"); + } + + this.rounds = rounds; + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param md the instance to clone. + */ + private Haval(Haval md) + { + this(md.hashSize, md.rounds); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.h5 = md.h5; + this.h6 = md.h6; + this.h7 = md.h7; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new Haval(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected synchronized void transform(byte[] in, int i) + { + int X0 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X1 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X2 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X3 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X4 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X5 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X6 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X7 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X8 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X9 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X10 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X11 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X12 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X13 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X14 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X15 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X16 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X17 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X18 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X19 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X20 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X21 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X22 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X23 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X24 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X25 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X26 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X27 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X28 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X29 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X30 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + int X31 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 24; + + int t0 = h0, t1 = h1, t2 = h2, t3 = h3, t4 = h4, t5 = h5, t6 = h6, t7 = h7; + + // Pass 1 + t7 = FF1(t7, t6, t5, t4, t3, t2, t1, t0, X0); + t6 = FF1(t6, t5, t4, t3, t2, t1, t0, t7, X1); + t5 = FF1(t5, t4, t3, t2, t1, t0, t7, t6, X2); + t4 = FF1(t4, t3, t2, t1, t0, t7, t6, t5, X3); + t3 = FF1(t3, t2, t1, t0, t7, t6, t5, t4, X4); + t2 = FF1(t2, t1, t0, t7, t6, t5, t4, t3, X5); + t1 = FF1(t1, t0, t7, t6, t5, t4, t3, t2, X6); + t0 = FF1(t0, t7, t6, t5, t4, t3, t2, t1, X7); + + t7 = FF1(t7, t6, t5, t4, t3, t2, t1, t0, X8); + t6 = FF1(t6, t5, t4, t3, t2, t1, t0, t7, X9); + t5 = FF1(t5, t4, t3, t2, t1, t0, t7, t6, X10); + t4 = FF1(t4, t3, t2, t1, t0, t7, t6, t5, X11); + t3 = FF1(t3, t2, t1, t0, t7, t6, t5, t4, X12); + t2 = FF1(t2, t1, t0, t7, t6, t5, t4, t3, X13); + t1 = FF1(t1, t0, t7, t6, t5, t4, t3, t2, X14); + t0 = FF1(t0, t7, t6, t5, t4, t3, t2, t1, X15); + + t7 = FF1(t7, t6, t5, t4, t3, t2, t1, t0, X16); + t6 = FF1(t6, t5, t4, t3, t2, t1, t0, t7, X17); + t5 = FF1(t5, t4, t3, t2, t1, t0, t7, t6, X18); + t4 = FF1(t4, t3, t2, t1, t0, t7, t6, t5, X19); + t3 = FF1(t3, t2, t1, t0, t7, t6, t5, t4, X20); + t2 = FF1(t2, t1, t0, t7, t6, t5, t4, t3, X21); + t1 = FF1(t1, t0, t7, t6, t5, t4, t3, t2, X22); + t0 = FF1(t0, t7, t6, t5, t4, t3, t2, t1, X23); + + t7 = FF1(t7, t6, t5, t4, t3, t2, t1, t0, X24); + t6 = FF1(t6, t5, t4, t3, t2, t1, t0, t7, X25); + t5 = FF1(t5, t4, t3, t2, t1, t0, t7, t6, X26); + t4 = FF1(t4, t3, t2, t1, t0, t7, t6, t5, X27); + t3 = FF1(t3, t2, t1, t0, t7, t6, t5, t4, X28); + t2 = FF1(t2, t1, t0, t7, t6, t5, t4, t3, X29); + t1 = FF1(t1, t0, t7, t6, t5, t4, t3, t2, X30); + t0 = FF1(t0, t7, t6, t5, t4, t3, t2, t1, X31); + + // Pass 2 + t7 = FF2(t7, t6, t5, t4, t3, t2, t1, t0, X5, 0x452821E6); + t6 = FF2(t6, t5, t4, t3, t2, t1, t0, t7, X14, 0x38D01377); + t5 = FF2(t5, t4, t3, t2, t1, t0, t7, t6, X26, 0xBE5466CF); + t4 = FF2(t4, t3, t2, t1, t0, t7, t6, t5, X18, 0x34E90C6C); + t3 = FF2(t3, t2, t1, t0, t7, t6, t5, t4, X11, 0xC0AC29B7); + t2 = FF2(t2, t1, t0, t7, t6, t5, t4, t3, X28, 0xC97C50DD); + t1 = FF2(t1, t0, t7, t6, t5, t4, t3, t2, X7, 0x3F84D5B5); + t0 = FF2(t0, t7, t6, t5, t4, t3, t2, t1, X16, 0xB5470917); + + t7 = FF2(t7, t6, t5, t4, t3, t2, t1, t0, X0, 0x9216D5D9); + t6 = FF2(t6, t5, t4, t3, t2, t1, t0, t7, X23, 0x8979FB1B); + t5 = FF2(t5, t4, t3, t2, t1, t0, t7, t6, X20, 0xD1310BA6); + t4 = FF2(t4, t3, t2, t1, t0, t7, t6, t5, X22, 0x98DFB5AC); + t3 = FF2(t3, t2, t1, t0, t7, t6, t5, t4, X1, 0x2FFD72DB); + t2 = FF2(t2, t1, t0, t7, t6, t5, t4, t3, X10, 0xD01ADFB7); + t1 = FF2(t1, t0, t7, t6, t5, t4, t3, t2, X4, 0xB8E1AFED); + t0 = FF2(t0, t7, t6, t5, t4, t3, t2, t1, X8, 0x6A267E96); + + t7 = FF2(t7, t6, t5, t4, t3, t2, t1, t0, X30, 0xBA7C9045); + t6 = FF2(t6, t5, t4, t3, t2, t1, t0, t7, X3, 0xF12C7F99); + t5 = FF2(t5, t4, t3, t2, t1, t0, t7, t6, X21, 0x24A19947); + t4 = FF2(t4, t3, t2, t1, t0, t7, t6, t5, X9, 0xB3916CF7); + t3 = FF2(t3, t2, t1, t0, t7, t6, t5, t4, X17, 0x0801F2E2); + t2 = FF2(t2, t1, t0, t7, t6, t5, t4, t3, X24, 0x858EFC16); + t1 = FF2(t1, t0, t7, t6, t5, t4, t3, t2, X29, 0x636920D8); + t0 = FF2(t0, t7, t6, t5, t4, t3, t2, t1, X6, 0x71574E69); + + t7 = FF2(t7, t6, t5, t4, t3, t2, t1, t0, X19, 0xA458FEA3); + t6 = FF2(t6, t5, t4, t3, t2, t1, t0, t7, X12, 0xF4933D7E); + t5 = FF2(t5, t4, t3, t2, t1, t0, t7, t6, X15, 0x0D95748F); + t4 = FF2(t4, t3, t2, t1, t0, t7, t6, t5, X13, 0x728EB658); + t3 = FF2(t3, t2, t1, t0, t7, t6, t5, t4, X2, 0x718BCD58); + t2 = FF2(t2, t1, t0, t7, t6, t5, t4, t3, X25, 0x82154AEE); + t1 = FF2(t1, t0, t7, t6, t5, t4, t3, t2, X31, 0x7B54A41D); + t0 = FF2(t0, t7, t6, t5, t4, t3, t2, t1, X27, 0xC25A59B5); + + // Pass 3 + t7 = FF3(t7, t6, t5, t4, t3, t2, t1, t0, X19, 0x9C30D539); + t6 = FF3(t6, t5, t4, t3, t2, t1, t0, t7, X9, 0x2AF26013); + t5 = FF3(t5, t4, t3, t2, t1, t0, t7, t6, X4, 0xC5D1B023); + t4 = FF3(t4, t3, t2, t1, t0, t7, t6, t5, X20, 0x286085F0); + t3 = FF3(t3, t2, t1, t0, t7, t6, t5, t4, X28, 0xCA417918); + t2 = FF3(t2, t1, t0, t7, t6, t5, t4, t3, X17, 0xB8DB38EF); + t1 = FF3(t1, t0, t7, t6, t5, t4, t3, t2, X8, 0x8E79DCB0); + t0 = FF3(t0, t7, t6, t5, t4, t3, t2, t1, X22, 0x603A180E); + + t7 = FF3(t7, t6, t5, t4, t3, t2, t1, t0, X29, 0x6C9E0E8B); + t6 = FF3(t6, t5, t4, t3, t2, t1, t0, t7, X14, 0xB01E8A3E); + t5 = FF3(t5, t4, t3, t2, t1, t0, t7, t6, X25, 0xD71577C1); + t4 = FF3(t4, t3, t2, t1, t0, t7, t6, t5, X12, 0xBD314B27); + t3 = FF3(t3, t2, t1, t0, t7, t6, t5, t4, X24, 0x78AF2FDA); + t2 = FF3(t2, t1, t0, t7, t6, t5, t4, t3, X30, 0x55605C60); + t1 = FF3(t1, t0, t7, t6, t5, t4, t3, t2, X16, 0xE65525F3); + t0 = FF3(t0, t7, t6, t5, t4, t3, t2, t1, X26, 0xAA55AB94); + + t7 = FF3(t7, t6, t5, t4, t3, t2, t1, t0, X31, 0x57489862); + t6 = FF3(t6, t5, t4, t3, t2, t1, t0, t7, X15, 0x63E81440); + t5 = FF3(t5, t4, t3, t2, t1, t0, t7, t6, X7, 0x55CA396A); + t4 = FF3(t4, t3, t2, t1, t0, t7, t6, t5, X3, 0x2AAB10B6); + t3 = FF3(t3, t2, t1, t0, t7, t6, t5, t4, X1, 0xB4CC5C34); + t2 = FF3(t2, t1, t0, t7, t6, t5, t4, t3, X0, 0x1141E8CE); + t1 = FF3(t1, t0, t7, t6, t5, t4, t3, t2, X18, 0xA15486AF); + t0 = FF3(t0, t7, t6, t5, t4, t3, t2, t1, X27, 0x7C72E993); + + t7 = FF3(t7, t6, t5, t4, t3, t2, t1, t0, X13, 0xB3EE1411); + t6 = FF3(t6, t5, t4, t3, t2, t1, t0, t7, X6, 0x636FBC2A); + t5 = FF3(t5, t4, t3, t2, t1, t0, t7, t6, X21, 0x2BA9C55D); + t4 = FF3(t4, t3, t2, t1, t0, t7, t6, t5, X10, 0x741831F6); + t3 = FF3(t3, t2, t1, t0, t7, t6, t5, t4, X23, 0xCE5C3E16); + t2 = FF3(t2, t1, t0, t7, t6, t5, t4, t3, X11, 0x9B87931E); + t1 = FF3(t1, t0, t7, t6, t5, t4, t3, t2, X5, 0xAFD6BA33); + t0 = FF3(t0, t7, t6, t5, t4, t3, t2, t1, X2, 0x6C24CF5C); + + if (rounds >= 4) + { + t7 = FF4(t7, t6, t5, t4, t3, t2, t1, t0, X24, 0x7A325381); + t6 = FF4(t6, t5, t4, t3, t2, t1, t0, t7, X4, 0x28958677); + t5 = FF4(t5, t4, t3, t2, t1, t0, t7, t6, X0, 0x3B8F4898); + t4 = FF4(t4, t3, t2, t1, t0, t7, t6, t5, X14, 0x6B4BB9AF); + t3 = FF4(t3, t2, t1, t0, t7, t6, t5, t4, X2, 0xC4BFE81B); + t2 = FF4(t2, t1, t0, t7, t6, t5, t4, t3, X7, 0x66282193); + t1 = FF4(t1, t0, t7, t6, t5, t4, t3, t2, X28, 0x61D809CC); + t0 = FF4(t0, t7, t6, t5, t4, t3, t2, t1, X23, 0xFB21A991); + t7 = FF4(t7, t6, t5, t4, t3, t2, t1, t0, X26, 0x487CAC60); + t6 = FF4(t6, t5, t4, t3, t2, t1, t0, t7, X6, 0x5DEC8032); + t5 = FF4(t5, t4, t3, t2, t1, t0, t7, t6, X30, 0xEF845D5D); + t4 = FF4(t4, t3, t2, t1, t0, t7, t6, t5, X20, 0xE98575B1); + t3 = FF4(t3, t2, t1, t0, t7, t6, t5, t4, X18, 0xDC262302); + t2 = FF4(t2, t1, t0, t7, t6, t5, t4, t3, X25, 0xEB651B88); + t1 = FF4(t1, t0, t7, t6, t5, t4, t3, t2, X19, 0x23893E81); + t0 = FF4(t0, t7, t6, t5, t4, t3, t2, t1, X3, 0xD396ACC5); + + t7 = FF4(t7, t6, t5, t4, t3, t2, t1, t0, X22, 0x0F6D6FF3); + t6 = FF4(t6, t5, t4, t3, t2, t1, t0, t7, X11, 0x83F44239); + t5 = FF4(t5, t4, t3, t2, t1, t0, t7, t6, X31, 0x2E0B4482); + t4 = FF4(t4, t3, t2, t1, t0, t7, t6, t5, X21, 0xA4842004); + t3 = FF4(t3, t2, t1, t0, t7, t6, t5, t4, X8, 0x69C8F04A); + t2 = FF4(t2, t1, t0, t7, t6, t5, t4, t3, X27, 0x9E1F9B5E); + t1 = FF4(t1, t0, t7, t6, t5, t4, t3, t2, X12, 0x21C66842); + t0 = FF4(t0, t7, t6, t5, t4, t3, t2, t1, X9, 0xF6E96C9A); + t7 = FF4(t7, t6, t5, t4, t3, t2, t1, t0, X1, 0x670C9C61); + t6 = FF4(t6, t5, t4, t3, t2, t1, t0, t7, X29, 0xABD388F0); + t5 = FF4(t5, t4, t3, t2, t1, t0, t7, t6, X5, 0x6A51A0D2); + t4 = FF4(t4, t3, t2, t1, t0, t7, t6, t5, X15, 0xD8542F68); + t3 = FF4(t3, t2, t1, t0, t7, t6, t5, t4, X17, 0x960FA728); + t2 = FF4(t2, t1, t0, t7, t6, t5, t4, t3, X10, 0xAB5133A3); + t1 = FF4(t1, t0, t7, t6, t5, t4, t3, t2, X16, 0x6EEF0B6C); + t0 = FF4(t0, t7, t6, t5, t4, t3, t2, t1, X13, 0x137A3BE4); + + if (rounds == 5) + { + t7 = FF5(t7, t6, t5, t4, t3, t2, t1, t0, X27, 0xBA3BF050); + t6 = FF5(t6, t5, t4, t3, t2, t1, t0, t7, X3, 0x7EFB2A98); + t5 = FF5(t5, t4, t3, t2, t1, t0, t7, t6, X21, 0xA1F1651D); + t4 = FF5(t4, t3, t2, t1, t0, t7, t6, t5, X26, 0x39AF0176); + t3 = FF5(t3, t2, t1, t0, t7, t6, t5, t4, X17, 0x66CA593E); + t2 = FF5(t2, t1, t0, t7, t6, t5, t4, t3, X11, 0x82430E88); + t1 = FF5(t1, t0, t7, t6, t5, t4, t3, t2, X20, 0x8CEE8619); + t0 = FF5(t0, t7, t6, t5, t4, t3, t2, t1, X29, 0x456F9FB4); + + t7 = FF5(t7, t6, t5, t4, t3, t2, t1, t0, X19, 0x7D84A5C3); + t6 = FF5(t6, t5, t4, t3, t2, t1, t0, t7, X0, 0x3B8B5EBE); + t5 = FF5(t5, t4, t3, t2, t1, t0, t7, t6, X12, 0xE06F75D8); + t4 = FF5(t4, t3, t2, t1, t0, t7, t6, t5, X7, 0x85C12073); + t3 = FF5(t3, t2, t1, t0, t7, t6, t5, t4, X13, 0x401A449F); + t2 = FF5(t2, t1, t0, t7, t6, t5, t4, t3, X8, 0x56C16AA6); + t1 = FF5(t1, t0, t7, t6, t5, t4, t3, t2, X31, 0x4ED3AA62); + t0 = FF5(t0, t7, t6, t5, t4, t3, t2, t1, X10, 0x363F7706); + + t7 = FF5(t7, t6, t5, t4, t3, t2, t1, t0, X5, 0x1BFEDF72); + t6 = FF5(t6, t5, t4, t3, t2, t1, t0, t7, X9, 0x429B023D); + t5 = FF5(t5, t4, t3, t2, t1, t0, t7, t6, X14, 0x37D0D724); + t4 = FF5(t4, t3, t2, t1, t0, t7, t6, t5, X30, 0xD00A1248); + t3 = FF5(t3, t2, t1, t0, t7, t6, t5, t4, X18, 0xDB0FEAD3); + t2 = FF5(t2, t1, t0, t7, t6, t5, t4, t3, X6, 0x49F1C09B); + t1 = FF5(t1, t0, t7, t6, t5, t4, t3, t2, X28, 0x075372C9); + t0 = FF5(t0, t7, t6, t5, t4, t3, t2, t1, X24, 0x80991B7B); + + t7 = FF5(t7, t6, t5, t4, t3, t2, t1, t0, X2, 0x25D479D8); + t6 = FF5(t6, t5, t4, t3, t2, t1, t0, t7, X23, 0xF6E8DEF7); + t5 = FF5(t5, t4, t3, t2, t1, t0, t7, t6, X16, 0xE3FE501A); + t4 = FF5(t4, t3, t2, t1, t0, t7, t6, t5, X22, 0xB6794C3B); + t3 = FF5(t3, t2, t1, t0, t7, t6, t5, t4, X4, 0x976CE0BD); + t2 = FF5(t2, t1, t0, t7, t6, t5, t4, t3, X1, 0x04C006BA); + t1 = FF5(t1, t0, t7, t6, t5, t4, t3, t2, X25, 0xC1A94FB6); + t0 = FF5(t0, t7, t6, t5, t4, t3, t2, t1, X15, 0x409F60C4); + } + } + + h7 += t7; + h6 += t6; + h5 += t5; + h4 += t4; + h3 += t3; + h2 += t2; + h1 += t1; + h0 += t0; + } + + protected byte[] padBuffer() + { + // pad out to 118 mod 128. other 10 bytes have special use. + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 118) ? (118 - n) : (246 - n); + byte[] result = new byte[padding + 10]; + result[0] = (byte) 0x01; + + // save the version number (LSB 3), the number of rounds (3 bits in the + // middle), the fingerprint length (MSB 2 bits and next byte) and the + // number of bits in the unpadded message. + int bl = hashSize * 8; + result[padding++] = (byte) (((bl & 0x03) << 6) | ((rounds & 0x07) << 3) | (HAVAL_VERSION & 0x07)); + result[padding++] = (byte) (bl >>> 2); + + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + result[padding++] = (byte) bits; + result[padding++] = (byte) (bits >>> 8); + result[padding++] = (byte) (bits >>> 16); + result[padding++] = (byte) (bits >>> 24); + result[padding++] = (byte) (bits >>> 32); + result[padding++] = (byte) (bits >>> 40); + result[padding++] = (byte) (bits >>> 48); + result[padding] = (byte) (bits >>> 56); + + return result; + } + + protected byte[] getResult() + { + tailorDigestBits(); // tailor context for the designated output size + // cast enough top context values into an array of hashSize bytes + byte[] result = new byte[hashSize]; + if (hashSize >= HAVAL_256_BIT) + { + result[31] = (byte) (h7 >>> 24); + result[30] = (byte) (h7 >>> 16); + result[29] = (byte) (h7 >>> 8); + result[28] = (byte) h7; + } + if (hashSize >= HAVAL_224_BIT) + { + result[27] = (byte) (h6 >>> 24); + result[26] = (byte) (h6 >>> 16); + result[25] = (byte) (h6 >>> 8); + result[24] = (byte) h6; + } + if (hashSize >= HAVAL_192_BIT) + { + result[23] = (byte) (h5 >>> 24); + result[22] = (byte) (h5 >>> 16); + result[21] = (byte) (h5 >>> 8); + result[20] = (byte) h5; + } + if (hashSize >= HAVAL_160_BIT) + { + result[19] = (byte) (h4 >>> 24); + result[18] = (byte) (h4 >>> 16); + result[17] = (byte) (h4 >>> 8); + result[16] = (byte) h4; + } + result[15] = (byte) (h3 >>> 24); + result[14] = (byte) (h3 >>> 16); + result[13] = (byte) (h3 >>> 8); + result[12] = (byte) h3; + result[11] = (byte) (h2 >>> 24); + result[10] = (byte) (h2 >>> 16); + result[9] = (byte) (h2 >>> 8); + result[8] = (byte) h2; + result[7] = (byte) (h1 >>> 24); + result[6] = (byte) (h1 >>> 16); + result[5] = (byte) (h1 >>> 8); + result[4] = (byte) h1; + result[3] = (byte) (h0 >>> 24); + result[2] = (byte) (h0 >>> 16); + result[1] = (byte) (h0 >>> 8); + result[0] = (byte) h0; + + return result; + } + + protected void resetContext() + { + h0 = 0x243F6A88; + h1 = 0x85A308D3; + h2 = 0x13198A2E; + h3 = 0x03707344; + h4 = 0xA4093822; + h5 = 0x299F31D0; + h6 = 0x082EFA98; + h7 = 0xEC4E6C89; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean(DIGEST0.equals(Util.toString(new Haval().digest()))); + } + return valid.booleanValue(); + } + + // helper methods ---------------------------------------------------------- + + /** Tailors the last output. */ + private void tailorDigestBits() + { + int t; + switch (hashSize) + { + case HAVAL_128_BIT: + t = (h7 & 0x000000FF) | (h6 & 0xFF000000) | (h5 & 0x00FF0000) + | (h4 & 0x0000FF00); + h0 += t >>> 8 | t << 24; + t = (h7 & 0x0000FF00) | (h6 & 0x000000FF) | (h5 & 0xFF000000) + | (h4 & 0x00FF0000); + h1 += t >>> 16 | t << 16; + t = (h7 & 0x00FF0000) | (h6 & 0x0000FF00) | (h5 & 0x000000FF) + | (h4 & 0xFF000000); + h2 += t >>> 24 | t << 8; + t = (h7 & 0xFF000000) | (h6 & 0x00FF0000) | (h5 & 0x0000FF00) + | (h4 & 0x000000FF); + h3 += t; + break; + case HAVAL_160_BIT: + t = (h7 & 0x3F) | (h6 & (0x7F << 25)) | (h5 & (0x3F << 19)); + h0 += t >>> 19 | t << 13; + t = (h7 & (0x3F << 6)) | (h6 & 0x3F) | (h5 & (0x7F << 25)); + h1 += t >>> 25 | t << 7; + t = (h7 & (0x7F << 12)) | (h6 & (0x3F << 6)) | (h5 & 0x3F); + h2 += t; + t = (h7 & (0x3F << 19)) | (h6 & (0x7F << 12)) | (h5 & (0x3F << 6)); + h3 += (t >>> 6); + t = (h7 & (0x7F << 25)) | (h6 & (0x3F << 19)) | (h5 & (0x7F << 12)); + h4 += (t >>> 12); + break; + case HAVAL_192_BIT: + t = (h7 & 0x1F) | (h6 & (0x3F << 26)); + h0 += t >>> 26 | t << 6; + t = (h7 & (0x1F << 5)) | (h6 & 0x1F); + h1 += t; + t = (h7 & (0x3F << 10)) | (h6 & (0x1F << 5)); + h2 += (t >>> 5); + t = (h7 & (0x1F << 16)) | (h6 & (0x3F << 10)); + h3 += (t >>> 10); + t = (h7 & (0x1F << 21)) | (h6 & (0x1F << 16)); + h4 += (t >>> 16); + t = (h7 & (0x3F << 26)) | (h6 & (0x1F << 21)); + h5 += (t >>> 21); + break; + case HAVAL_224_BIT: + h0 += ((h7 >>> 27) & 0x1F); + h1 += ((h7 >>> 22) & 0x1F); + h2 += ((h7 >>> 18) & 0x0F); + h3 += ((h7 >>> 13) & 0x1F); + h4 += ((h7 >>> 9) & 0x0F); + h5 += ((h7 >>> 4) & 0x1F); + h6 += (h7 & 0x0F); + } + } + + /** + * Permutations phi_{i,j}, i=3,4,5, j=1,...,i. + * + * rounds = 3: 6 5 4 3 2 1 0 + * | | | | | | | (replaced by) + * phi_{3,1}: 1 0 3 5 6 2 4 + * phi_{3,2}: 4 2 1 0 5 3 6 + * phi_{3,3}: 6 1 2 3 4 5 0 + * + * rounds = 4: 6 5 4 3 2 1 0 + * | | | | | | | (replaced by) + * phi_{4,1}: 2 6 1 4 5 3 0 + * phi_{4,2}: 3 5 2 0 1 6 4 + * phi_{4,3}: 1 4 3 6 0 2 5 + * phi_{4,4}: 6 4 0 5 2 1 3 + * + * rounds = 5: 6 5 4 3 2 1 0 + * | | | | | | | (replaced by) + * phi_{5,1}: 3 4 1 0 5 2 6 + * phi_{5,2}: 6 2 1 0 3 4 5 + * phi_{5,3}: 2 6 0 4 3 1 5 + * phi_{5,4}: 1 5 3 2 0 4 6 + * phi_{5,5}: 2 5 0 6 4 3 1 + */ + private int FF1(int x7, int x6, int x5, int x4, int x3, int x2, int x1, + int x0, int w) + { + int t; + switch (rounds) + { + case 3: + t = f1(x1, x0, x3, x5, x6, x2, x4); + break; + case 4: + t = f1(x2, x6, x1, x4, x5, x3, x0); + break; + default: + t = f1(x3, x4, x1, x0, x5, x2, x6); + } + return (t >>> 7 | t << 25) + (x7 >>> 11 | x7 << 21) + w; + } + + private int FF2(int x7, int x6, int x5, int x4, int x3, int x2, int x1, + int x0, int w, int c) + { + int t; + switch (rounds) + { + case 3: + t = f2(x4, x2, x1, x0, x5, x3, x6); + break; + case 4: + t = f2(x3, x5, x2, x0, x1, x6, x4); + break; + default: + t = f2(x6, x2, x1, x0, x3, x4, x5); + } + return (t >>> 7 | t << 25) + (x7 >>> 11 | x7 << 21) + w + c; + } + + private int FF3(int x7, int x6, int x5, int x4, int x3, int x2, int x1, + int x0, int w, int c) + { + int t; + switch (rounds) + { + case 3: + t = f3(x6, x1, x2, x3, x4, x5, x0); + break; + case 4: + t = f3(x1, x4, x3, x6, x0, x2, x5); + break; + default: + t = f3(x2, x6, x0, x4, x3, x1, x5); + } + return (t >>> 7 | t << 25) + (x7 >>> 11 | x7 << 21) + w + c; + } + + private int FF4(int x7, int x6, int x5, int x4, int x3, int x2, int x1, + int x0, int w, int c) + { + int t; + switch (rounds) + { + case 4: + t = f4(x6, x4, x0, x5, x2, x1, x3); + break; + default: + t = f4(x1, x5, x3, x2, x0, x4, x6); + } + return (t >>> 7 | t << 25) + (x7 >>> 11 | x7 << 21) + w + c; + } + + private int FF5(int x7, int x6, int x5, int x4, int x3, int x2, int x1, + int x0, int w, int c) + { + int t = f5(x2, x5, x0, x6, x4, x3, x1); + return (t >>> 7 | t << 25) + (x7 >>> 11 | x7 << 21) + w + c; + } + + private int f1(int x6, int x5, int x4, int x3, int x2, int x1, int x0) + { + return x1 & (x0 ^ x4) ^ x2 & x5 ^ x3 & x6 ^ x0; + } + + private int f2(int x6, int x5, int x4, int x3, int x2, int x1, int x0) + { + return x2 & (x1 & ~x3 ^ x4 & x5 ^ x6 ^ x0) ^ x4 & (x1 ^ x5) ^ x3 & x5 ^ x0; + } + + private int f3(int x6, int x5, int x4, int x3, int x2, int x1, int x0) + { + return x3 & (x1 & x2 ^ x6 ^ x0) ^ x1 & x4 ^ x2 & x5 ^ x0; + } + + private int f4(int x6, int x5, int x4, int x3, int x2, int x1, int x0) + { + return x4 & (x5 & ~x2 ^ x3 & ~x6 ^ x1 ^ x6 ^ x0) ^ x3 & (x1 & x2 ^ x5 ^ x6) + ^ x2 & x6 ^ x0; + } + + private int f5(int x6, int x5, int x4, int x3, int x2, int x1, int x0) + { + return x0 & (x1 & x2 & x3 ^ ~x5) ^ x1 & x4 ^ x2 & x5 ^ x3 & x6; + } +} diff --git a/gnu/java/security/hash/IMessageDigest.java b/gnu/java/security/hash/IMessageDigest.java new file mode 100644 index 000000000..b3d7f69ca --- /dev/null +++ b/gnu/java/security/hash/IMessageDigest.java @@ -0,0 +1,135 @@ +/* IMessageDigest.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +/** + *

The basic visible methods of any hash algorithm.

+ * + *

A hash (or message digest) algorithm produces its output by iterating a + * basic compression function on blocks of data.

+ */ +public interface IMessageDigest extends Cloneable +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + *

Returns the canonical name of this algorithm.

+ * + * @return the canonical name of this instance. + */ + String name(); + + /** + *

Returns the output length in bytes of this message digest algorithm.

+ * + * @return the output length in bytes of this message digest algorithm. + */ + int hashSize(); + + /** + *

Returns the algorithm's (inner) block size in bytes.

+ * + * @return the algorithm's inner block size in bytes. + */ + int blockSize(); + + /** + *

Continues a message digest operation using the input byte.

+ * + * @param b the input byte to digest. + */ + void update(byte b); + + /** + *

Continues a message digest operation, by filling the buffer, processing + * data in the algorithm's HASH_SIZE-bit block(s), updating the context and + * count, and buffering the remaining bytes in buffer for the next + * operation.

+ * + * @param in the input block. + */ + void update(byte[] in); + + /** + *

Continues a message digest operation, by filling the buffer, processing + * data in the algorithm's HASH_SIZE-bit block(s), updating the context and + * count, and buffering the remaining bytes in buffer for the next + * operation.

+ * + * @param in the input block. + * @param offset start of meaningful bytes in input block. + * @param length number of bytes, in input block, to consider. + */ + void update(byte[] in, int offset, int length); + + /** + *

Completes the message digest by performing final operations such as + * padding and resetting the instance.

+ * + * @return the array of bytes representing the hash value. + */ + byte[] digest(); + + /** + *

Resets the current context of this instance clearing any eventually cached + * intermediary values.

+ */ + void reset(); + + /** + *

A basic test. Ensures that the digest of a pre-determined message is equal + * to a known pre-computed value.

+ * + * @return true if the implementation passes a basic self-test. + * Returns false otherwise. + */ + boolean selfTest(); + + /** + *

Returns a clone copy of this instance.

+ * + * @return a clone copy of this instance. + */ + Object clone(); +} diff --git a/gnu/java/security/hash/MD2.java b/gnu/java/security/hash/MD2.java new file mode 100644 index 000000000..41e876983 --- /dev/null +++ b/gnu/java/security/hash/MD2.java @@ -0,0 +1,301 @@ +/* MD2.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

An implementation of the MD2 message digest algorithm.

+ * + *

MD2 is not widely used. Unless it is needed for compatibility with + * existing systems, it is not recommended for use in new applications.

+ * + *

References:

+ * + *
    + *
  1. The MD2 + * Message-Digest Algorithm.
    + * B. Kaliski.
  2. + *
  3. The RFC ERRATA PAGE + * under section RFC 1319.
  4. + *
+ */ +public class MD2 extends BaseHash +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** An MD2 message digest is always 128-bits long, or 16 bytes. */ + private static final int DIGEST_LENGTH = 16; + + /** The MD2 algorithm operates on 128-bit blocks, or 16 bytes. */ + private static final int BLOCK_LENGTH = 16; + + /** 256 byte "random" permutation of the digits of pi. */ + private static final byte[] PI = { 41, 46, 67, -55, -94, -40, 124, 1, 61, 54, + 84, -95, -20, -16, 6, 19, 98, -89, 5, -13, + -64, -57, 115, -116, -104, -109, 43, -39, + -68, 76, -126, -54, 30, -101, 87, 60, -3, + -44, -32, 22, 103, 66, 111, 24, -118, 23, + -27, 18, -66, 78, -60, -42, -38, -98, -34, + 73, -96, -5, -11, -114, -69, 47, -18, 122, + -87, 104, 121, -111, 21, -78, 7, 63, -108, + -62, 16, -119, 11, 34, 95, 33, -128, 127, + 93, -102, 90, -112, 50, 39, 53, 62, -52, + -25, -65, -9, -105, 3, -1, 25, 48, -77, 72, + -91, -75, -47, -41, 94, -110, 42, -84, 86, + -86, -58, 79, -72, 56, -46, -106, -92, 125, + -74, 118, -4, 107, -30, -100, 116, 4, -15, + 69, -99, 112, 89, 100, 113, -121, 32, -122, + 91, -49, 101, -26, 45, -88, 2, 27, 96, 37, + -83, -82, -80, -71, -10, 28, 70, 97, 105, + 52, 64, 126, 15, 85, 71, -93, 35, -35, 81, + -81, 58, -61, 92, -7, -50, -70, -59, -22, + 38, 44, 83, 13, 110, -123, 40, -124, 9, + -45, -33, -51, -12, 65, -127, 77, 82, 106, + -36, 55, -56, 108, -63, -85, -6, 36, -31, + 123, 8, 12, -67, -79, 74, 120, -120, -107, + -117, -29, 99, -24, 109, -23, -53, -43, -2, + 59, 0, 29, 57, -14, -17, -73, 14, 102, 88, + -48, -28, -90, 119, 114, -8, -21, 117, 75, + 10, 49, 68, 80, -76, -113, -19, 31, 26, + -37, -103, -115, 51, -97, 17, -125, 20 }; + + /** The output of this message digest when no data has been input. */ + private static final String DIGEST0 = "8350E5A3E24C153DF2275C9F80692773"; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** The checksum computed so far. */ + private byte[] checksum; + + /** + * Work array needed by encrypt method. First BLOCK_LENGTH bytes + * are also used to store the running digest. + */ + private byte[] work; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Creates a new MD2 digest ready for use. */ + public MD2() + { + super(Registry.MD2_HASH, DIGEST_LENGTH, BLOCK_LENGTH); + } + + /** + *

Private constructor used for cloning.

+ * + * @param md2 the instance to clone. + */ + private MD2(MD2 md2) + { + this(); + + // superclass field + this.count = md2.count; + this.buffer = (byte[]) md2.buffer.clone(); + + // private field + this.checksum = (byte[]) md2.checksum.clone(); + this.work = (byte[]) md2.work.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new MD2(this); + } + + // Implementation of abstract methods in BaseHash -------------------------- + + protected byte[] getResult() + { + byte[] result = new byte[DIGEST_LENGTH]; + + // Encrypt checksum as last block. + encryptBlock(checksum, 0); + + for (int i = 0; i < BLOCK_LENGTH; i++) + { + result[i] = work[i]; + } + + return result; + } + + protected void resetContext() + { + checksum = new byte[BLOCK_LENGTH]; + work = new byte[BLOCK_LENGTH * 3]; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean(DIGEST0.equals(Util.toString(new MD2().digest()))); + } + return valid.booleanValue(); + } + + /** + *

Generates an array of padding bytes. The padding is defined as + * i bytes of value i, where i is the + * number of bytes to fill the last block of the message to + * BLOCK_LENGTH bytes (or BLOCK_LENGTH bytes when + * the last block was completely full).

+ * + * @return the bytes to pad the remaining bytes in the buffer before + * completing a hash operation. + */ + protected byte[] padBuffer() + { + int length = BLOCK_LENGTH - (int) (count % BLOCK_LENGTH); + if (length == 0) + { + length = BLOCK_LENGTH; + } + byte[] pad = new byte[length]; + for (int i = 0; i < length; i++) + { + pad[i] = (byte) length; + } + return pad; + } + + /** + *

Adds BLOCK_LENGTH bytes to the running digest.

+ * + * @param in the byte array to take the BLOCK_LENGTH bytes from. + * @param off the offset to start from in the given byte array. + */ + protected void transform(byte[] in, int off) + { + // encryptBlock(in, off); + // updateCheckSum(in, off); + updateCheckSumAndEncryptBlock(in, off); + } + + // Private instance methods ------------------------------------------------ + + /** + * Updates the checksum with the BLOCK_LENGTH bytes from the + * given array starting at off. + */ + /* + private void updateCheckSum(byte[] in, int off) { + byte l = checksum[BLOCK_LENGTH-1]; + for (int i = 0; i < BLOCK_LENGTH; i++) { + byte b = in[off+i]; + // l = (byte)((checksum[i] & 0xFF) ^ (PI[((b & 0xFF) ^ (l & 0xFF))] & 0xFF)); + l = (byte)(checksum[i] ^ PI[(b ^ l) & 0xFF]); + checksum[i] = l; + } + } + */ + /** + * Adds a new block (BLOCK_LENGTH bytes) to the running digest + * from the given byte array starting from the given offset. + */ + private void encryptBlock(byte[] in, int off) + { + for (int i = 0; i < BLOCK_LENGTH; i++) + { + byte b = in[off + i]; + work[BLOCK_LENGTH + i] = b; + work[BLOCK_LENGTH * 2 + i] = (byte) (work[i] ^ b); + } + + byte t = 0; + for (int i = 0; i < 18; i++) + { + for (int j = 0; j < 3 * BLOCK_LENGTH; j++) + { + // t = (byte)((work[j] & 0xFF) ^ (PI[t & 0xFF] & 0xFF)); + t = (byte) (work[j] ^ PI[t & 0xFF]); + work[j] = t; + } + // t = (byte)((t + i) & 0xFF); + t = (byte) (t + i); + } + } + + /** + * Optimized method that combines a checksum update and encrypt of a block. + */ + private void updateCheckSumAndEncryptBlock(byte[] in, int off) + { + byte l = checksum[BLOCK_LENGTH - 1]; + for (int i = 0; i < BLOCK_LENGTH; i++) + { + byte b = in[off + i]; + work[BLOCK_LENGTH + i] = b; + // work[BLOCK_LENGTH*2+i] = (byte)((work[i] & 0xFF) ^ (b & 0xFF)); + work[BLOCK_LENGTH * 2 + i] = (byte) (work[i] ^ b); + // l = (byte)((checksum[i] & 0xFF) ^ (PI[((b & 0xFF) ^ (l & 0xFF))] & 0xFF)); + l = (byte) (checksum[i] ^ PI[(b ^ l) & 0xFF]); + checksum[i] = l; + } + + byte t = 0; + for (int i = 0; i < 18; i++) + { + for (int j = 0; j < 3 * BLOCK_LENGTH; j++) + { + // t = (byte)((work[j] & 0xFF) ^ (PI[t & 0xFF] & 0xFF)); + t = (byte) (work[j] ^ PI[t & 0xFF]); + work[j] = t; + } + // t = (byte)((t + i) & 0xFF); + t = (byte) (t + i); + } + } +} diff --git a/gnu/java/security/hash/MD4.java b/gnu/java/security/hash/MD4.java new file mode 100644 index 000000000..54dda358b --- /dev/null +++ b/gnu/java/security/hash/MD4.java @@ -0,0 +1,328 @@ +/* MD4.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

An implementation of Ron Rivest's MD4 message digest algorithm.

+ * + *

MD4 was the precursor to the stronger {@link gnu.crypto.hash.MD5} + * algorithm, and while not considered cryptograpically secure itself, MD4 is + * in use in various applications. It is slightly faster than MD5.

+ * + *

References:

+ * + *
    + *
  1. The MD4 + * Message-Digest Algorithm.
    + * R. Rivest.
  2. + *
+ * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class MD4 extends BaseHash +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** An MD4 message digest is always 128-bits long, or 16 bytes. */ + private static final int DIGEST_LENGTH = 16; + + /** The MD4 algorithm operates on 512-bit blocks, or 64 bytes. */ + private static final int BLOCK_LENGTH = 64; + + private static final int A = 0x67452301; + + private static final int B = 0xefcdab89; + + private static final int C = 0x98badcfe; + + private static final int D = 0x10325476; + + /** The output of this message digest when no data has been input. */ + private static final String DIGEST0 = "31D6CFE0D16AE931B73C59D7E0C089C0"; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + private int a, b, c, d; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Public constructor. Initializes the chaining variables, sets the byte + * count to 0, and creates a new block of 512 bits. + *

+ */ + public MD4() + { + super(Registry.MD4_HASH, DIGEST_LENGTH, BLOCK_LENGTH); + } + + /** + *

Trivial private constructor for cloning purposes.

+ * + * @param that the instance to clone. + */ + private MD4(MD4 that) + { + this(); + + this.a = that.a; + this.b = that.b; + this.c = that.c; + this.d = that.d; + this.count = that.count; + this.buffer = (byte[]) that.buffer.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new MD4(this); + } + + // Implementation of abstract methods in BashHash -------------------------- + + protected byte[] getResult() + { + byte[] digest = { (byte) a, (byte) (a >>> 8), (byte) (a >>> 16), + (byte) (a >>> 24), (byte) b, (byte) (b >>> 8), + (byte) (b >>> 16), (byte) (b >>> 24), (byte) c, + (byte) (c >>> 8), (byte) (c >>> 16), (byte) (c >>> 24), + (byte) d, (byte) (d >>> 8), (byte) (d >>> 16), + (byte) (d >>> 24) }; + return digest; + } + + protected void resetContext() + { + a = A; + b = B; + c = C; + d = D; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean(DIGEST0.equals(Util.toString(new MD4().digest()))); + } + return valid.booleanValue(); + } + + protected byte[] padBuffer() + { + int n = (int) (count % BLOCK_LENGTH); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] pad = new byte[padding + 8]; + + pad[0] = (byte) 0x80; + long bits = count << 3; + pad[padding++] = (byte) bits; + pad[padding++] = (byte) (bits >>> 8); + pad[padding++] = (byte) (bits >>> 16); + pad[padding++] = (byte) (bits >>> 24); + pad[padding++] = (byte) (bits >>> 32); + pad[padding++] = (byte) (bits >>> 40); + pad[padding++] = (byte) (bits >>> 48); + pad[padding] = (byte) (bits >>> 56); + + return pad; + } + + protected void transform(byte[] in, int i) + { + int X0 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X1 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X2 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X3 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X4 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X5 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X6 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X7 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X8 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X9 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X10 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X11 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X12 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X13 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X14 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X15 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i] << 24; + + int aa, bb, cc, dd; + + aa = a; + bb = b; + cc = c; + dd = d; + + aa += ((bb & cc) | ((~bb) & dd)) + X0; + aa = aa << 3 | aa >>> -3; + dd += ((aa & bb) | ((~aa) & cc)) + X1; + dd = dd << 7 | dd >>> -7; + cc += ((dd & aa) | ((~dd) & bb)) + X2; + cc = cc << 11 | cc >>> -11; + bb += ((cc & dd) | ((~cc) & aa)) + X3; + bb = bb << 19 | bb >>> -19; + aa += ((bb & cc) | ((~bb) & dd)) + X4; + aa = aa << 3 | aa >>> -3; + dd += ((aa & bb) | ((~aa) & cc)) + X5; + dd = dd << 7 | dd >>> -7; + cc += ((dd & aa) | ((~dd) & bb)) + X6; + cc = cc << 11 | cc >>> -11; + bb += ((cc & dd) | ((~cc) & aa)) + X7; + bb = bb << 19 | bb >>> -19; + aa += ((bb & cc) | ((~bb) & dd)) + X8; + aa = aa << 3 | aa >>> -3; + dd += ((aa & bb) | ((~aa) & cc)) + X9; + dd = dd << 7 | dd >>> -7; + cc += ((dd & aa) | ((~dd) & bb)) + X10; + cc = cc << 11 | cc >>> -11; + bb += ((cc & dd) | ((~cc) & aa)) + X11; + bb = bb << 19 | bb >>> -19; + aa += ((bb & cc) | ((~bb) & dd)) + X12; + aa = aa << 3 | aa >>> -3; + dd += ((aa & bb) | ((~aa) & cc)) + X13; + dd = dd << 7 | dd >>> -7; + cc += ((dd & aa) | ((~dd) & bb)) + X14; + cc = cc << 11 | cc >>> -11; + bb += ((cc & dd) | ((~cc) & aa)) + X15; + bb = bb << 19 | bb >>> -19; + + aa += ((bb & (cc | dd)) | (cc & dd)) + X0 + 0x5a827999; + aa = aa << 3 | aa >>> -3; + dd += ((aa & (bb | cc)) | (bb & cc)) + X4 + 0x5a827999; + dd = dd << 5 | dd >>> -5; + cc += ((dd & (aa | bb)) | (aa & bb)) + X8 + 0x5a827999; + cc = cc << 9 | cc >>> -9; + bb += ((cc & (dd | aa)) | (dd & aa)) + X12 + 0x5a827999; + bb = bb << 13 | bb >>> -13; + aa += ((bb & (cc | dd)) | (cc & dd)) + X1 + 0x5a827999; + aa = aa << 3 | aa >>> -3; + dd += ((aa & (bb | cc)) | (bb & cc)) + X5 + 0x5a827999; + dd = dd << 5 | dd >>> -5; + cc += ((dd & (aa | bb)) | (aa & bb)) + X9 + 0x5a827999; + cc = cc << 9 | cc >>> -9; + bb += ((cc & (dd | aa)) | (dd & aa)) + X13 + 0x5a827999; + bb = bb << 13 | bb >>> -13; + aa += ((bb & (cc | dd)) | (cc & dd)) + X2 + 0x5a827999; + aa = aa << 3 | aa >>> -3; + dd += ((aa & (bb | cc)) | (bb & cc)) + X6 + 0x5a827999; + dd = dd << 5 | dd >>> -5; + cc += ((dd & (aa | bb)) | (aa & bb)) + X10 + 0x5a827999; + cc = cc << 9 | cc >>> -9; + bb += ((cc & (dd | aa)) | (dd & aa)) + X14 + 0x5a827999; + bb = bb << 13 | bb >>> -13; + aa += ((bb & (cc | dd)) | (cc & dd)) + X3 + 0x5a827999; + aa = aa << 3 | aa >>> -3; + dd += ((aa & (bb | cc)) | (bb & cc)) + X7 + 0x5a827999; + dd = dd << 5 | dd >>> -5; + cc += ((dd & (aa | bb)) | (aa & bb)) + X11 + 0x5a827999; + cc = cc << 9 | cc >>> -9; + bb += ((cc & (dd | aa)) | (dd & aa)) + X15 + 0x5a827999; + bb = bb << 13 | bb >>> -13; + + aa += (bb ^ cc ^ dd) + X0 + 0x6ed9eba1; + aa = aa << 3 | aa >>> -3; + dd += (aa ^ bb ^ cc) + X8 + 0x6ed9eba1; + dd = dd << 9 | dd >>> -9; + cc += (dd ^ aa ^ bb) + X4 + 0x6ed9eba1; + cc = cc << 11 | cc >>> -11; + bb += (cc ^ dd ^ aa) + X12 + 0x6ed9eba1; + bb = bb << 15 | bb >>> -15; + aa += (bb ^ cc ^ dd) + X2 + 0x6ed9eba1; + aa = aa << 3 | aa >>> -3; + dd += (aa ^ bb ^ cc) + X10 + 0x6ed9eba1; + dd = dd << 9 | dd >>> -9; + cc += (dd ^ aa ^ bb) + X6 + 0x6ed9eba1; + cc = cc << 11 | cc >>> -11; + bb += (cc ^ dd ^ aa) + X14 + 0x6ed9eba1; + bb = bb << 15 | bb >>> -15; + aa += (bb ^ cc ^ dd) + X1 + 0x6ed9eba1; + aa = aa << 3 | aa >>> -3; + dd += (aa ^ bb ^ cc) + X9 + 0x6ed9eba1; + dd = dd << 9 | dd >>> -9; + cc += (dd ^ aa ^ bb) + X5 + 0x6ed9eba1; + cc = cc << 11 | cc >>> -11; + bb += (cc ^ dd ^ aa) + X13 + 0x6ed9eba1; + bb = bb << 15 | bb >>> -15; + aa += (bb ^ cc ^ dd) + X3 + 0x6ed9eba1; + aa = aa << 3 | aa >>> -3; + dd += (aa ^ bb ^ cc) + X11 + 0x6ed9eba1; + dd = dd << 9 | dd >>> -9; + cc += (dd ^ aa ^ bb) + X7 + 0x6ed9eba1; + cc = cc << 11 | cc >>> -11; + bb += (cc ^ dd ^ aa) + X15 + 0x6ed9eba1; + bb = bb << 15 | bb >>> -15; + + a += aa; + b += bb; + c += cc; + d += dd; + } +} diff --git a/gnu/java/security/hash/MD5.java b/gnu/java/security/hash/MD5.java new file mode 100644 index 000000000..463292984 --- /dev/null +++ b/gnu/java/security/hash/MD5.java @@ -0,0 +1,365 @@ +/* MD5.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

The MD5 message-digest algorithm takes as input a message of arbitrary + * length and produces as output a 128-bit "fingerprint" or "message digest" of + * the input. It is conjectured that it is computationally infeasible to + * produce two messages having the same message digest, or to produce any + * message having a given prespecified target message digest.

+ * + *

References:

+ * + *
    + *
  1. The MD5 Message- + * Digest Algorithm.
    + * R. Rivest.
  2. + *
+ */ +public class MD5 extends BaseHash +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + private static final String DIGEST0 = "D41D8CD98F00B204E9800998ECF8427E"; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 128-bit interim result. */ + private int h0, h1, h2, h3; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public MD5() + { + super(Registry.MD5_HASH, 16, BLOCK_SIZE); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param md the instance to clone. + */ + private MD5(MD5 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new MD5(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected synchronized void transform(byte[] in, int i) + { + int X0 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X1 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X2 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X3 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X4 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X5 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X6 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X7 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X8 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X9 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X10 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X11 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X12 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X13 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X14 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X15 = (in[i++] & 0xFF) | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF) << 16 + | in[i] << 24; + + int A = h0; + int B = h1; + int C = h2; + int D = h3; + + // hex constants are from md5.c in FSF Gnu Privacy Guard 0.9.2 + // round 1 + A += ((B & C) | (~B & D)) + X0 + 0xD76AA478; + A = B + (A << 7 | A >>> -7); + D += ((A & B) | (~A & C)) + X1 + 0xE8C7B756; + D = A + (D << 12 | D >>> -12); + C += ((D & A) | (~D & B)) + X2 + 0x242070DB; + C = D + (C << 17 | C >>> -17); + B += ((C & D) | (~C & A)) + X3 + 0xC1BDCEEE; + B = C + (B << 22 | B >>> -22); + + A += ((B & C) | (~B & D)) + X4 + 0xF57C0FAF; + A = B + (A << 7 | A >>> -7); + D += ((A & B) | (~A & C)) + X5 + 0x4787C62A; + D = A + (D << 12 | D >>> -12); + C += ((D & A) | (~D & B)) + X6 + 0xA8304613; + C = D + (C << 17 | C >>> -17); + B += ((C & D) | (~C & A)) + X7 + 0xFD469501; + B = C + (B << 22 | B >>> -22); + + A += ((B & C) | (~B & D)) + X8 + 0x698098D8; + A = B + (A << 7 | A >>> -7); + D += ((A & B) | (~A & C)) + X9 + 0x8B44F7AF; + D = A + (D << 12 | D >>> -12); + C += ((D & A) | (~D & B)) + X10 + 0xFFFF5BB1; + C = D + (C << 17 | C >>> -17); + B += ((C & D) | (~C & A)) + X11 + 0x895CD7BE; + B = C + (B << 22 | B >>> -22); + + A += ((B & C) | (~B & D)) + X12 + 0x6B901122; + A = B + (A << 7 | A >>> -7); + D += ((A & B) | (~A & C)) + X13 + 0xFD987193; + D = A + (D << 12 | D >>> -12); + C += ((D & A) | (~D & B)) + X14 + 0xA679438E; + C = D + (C << 17 | C >>> -17); + B += ((C & D) | (~C & A)) + X15 + 0x49B40821; + B = C + (B << 22 | B >>> -22); + + // round 2 + A += ((B & D) | (C & ~D)) + X1 + 0xF61E2562; + A = B + (A << 5 | A >>> -5); + D += ((A & C) | (B & ~C)) + X6 + 0xC040B340; + D = A + (D << 9 | D >>> -9); + C += ((D & B) | (A & ~B)) + X11 + 0x265E5A51; + C = D + (C << 14 | C >>> -14); + B += ((C & A) | (D & ~A)) + X0 + 0xE9B6C7AA; + B = C + (B << 20 | B >>> -20); + + A += ((B & D) | (C & ~D)) + X5 + 0xD62F105D; + A = B + (A << 5 | A >>> -5); + D += ((A & C) | (B & ~C)) + X10 + 0x02441453; + D = A + (D << 9 | D >>> -9); + C += ((D & B) | (A & ~B)) + X15 + 0xD8A1E681; + C = D + (C << 14 | C >>> -14); + B += ((C & A) | (D & ~A)) + X4 + 0xE7D3FBC8; + B = C + (B << 20 | B >>> -20); + + A += ((B & D) | (C & ~D)) + X9 + 0x21E1CDE6; + A = B + (A << 5 | A >>> -5); + D += ((A & C) | (B & ~C)) + X14 + 0xC33707D6; + D = A + (D << 9 | D >>> -9); + C += ((D & B) | (A & ~B)) + X3 + 0xF4D50D87; + C = D + (C << 14 | C >>> -14); + B += ((C & A) | (D & ~A)) + X8 + 0x455A14ED; + B = C + (B << 20 | B >>> -20); + + A += ((B & D) | (C & ~D)) + X13 + 0xA9E3E905; + A = B + (A << 5 | A >>> -5); + D += ((A & C) | (B & ~C)) + X2 + 0xFCEFA3F8; + D = A + (D << 9 | D >>> -9); + C += ((D & B) | (A & ~B)) + X7 + 0x676F02D9; + C = D + (C << 14 | C >>> -14); + B += ((C & A) | (D & ~A)) + X12 + 0x8D2A4C8A; + B = C + (B << 20 | B >>> -20); + + // round 3 + A += (B ^ C ^ D) + X5 + 0xFFFA3942; + A = B + (A << 4 | A >>> -4); + D += (A ^ B ^ C) + X8 + 0x8771F681; + D = A + (D << 11 | D >>> -11); + C += (D ^ A ^ B) + X11 + 0x6D9D6122; + C = D + (C << 16 | C >>> -16); + B += (C ^ D ^ A) + X14 + 0xFDE5380C; + B = C + (B << 23 | B >>> -23); + + A += (B ^ C ^ D) + X1 + 0xA4BEEA44; + A = B + (A << 4 | A >>> -4); + D += (A ^ B ^ C) + X4 + 0x4BDECFA9; + D = A + (D << 11 | D >>> -11); + C += (D ^ A ^ B) + X7 + 0xF6BB4B60; + C = D + (C << 16 | C >>> -16); + B += (C ^ D ^ A) + X10 + 0xBEBFBC70; + B = C + (B << 23 | B >>> -23); + + A += (B ^ C ^ D) + X13 + 0x289B7EC6; + A = B + (A << 4 | A >>> -4); + D += (A ^ B ^ C) + X0 + 0xEAA127FA; + D = A + (D << 11 | D >>> -11); + C += (D ^ A ^ B) + X3 + 0xD4EF3085; + C = D + (C << 16 | C >>> -16); + B += (C ^ D ^ A) + X6 + 0x04881D05; + B = C + (B << 23 | B >>> -23); + + A += (B ^ C ^ D) + X9 + 0xD9D4D039; + A = B + (A << 4 | A >>> -4); + D += (A ^ B ^ C) + X12 + 0xE6DB99E5; + D = A + (D << 11 | D >>> -11); + C += (D ^ A ^ B) + X15 + 0x1FA27CF8; + C = D + (C << 16 | C >>> -16); + B += (C ^ D ^ A) + X2 + 0xC4AC5665; + B = C + (B << 23 | B >>> -23); + + // round 4 + A += (C ^ (B | ~D)) + X0 + 0xF4292244; + A = B + (A << 6 | A >>> -6); + D += (B ^ (A | ~C)) + X7 + 0x432AFF97; + D = A + (D << 10 | D >>> -10); + C += (A ^ (D | ~B)) + X14 + 0xAB9423A7; + C = D + (C << 15 | C >>> -15); + B += (D ^ (C | ~A)) + X5 + 0xFC93A039; + B = C + (B << 21 | B >>> -21); + + A += (C ^ (B | ~D)) + X12 + 0x655B59C3; + A = B + (A << 6 | A >>> -6); + D += (B ^ (A | ~C)) + X3 + 0x8F0CCC92; + D = A + (D << 10 | D >>> -10); + C += (A ^ (D | ~B)) + X10 + 0xFFEFF47D; + C = D + (C << 15 | C >>> -15); + B += (D ^ (C | ~A)) + X1 + 0x85845dd1; + B = C + (B << 21 | B >>> -21); + + A += (C ^ (B | ~D)) + X8 + 0x6FA87E4F; + A = B + (A << 6 | A >>> -6); + D += (B ^ (A | ~C)) + X15 + 0xFE2CE6E0; + D = A + (D << 10 | D >>> -10); + C += (A ^ (D | ~B)) + X6 + 0xA3014314; + C = D + (C << 15 | C >>> -15); + B += (D ^ (C | ~A)) + X13 + 0x4E0811A1; + B = C + (B << 21 | B >>> -21); + + A += (C ^ (B | ~D)) + X4 + 0xF7537E82; + A = B + (A << 6 | A >>> -6); + D += (B ^ (A | ~C)) + X11 + 0xBD3AF235; + D = A + (D << 10 | D >>> -10); + C += (A ^ (D | ~B)) + X2 + 0x2AD7D2BB; + C = D + (C << 15 | C >>> -15); + B += (D ^ (C | ~A)) + X9 + 0xEB86D391; + B = C + (B << 21 | B >>> -21); + + h0 += A; + h1 += B; + h2 += C; + h3 += D; + } + + protected byte[] padBuffer() + { + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding + 8]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + result[padding++] = (byte) bits; + result[padding++] = (byte) (bits >>> 8); + result[padding++] = (byte) (bits >>> 16); + result[padding++] = (byte) (bits >>> 24); + result[padding++] = (byte) (bits >>> 32); + result[padding++] = (byte) (bits >>> 40); + result[padding++] = (byte) (bits >>> 48); + result[padding] = (byte) (bits >>> 56); + + return result; + } + + protected byte[] getResult() + { + byte[] result = new byte[] { (byte) h0, (byte) (h0 >>> 8), + (byte) (h0 >>> 16), (byte) (h0 >>> 24), + (byte) h1, (byte) (h1 >>> 8), + (byte) (h1 >>> 16), (byte) (h1 >>> 24), + (byte) h2, (byte) (h2 >>> 8), + (byte) (h2 >>> 16), (byte) (h2 >>> 24), + (byte) h3, (byte) (h3 >>> 8), + (byte) (h3 >>> 16), (byte) (h3 >>> 24) }; + + return result; + } + + protected void resetContext() + { + // magic MD5/RIPEMD128 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean(DIGEST0.equals(Util.toString(new MD5().digest()))); + } + return valid.booleanValue(); + } +} diff --git a/gnu/java/security/hash/RipeMD128.java b/gnu/java/security/hash/RipeMD128.java new file mode 100644 index 000000000..83e8f2504 --- /dev/null +++ b/gnu/java/security/hash/RipeMD128.java @@ -0,0 +1,291 @@ +/* RipeMD128.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

RIPEMD-128 is a 128-bit message digest.

+ * + *

References:

+ * + *
    + *
  1. + * RIPEMD160: A Strengthened Version of RIPEMD.
    + * Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
  2. + *
+ */ +public class RipeMD128 extends BaseHash +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + private static final String DIGEST0 = "CDF26213A150DC3ECB610F18F6B38B46"; + + /** Constants for the transform method. */ + // selection of message word + private static final int[] R = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, + 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, + 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, + 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2 }; + + private static final int[] Rp = { 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, + 10, 3, 12, 6, 11, 3, 7, 0, 13, 5, 10, 14, + 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, + 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, + 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14 }; + + // amount for rotate left (rol) + private static final int[] S = { 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, + 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, + 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, + 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, + 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, + 12 }; + + private static final int[] Sp = { 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, + 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, + 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, + 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, + 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, + 15, 8 }; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 128-bit h0, h1, h2, h3 (interim result) */ + private int h0, h1, h2, h3; + + /** 512 bits work buffer = 16 x 32-bit words */ + private int[] X = new int[16]; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public RipeMD128() + { + super(Registry.RIPEMD128_HASH, 16, BLOCK_SIZE); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param md the instance to clone. + */ + private RipeMD128(RipeMD128 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new RipeMD128(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected void transform(byte[] in, int offset) + { + int A, B, C, D, Ap, Bp, Cp, Dp, T, s, i; + + // encode 64 bytes from input block into an array of 16 unsigned + // integers. + for (i = 0; i < 16; i++) + { + X[i] = (in[offset++] & 0xFF) | (in[offset++] & 0xFF) << 8 + | (in[offset++] & 0xFF) << 16 | in[offset++] << 24; + } + + A = Ap = h0; + B = Bp = h1; + C = Cp = h2; + D = Dp = h3; + + for (i = 0; i < 16; i++) + { // rounds 0...15 + s = S[i]; + T = A + (B ^ C ^ D) + X[i]; + A = D; + D = C; + C = B; + B = T << s | T >>> (32 - s); + + s = Sp[i]; + T = Ap + ((Bp & Dp) | (Cp & ~Dp)) + X[Rp[i]] + 0x50A28BE6; + Ap = Dp; + Dp = Cp; + Cp = Bp; + Bp = T << s | T >>> (32 - s); + } + + for (; i < 32; i++) + { // rounds 16...31 + s = S[i]; + T = A + ((B & C) | (~B & D)) + X[R[i]] + 0x5A827999; + A = D; + D = C; + C = B; + B = T << s | T >>> (32 - s); + + s = Sp[i]; + T = Ap + ((Bp | ~Cp) ^ Dp) + X[Rp[i]] + 0x5C4DD124; + Ap = Dp; + Dp = Cp; + Cp = Bp; + Bp = T << s | T >>> (32 - s); + } + + for (; i < 48; i++) + { // rounds 32...47 + s = S[i]; + T = A + ((B | ~C) ^ D) + X[R[i]] + 0x6ED9EBA1; + A = D; + D = C; + C = B; + B = T << s | T >>> (32 - s); + + s = Sp[i]; + T = Ap + ((Bp & Cp) | (~Bp & Dp)) + X[Rp[i]] + 0x6D703EF3; + Ap = Dp; + Dp = Cp; + Cp = Bp; + Bp = T << s | T >>> (32 - s); + } + + for (; i < 64; i++) + { // rounds 48...63 + s = S[i]; + T = A + ((B & D) | (C & ~D)) + X[R[i]] + 0x8F1BBCDC; + A = D; + D = C; + C = B; + B = T << s | T >>> (32 - s); + + s = Sp[i]; + T = Ap + (Bp ^ Cp ^ Dp) + X[Rp[i]]; + Ap = Dp; + Dp = Cp; + Cp = Bp; + Bp = T << s | T >>> (32 - s); + } + + T = h1 + C + Dp; + h1 = h2 + D + Ap; + h2 = h3 + A + Bp; + h3 = h0 + B + Cp; + h0 = T; + } + + protected byte[] padBuffer() + { + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding + 8]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + result[padding++] = (byte) bits; + result[padding++] = (byte) (bits >>> 8); + result[padding++] = (byte) (bits >>> 16); + result[padding++] = (byte) (bits >>> 24); + result[padding++] = (byte) (bits >>> 32); + result[padding++] = (byte) (bits >>> 40); + result[padding++] = (byte) (bits >>> 48); + result[padding] = (byte) (bits >>> 56); + + return result; + } + + protected byte[] getResult() + { + byte[] result = new byte[] { (byte) h0, (byte) (h0 >>> 8), + (byte) (h0 >>> 16), (byte) (h0 >>> 24), + (byte) h1, (byte) (h1 >>> 8), + (byte) (h1 >>> 16), (byte) (h1 >>> 24), + (byte) h2, (byte) (h2 >>> 8), + (byte) (h2 >>> 16), (byte) (h2 >>> 24), + (byte) h3, (byte) (h3 >>> 8), + (byte) (h3 >>> 16), (byte) (h3 >>> 24) }; + + return result; + } + + protected void resetContext() + { + // magic RIPEMD128 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean + (DIGEST0.equals(Util.toString(new RipeMD128().digest()))); + } + return valid.booleanValue(); + } +} diff --git a/gnu/java/security/hash/RipeMD160.java b/gnu/java/security/hash/RipeMD160.java new file mode 100644 index 000000000..73ecc5161 --- /dev/null +++ b/gnu/java/security/hash/RipeMD160.java @@ -0,0 +1,328 @@ +/* RipeMD160.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

RIPEMD-160 is a 160-bit message digest.

+ * + *

References:

+ * + *
    + *
  1. + * RIPEMD160: A Strengthened Version of RIPEMD.
    + * Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
  2. + *
+ */ +public class RipeMD160 extends BaseHash +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + private static final String DIGEST0 = "9C1185A5C5E9FC54612808977EE8F548B2258D31"; + + // selection of message word + private static final int[] R = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, + 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, + 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, + 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 4, 0, + 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, + 13 }; + + private static final int[] Rp = { 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, + 10, 3, 12, 6, 11, 3, 7, 0, 13, 5, 10, 14, + 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, + 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, + 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, + 3, 9, 11 }; + + // amount for rotate left (rol) + private static final int[] S = { 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, + 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, + 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, + 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, + 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, + 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, + 14, 11, 8, 5, 6 }; + + private static final int[] Sp = { 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, + 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, + 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, + 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, + 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, + 15, 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, + 5, 15, 13, 11, 11 }; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 160-bit h0, h1, h2, h3, h4 (interim result) */ + private int h0, h1, h2, h3, h4; + + /** 512 bits work buffer = 16 x 32-bit words */ + private int[] X = new int[16]; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public RipeMD160() + { + super(Registry.RIPEMD160_HASH, 20, BLOCK_SIZE); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param md the instance to clone. + */ + private RipeMD160(RipeMD160 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return (new RipeMD160(this)); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected void transform(byte[] in, int offset) + { + int A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, T, s, i; + + // encode 64 bytes from input block into an array of 16 unsigned integers + for (i = 0; i < 16; i++) + { + X[i] = (in[offset++] & 0xFF) | (in[offset++] & 0xFF) << 8 + | (in[offset++] & 0xFF) << 16 | in[offset++] << 24; + } + + A = Ap = h0; + B = Bp = h1; + C = Cp = h2; + D = Dp = h3; + E = Ep = h4; + + for (i = 0; i < 16; i++) + { // rounds 0...15 + s = S[i]; + T = A + (B ^ C ^ D) + X[i]; + A = E; + E = D; + D = C << 10 | C >>> 22; + C = B; + B = (T << s | T >>> (32 - s)) + A; + + s = Sp[i]; + T = Ap + (Bp ^ (Cp | ~Dp)) + X[Rp[i]] + 0x50A28BE6; + Ap = Ep; + Ep = Dp; + Dp = Cp << 10 | Cp >>> 22; + Cp = Bp; + Bp = (T << s | T >>> (32 - s)) + Ap; + } + + for (; i < 32; i++) + { // rounds 16...31 + s = S[i]; + T = A + ((B & C) | (~B & D)) + X[R[i]] + 0x5A827999; + A = E; + E = D; + D = C << 10 | C >>> 22; + C = B; + B = (T << s | T >>> (32 - s)) + A; + + s = Sp[i]; + T = Ap + ((Bp & Dp) | (Cp & ~Dp)) + X[Rp[i]] + 0x5C4DD124; + Ap = Ep; + Ep = Dp; + Dp = Cp << 10 | Cp >>> 22; + Cp = Bp; + Bp = (T << s | T >>> (32 - s)) + Ap; + } + + for (; i < 48; i++) + { // rounds 32...47 + s = S[i]; + T = A + ((B | ~C) ^ D) + X[R[i]] + 0x6ED9EBA1; + A = E; + E = D; + D = C << 10 | C >>> 22; + C = B; + B = (T << s | T >>> (32 - s)) + A; + + s = Sp[i]; + T = Ap + ((Bp | ~Cp) ^ Dp) + X[Rp[i]] + 0x6D703EF3; + Ap = Ep; + Ep = Dp; + Dp = Cp << 10 | Cp >>> 22; + Cp = Bp; + Bp = (T << s | T >>> (32 - s)) + Ap; + } + + for (; i < 64; i++) + { // rounds 48...63 + s = S[i]; + T = A + ((B & D) | (C & ~D)) + X[R[i]] + 0x8F1BBCDC; + A = E; + E = D; + D = C << 10 | C >>> 22; + C = B; + B = (T << s | T >>> (32 - s)) + A; + + s = Sp[i]; + T = Ap + ((Bp & Cp) | (~Bp & Dp)) + X[Rp[i]] + 0x7A6D76E9; + Ap = Ep; + Ep = Dp; + Dp = Cp << 10 | Cp >>> 22; + Cp = Bp; + Bp = (T << s | T >>> (32 - s)) + Ap; + } + + for (; i < 80; i++) + { // rounds 64...79 + s = S[i]; + T = A + (B ^ (C | ~D)) + X[R[i]] + 0xA953FD4E; + A = E; + E = D; + D = C << 10 | C >>> 22; + C = B; + B = (T << s | T >>> (32 - s)) + A; + + s = Sp[i]; + T = Ap + (Bp ^ Cp ^ Dp) + X[Rp[i]]; + Ap = Ep; + Ep = Dp; + Dp = Cp << 10 | Cp >>> 22; + Cp = Bp; + Bp = (T << s | T >>> (32 - s)) + Ap; + } + + T = h1 + C + Dp; + h1 = h2 + D + Ep; + h2 = h3 + E + Ap; + h3 = h4 + A + Bp; + h4 = h0 + B + Cp; + h0 = T; + } + + protected byte[] padBuffer() + { + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding + 8]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + result[padding++] = (byte) bits; + result[padding++] = (byte) (bits >>> 8); + result[padding++] = (byte) (bits >>> 16); + result[padding++] = (byte) (bits >>> 24); + result[padding++] = (byte) (bits >>> 32); + result[padding++] = (byte) (bits >>> 40); + result[padding++] = (byte) (bits >>> 48); + result[padding] = (byte) (bits >>> 56); + + return result; + } + + protected byte[] getResult() + { + byte[] result = new byte[] { (byte) h0, (byte) (h0 >>> 8), + (byte) (h0 >>> 16), (byte) (h0 >>> 24), + (byte) h1, (byte) (h1 >>> 8), + (byte) (h1 >>> 16), (byte) (h1 >>> 24), + (byte) h2, (byte) (h2 >>> 8), + (byte) (h2 >>> 16), (byte) (h2 >>> 24), + (byte) h3, (byte) (h3 >>> 8), + (byte) (h3 >>> 16), (byte) (h3 >>> 24), + (byte) h4, (byte) (h4 >>> 8), + (byte) (h4 >>> 16), (byte) (h4 >>> 24) }; + + return result; + } + + protected void resetContext() + { + // magic RIPEMD160 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + h4 = 0xC3D2E1F0; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean + (DIGEST0.equals(Util.toString(new RipeMD160().digest()))); + } + return valid.booleanValue(); + } +} diff --git a/gnu/java/security/hash/Sha160.java b/gnu/java/security/hash/Sha160.java new file mode 100644 index 000000000..bf5f45652 --- /dev/null +++ b/gnu/java/security/hash/Sha160.java @@ -0,0 +1,308 @@ +/* Sha160.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

The Secure Hash Algorithm (SHA-1) is required for use with the Digital + * Signature Algorithm (DSA) as specified in the Digital Signature Standard + * (DSS) and whenever a secure hash algorithm is required for federal + * applications. For a message of length less than 2^64 bits, the SHA-1 + * produces a 160-bit condensed representation of the message called a message + * digest. The message digest is used during generation of a signature for the + * message. The SHA-1 is also used to compute a message digest for the received + * version of the message during the process of verifying the signature. Any + * change to the message in transit will, with very high probability, result in + * a different message digest, and the signature will fail to verify.

+ * + *

The SHA-1 is designed to have the following properties: it is + * computationally infeasible to find a message which corresponds to a given + * message digest, or to find two different messages which produce the same + * message digest.

+ * + *

References:

+ * + *
    + *
  1. SECURE HASH + * STANDARD
    + * Federal Information, Processing Standards Publication 180-1, 1995 April 17. + *
  2. + *
+ */ +public class Sha160 extends BaseHash +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + private static final String DIGEST0 = "A9993E364706816ABA3E25717850C26C9CD0D89D"; + + private static final int[] w = new int[80]; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 160-bit interim result. */ + private int h0, h1, h2, h3, h4; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Sha160() + { + super(Registry.SHA160_HASH, 20, BLOCK_SIZE); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param md the instance to clone. + */ + private Sha160(Sha160 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final int[] G(int hh0, int hh1, int hh2, int hh3, int hh4, + byte[] in, int offset) + { + // int[] w = new int[80]; + // int i, T; + // for (i = 0; i < 16; i++) { + // w[i] = in[offset++] << 24 | + // (in[offset++] & 0xFF) << 16 | + // (in[offset++] & 0xFF) << 8 | + // (in[offset++] & 0xFF); + // } + // for (i = 16; i < 80; i++) { + // T = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]; + // w[i] = T << 1 | T >>> 31; + // } + + // return sha(hh0, hh1, hh2, hh3, hh4, in, offset, w); + return sha(hh0, hh1, hh2, hh3, hh4, in, offset); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new Sha160(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected void transform(byte[] in, int offset) + { + // int i, T; + // for (i = 0; i < 16; i++) { + // W[i] = in[offset++] << 24 | + // (in[offset++] & 0xFF) << 16 | + // (in[offset++] & 0xFF) << 8 | + // (in[offset++] & 0xFF); + // } + // for (i = 16; i < 80; i++) { + // T = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; + // W[i] = T << 1 | T >>> 31; + // } + + // int[] result = sha(h0, h1, h2, h3, h4, in, offset, W); + int[] result = sha(h0, h1, h2, h3, h4, in, offset); + + h0 = result[0]; + h1 = result[1]; + h2 = result[2]; + h3 = result[3]; + h4 = result[4]; + } + + protected byte[] padBuffer() + { + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding + 8]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + result[padding++] = (byte) (bits >>> 56); + result[padding++] = (byte) (bits >>> 48); + result[padding++] = (byte) (bits >>> 40); + result[padding++] = (byte) (bits >>> 32); + result[padding++] = (byte) (bits >>> 24); + result[padding++] = (byte) (bits >>> 16); + result[padding++] = (byte) (bits >>> 8); + result[padding] = (byte) bits; + + return result; + } + + protected byte[] getResult() + { + byte[] result = new byte[] { (byte) (h0 >>> 24), (byte) (h0 >>> 16), + (byte) (h0 >>> 8), (byte) h0, + (byte) (h1 >>> 24), (byte) (h1 >>> 16), + (byte) (h1 >>> 8), (byte) h1, + (byte) (h2 >>> 24), (byte) (h2 >>> 16), + (byte) (h2 >>> 8), (byte) h2, + (byte) (h3 >>> 24), (byte) (h3 >>> 16), + (byte) (h3 >>> 8), (byte) h3, + (byte) (h4 >>> 24), (byte) (h4 >>> 16), + (byte) (h4 >>> 8), (byte) h4 }; + + return result; + } + + protected void resetContext() + { + // magic SHA-1/RIPEMD160 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + h4 = 0xC3D2E1F0; + } + + public boolean selfTest() + { + if (valid == null) + { + Sha160 md = new Sha160(); + md.update((byte) 0x61); // a + md.update((byte) 0x62); // b + md.update((byte) 0x63); // c + String result = Util.toString(md.digest()); + valid = new Boolean(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + // SHA specific methods ---------------------------------------------------- + + private static final synchronized int[] + // sha(int hh0, int hh1, int hh2, int hh3, int hh4, byte[] in, int offset, int[] w) { + sha(int hh0, int hh1, int hh2, int hh3, int hh4, byte[] in, int offset) + { + int A = hh0; + int B = hh1; + int C = hh2; + int D = hh3; + int E = hh4; + int r, T; + + for (r = 0; r < 16; r++) + { + w[r] = in[offset++] << 24 | (in[offset++] & 0xFF) << 16 + | (in[offset++] & 0xFF) << 8 | (in[offset++] & 0xFF); + } + for (r = 16; r < 80; r++) + { + T = w[r - 3] ^ w[r - 8] ^ w[r - 14] ^ w[r - 16]; + w[r] = T << 1 | T >>> 31; + } + + // rounds 0-19 + for (r = 0; r < 20; r++) + { + T = (A << 5 | A >>> 27) + ((B & C) | (~B & D)) + E + w[r] + 0x5A827999; + E = D; + D = C; + C = B << 30 | B >>> 2; + B = A; + A = T; + } + + // rounds 20-39 + for (r = 20; r < 40; r++) + { + T = (A << 5 | A >>> 27) + (B ^ C ^ D) + E + w[r] + 0x6ED9EBA1; + E = D; + D = C; + C = B << 30 | B >>> 2; + B = A; + A = T; + } + + // rounds 40-59 + for (r = 40; r < 60; r++) + { + T = (A << 5 | A >>> 27) + (B & C | B & D | C & D) + E + w[r] + + 0x8F1BBCDC; + E = D; + D = C; + C = B << 30 | B >>> 2; + B = A; + A = T; + } + + // rounds 60-79 + for (r = 60; r < 80; r++) + { + T = (A << 5 | A >>> 27) + (B ^ C ^ D) + E + w[r] + 0xCA62C1D6; + E = D; + D = C; + C = B << 30 | B >>> 2; + B = A; + A = T; + } + + return new int[] { hh0 + A, hh1 + B, hh2 + C, hh3 + D, hh4 + E }; + } +} diff --git a/gnu/java/security/hash/Sha256.java b/gnu/java/security/hash/Sha256.java new file mode 100644 index 000000000..9ef70a1a6 --- /dev/null +++ b/gnu/java/security/hash/Sha256.java @@ -0,0 +1,278 @@ +/* Sha256.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

Implementation of SHA2-1 [SHA-256] per the IETF Draft Specification.

+ * + *

References:

+ *
    + *
  1. + * Descriptions of SHA-256, SHA-384, and SHA-512,
  2. + *
  3. http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf
  4. + *
+ */ +public class Sha256 extends BaseHash +{ + + // Constants and variables + // ------------------------------------------------------------------------- + private static final int[] k = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, + 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, + 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, + 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, + 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, + 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, + 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, + 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, + 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, + 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, + 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, + 0xc67178f2 }; + + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + private static final String DIGEST0 = "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"; + + private static final int[] w = new int[64]; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 256-bit interim result. */ + private int h0, h1, h2, h3, h4, h5, h6, h7; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Sha256() + { + super(Registry.SHA256_HASH, 32, BLOCK_SIZE); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param md the instance to clone. + */ + private Sha256(Sha256 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.h5 = md.h5; + this.h6 = md.h6; + this.h7 = md.h7; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final int[] G(int hh0, int hh1, int hh2, int hh3, int hh4, + int hh5, int hh6, int hh7, byte[] in, int offset) + { + return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new Sha256(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected void transform(byte[] in, int offset) + { + int[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset); + + h0 = result[0]; + h1 = result[1]; + h2 = result[2]; + h3 = result[3]; + h4 = result[4]; + h5 = result[5]; + h6 = result[6]; + h7 = result[7]; + } + + protected byte[] padBuffer() + { + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding + 8]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + result[padding++] = (byte) (bits >>> 56); + result[padding++] = (byte) (bits >>> 48); + result[padding++] = (byte) (bits >>> 40); + result[padding++] = (byte) (bits >>> 32); + result[padding++] = (byte) (bits >>> 24); + result[padding++] = (byte) (bits >>> 16); + result[padding++] = (byte) (bits >>> 8); + result[padding] = (byte) bits; + + return result; + } + + protected byte[] getResult() + { + return new byte[] { (byte) (h0 >>> 24), (byte) (h0 >>> 16), + (byte) (h0 >>> 8), (byte) h0, (byte) (h1 >>> 24), + (byte) (h1 >>> 16), (byte) (h1 >>> 8), (byte) h1, + (byte) (h2 >>> 24), (byte) (h2 >>> 16), + (byte) (h2 >>> 8), (byte) h2, (byte) (h3 >>> 24), + (byte) (h3 >>> 16), (byte) (h3 >>> 8), (byte) h3, + (byte) (h4 >>> 24), (byte) (h4 >>> 16), + (byte) (h4 >>> 8), (byte) h4, (byte) (h5 >>> 24), + (byte) (h5 >>> 16), (byte) (h5 >>> 8), (byte) h5, + (byte) (h6 >>> 24), (byte) (h6 >>> 16), + (byte) (h6 >>> 8), (byte) h6, (byte) (h7 >>> 24), + (byte) (h7 >>> 16), (byte) (h7 >>> 8), (byte) h7 }; + } + + protected void resetContext() + { + // magic SHA-256 initialisation constants + h0 = 0x6a09e667; + h1 = 0xbb67ae85; + h2 = 0x3c6ef372; + h3 = 0xa54ff53a; + h4 = 0x510e527f; + h5 = 0x9b05688c; + h6 = 0x1f83d9ab; + h7 = 0x5be0cd19; + } + + public boolean selfTest() + { + if (valid == null) + { + Sha256 md = new Sha256(); + md.update((byte) 0x61); // a + md.update((byte) 0x62); // b + md.update((byte) 0x63); // c + String result = Util.toString(md.digest()); + valid = new Boolean(DIGEST0.equals(result)); + } + + return valid.booleanValue(); + } + + // SHA specific methods ---------------------------------------------------- + + private static final synchronized int[] sha(int hh0, int hh1, int hh2, + int hh3, int hh4, int hh5, + int hh6, int hh7, byte[] in, + int offset) + { + int A = hh0; + int B = hh1; + int C = hh2; + int D = hh3; + int E = hh4; + int F = hh5; + int G = hh6; + int H = hh7; + int r, T, T2; + + for (r = 0; r < 16; r++) + { + w[r] = (in[offset++] << 24 | (in[offset++] & 0xFF) << 16 + | (in[offset++] & 0xFF) << 8 | (in[offset++] & 0xFF)); + } + for (r = 16; r < 64; r++) + { + T = w[r - 2]; + T2 = w[r - 15]; + w[r] = ((((T >>> 17) | (T << 15)) ^ ((T >>> 19) | (T << 13)) ^ (T >>> 10)) + + w[r - 7] + + (((T2 >>> 7) | (T2 << 25)) ^ ((T2 >>> 18) | (T2 << 14)) ^ (T2 >>> 3)) + + w[r - 16]); + } + + for (r = 0; r < 64; r++) + { + T = (H + + (((E >>> 6) | (E << 26)) ^ ((E >>> 11) | (E << 21)) ^ ((E >>> 25) | (E << 7))) + + ((E & F) ^ (~E & G)) + k[r] + w[r]); + T2 = ((((A >>> 2) | (A << 30)) ^ ((A >>> 13) | (A << 19)) ^ ((A >>> 22) | (A << 10))) + + ((A & B) ^ (A & C) ^ (B & C))); + H = G; + G = F; + F = E; + E = D + T; + D = C; + C = B; + B = A; + A = T + T2; + } + + return new int[] { hh0 + A, hh1 + B, hh2 + C, hh3 + D, hh4 + E, hh5 + F, + hh6 + G, hh7 + H }; + } +} diff --git a/gnu/java/security/hash/Sha384.java b/gnu/java/security/hash/Sha384.java new file mode 100644 index 000000000..2f619dc98 --- /dev/null +++ b/gnu/java/security/hash/Sha384.java @@ -0,0 +1,322 @@ +/* Sha384.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

Implementation of SHA2-2 [SHA-384] per the IETF Draft Specification.

+ * + *

References:

+ *
    + *
  1. + * Descriptions of SHA-256, SHA-384, and SHA-512,
  2. + *
  3. http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf
  4. + *
+ */ +public class Sha384 extends BaseHash +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final long[] k = { 0x428a2f98d728ae22L, 0x7137449123ef65cdL, + 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL, + 0x3956c25bf348b538L, 0x59f111f1b605d019L, + 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L, + 0xd807aa98a3030242L, 0x12835b0145706fbeL, + 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L, + 0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, + 0x9bdc06a725c71235L, 0xc19bf174cf692694L, + 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, + 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L, + 0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, + 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L, + 0x983e5152ee66dfabL, 0xa831c66d2db43210L, + 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L, + 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, + 0x06ca6351e003826fL, 0x142929670a0e6e70L, + 0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, + 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL, + 0x650a73548baf63deL, 0x766a0abb3c77b2a8L, + 0x81c2c92e47edaee6L, 0x92722c851482353bL, + 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, + 0xc24b8b70d0f89791L, 0xc76c51a30654be30L, + 0xd192e819d6ef5218L, 0xd69906245565a910L, + 0xf40e35855771202aL, 0x106aa07032bbd1b8L, + 0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, + 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L, + 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, + 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L, + 0x748f82ee5defb2fcL, 0x78a5636f43172f60L, + 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL, + 0x90befffa23631e28L, 0xa4506cebde82bde9L, + 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL, + 0xca273eceea26619cL, 0xd186b8c721c0c207L, + 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L, + 0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, + 0x113f9804bef90daeL, 0x1b710b35131c471bL, + 0x28db77f523047d84L, 0x32caab7b40c72493L, + 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL, + 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, + 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L }; + + private static final int BLOCK_SIZE = 128; // inner block size in bytes + + private static final String DIGEST0 = "CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED" + + "8086072BA1E7CC2358BAECA134C825A7"; + + private static final long[] w = new long[80]; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 512-bit interim result. */ + private long h0, h1, h2, h3, h4, h5, h6, h7; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Sha384() + { + super(Registry.SHA384_HASH, 48, BLOCK_SIZE); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param md the instance to clone. + */ + private Sha384(Sha384 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.h5 = md.h5; + this.h6 = md.h6; + this.h7 = md.h7; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final long[] G(long hh0, long hh1, long hh2, long hh3, + long hh4, long hh5, long hh6, long hh7, + byte[] in, int offset) + { + return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new Sha384(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected void transform(byte[] in, int offset) + { + long[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset); + + h0 = result[0]; + h1 = result[1]; + h2 = result[2]; + h3 = result[3]; + h4 = result[4]; + h5 = result[5]; + h6 = result[6]; + h7 = result[7]; + } + + protected byte[] padBuffer() + { + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 112) ? (112 - n) : (240 - n); + byte[] result = new byte[padding + 16]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + + // save number of bits, casting the long to an array of 8 bytes + // TODO: FIX Only ~35 bits of 128 bit counter usable this way + long bits = count << 3; + padding += 8; + result[padding++] = (byte) (bits >>> 56); + result[padding++] = (byte) (bits >>> 48); + result[padding++] = (byte) (bits >>> 40); + result[padding++] = (byte) (bits >>> 32); + result[padding++] = (byte) (bits >>> 24); + result[padding++] = (byte) (bits >>> 16); + result[padding++] = (byte) (bits >>> 8); + result[padding] = (byte) bits; + + return result; + } + + protected byte[] getResult() + { + return new byte[] { (byte) (h0 >>> 56), (byte) (h0 >>> 48), + (byte) (h0 >>> 40), (byte) (h0 >>> 32), + (byte) (h0 >>> 24), (byte) (h0 >>> 16), + (byte) (h0 >>> 8), (byte) h0, (byte) (h1 >>> 56), + (byte) (h1 >>> 48), (byte) (h1 >>> 40), + (byte) (h1 >>> 32), (byte) (h1 >>> 24), + (byte) (h1 >>> 16), (byte) (h1 >>> 8), (byte) h1, + (byte) (h2 >>> 56), (byte) (h2 >>> 48), + (byte) (h2 >>> 40), (byte) (h2 >>> 32), + (byte) (h2 >>> 24), (byte) (h2 >>> 16), + (byte) (h2 >>> 8), (byte) h2, (byte) (h3 >>> 56), + (byte) (h3 >>> 48), (byte) (h3 >>> 40), + (byte) (h3 >>> 32), (byte) (h3 >>> 24), + (byte) (h3 >>> 16), (byte) (h3 >>> 8), (byte) h3, + (byte) (h4 >>> 56), (byte) (h4 >>> 48), + (byte) (h4 >>> 40), (byte) (h4 >>> 32), + (byte) (h4 >>> 24), (byte) (h4 >>> 16), + (byte) (h4 >>> 8), (byte) h4, (byte) (h5 >>> 56), + (byte) (h5 >>> 48), (byte) (h5 >>> 40), + (byte) (h5 >>> 32), (byte) (h5 >>> 24), + (byte) (h5 >>> 16), (byte) (h5 >>> 8), (byte) h5 + // (byte)(h6 >>> 56), (byte)(h6 >>> 48), (byte)(h6 >>> 40), (byte)(h6 >>> 32), + // (byte)(h6 >>> 24), (byte)(h6 >>> 16), (byte)(h6 >>> 8), (byte) h6, + // (byte)(h7 >>> 56), (byte)(h7 >>> 48), (byte)(h7 >>> 40), (byte)(h7 >>> 32), + // (byte)(h7 >>> 24), (byte)(h7 >>> 16), (byte)(h7 >>> 8), (byte) h7 + }; + } + + protected void resetContext() + { + // magic SHA-384 initialisation constants + h0 = 0xcbbb9d5dc1059ed8L; + h1 = 0x629a292a367cd507L; + h2 = 0x9159015a3070dd17L; + h3 = 0x152fecd8f70e5939L; + h4 = 0x67332667ffc00b31L; + h5 = 0x8eb44a8768581511L; + h6 = 0xdb0c2e0d64f98fa7L; + h7 = 0x47b5481dbefa4fa4L; + } + + public boolean selfTest() + { + if (valid == null) + { + Sha384 md = new Sha384(); + md.update((byte) 0x61); // a + md.update((byte) 0x62); // b + md.update((byte) 0x63); // c + String result = Util.toString(md.digest()); + valid = new Boolean(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + // SHA specific methods ---------------------------------------------------- + + private static final synchronized long[] sha(long hh0, long hh1, long hh2, + long hh3, long hh4, long hh5, + long hh6, long hh7, byte[] in, + int offset) + { + long A = hh0; + long B = hh1; + long C = hh2; + long D = hh3; + long E = hh4; + long F = hh5; + long G = hh6; + long H = hh7; + long T, T2; + int r; + + for (r = 0; r < 16; r++) + { + w[r] = (long) in[offset++] << 56 | ((long) in[offset++] & 0xFF) << 48 + | ((long) in[offset++] & 0xFF) << 40 + | ((long) in[offset++] & 0xFF) << 32 + | ((long) in[offset++] & 0xFF) << 24 + | ((long) in[offset++] & 0xFF) << 16 + | ((long) in[offset++] & 0xFF) << 8 + | ((long) in[offset++] & 0xFF); + } + for (r = 16; r < 80; r++) + { + T = w[r - 2]; + T2 = w[r - 15]; + w[r] = (((T >>> 19) | (T << 45)) ^ ((T >>> 61) | (T << 3)) ^ (T >>> 6)) + + w[r - 7] + + (((T2 >>> 1) | (T2 << 63)) ^ ((T2 >>> 8) | (T2 << 56)) ^ (T2 >>> 7)) + + w[r - 16]; + } + + for (r = 0; r < 80; r++) + { + + T = H + + (((E >>> 14) | (E << 50)) ^ ((E >>> 18) | (E << 46)) ^ ((E >>> 41) | (E << 23))) + + ((E & F) ^ ((~E) & G)) + k[r] + w[r]; + // T IS INCORRECT SOMEHOW + T2 = (((A >>> 28) | (A << 36)) ^ ((A >>> 34) | (A << 30)) ^ ((A >>> 39) | (A << 25))) + + ((A & B) ^ (A & C) ^ (B & C)); + H = G; + G = F; + F = E; + E = D + T; + D = C; + C = B; + B = A; + A = T + T2; + } + + return new long[] { hh0 + A, hh1 + B, hh2 + C, hh3 + D, hh4 + E, hh5 + F, + hh6 + G, hh7 + H }; + } +} diff --git a/gnu/java/security/hash/Sha512.java b/gnu/java/security/hash/Sha512.java new file mode 100644 index 000000000..798b34dfc --- /dev/null +++ b/gnu/java/security/hash/Sha512.java @@ -0,0 +1,322 @@ +/* Sha512.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

Implementation of SHA2-3 [SHA-512] per the IETF Draft Specification.

+ * + *

References:

+ *
    + *
  1. + * Descriptions of SHA-256, SHA-384, and SHA-512,
  2. + *
  3. http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf
  4. + *
+ */ +public class Sha512 extends BaseHash +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final long[] k = { 0x428a2f98d728ae22L, 0x7137449123ef65cdL, + 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL, + 0x3956c25bf348b538L, 0x59f111f1b605d019L, + 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L, + 0xd807aa98a3030242L, 0x12835b0145706fbeL, + 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L, + 0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, + 0x9bdc06a725c71235L, 0xc19bf174cf692694L, + 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, + 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L, + 0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, + 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L, + 0x983e5152ee66dfabL, 0xa831c66d2db43210L, + 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L, + 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, + 0x06ca6351e003826fL, 0x142929670a0e6e70L, + 0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, + 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL, + 0x650a73548baf63deL, 0x766a0abb3c77b2a8L, + 0x81c2c92e47edaee6L, 0x92722c851482353bL, + 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, + 0xc24b8b70d0f89791L, 0xc76c51a30654be30L, + 0xd192e819d6ef5218L, 0xd69906245565a910L, + 0xf40e35855771202aL, 0x106aa07032bbd1b8L, + 0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, + 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L, + 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, + 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L, + 0x748f82ee5defb2fcL, 0x78a5636f43172f60L, + 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL, + 0x90befffa23631e28L, 0xa4506cebde82bde9L, + 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL, + 0xca273eceea26619cL, 0xd186b8c721c0c207L, + 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L, + 0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, + 0x113f9804bef90daeL, 0x1b710b35131c471bL, + 0x28db77f523047d84L, 0x32caab7b40c72493L, + 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL, + 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, + 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L }; + + private static final int BLOCK_SIZE = 128; // inner block size in bytes + + private static final String DIGEST0 = "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA20A9EEEE64B55D39A" + + "2192992A274FC1A836BA3C23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F"; + + private static final long[] w = new long[80]; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 512-bit interim result. */ + private long h0, h1, h2, h3, h4, h5, h6, h7; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Sha512() + { + super(Registry.SHA512_HASH, 64, BLOCK_SIZE); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param md the instance to clone. + */ + private Sha512(Sha512 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.h5 = md.h5; + this.h6 = md.h6; + this.h7 = md.h7; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final long[] G(long hh0, long hh1, long hh2, long hh3, + long hh4, long hh5, long hh6, long hh7, + byte[] in, int offset) + { + return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new Sha512(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected void transform(byte[] in, int offset) + { + long[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset); + + h0 = result[0]; + h1 = result[1]; + h2 = result[2]; + h3 = result[3]; + h4 = result[4]; + h5 = result[5]; + h6 = result[6]; + h7 = result[7]; + } + + protected byte[] padBuffer() + { + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 112) ? (112 - n) : (240 - n); + byte[] result = new byte[padding + 16]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + + // save number of bits, casting the long to an array of 8 bytes + // TODO: FIX Only ~35 bits of 128 bit counter usable this way + long bits = count << 3; + padding += 8; + result[padding++] = (byte) (bits >>> 56); + result[padding++] = (byte) (bits >>> 48); + result[padding++] = (byte) (bits >>> 40); + result[padding++] = (byte) (bits >>> 32); + result[padding++] = (byte) (bits >>> 24); + result[padding++] = (byte) (bits >>> 16); + result[padding++] = (byte) (bits >>> 8); + result[padding] = (byte) bits; + + return result; + } + + protected byte[] getResult() + { + return new byte[] { (byte) (h0 >>> 56), (byte) (h0 >>> 48), + (byte) (h0 >>> 40), (byte) (h0 >>> 32), + (byte) (h0 >>> 24), (byte) (h0 >>> 16), + (byte) (h0 >>> 8), (byte) h0, (byte) (h1 >>> 56), + (byte) (h1 >>> 48), (byte) (h1 >>> 40), + (byte) (h1 >>> 32), (byte) (h1 >>> 24), + (byte) (h1 >>> 16), (byte) (h1 >>> 8), (byte) h1, + (byte) (h2 >>> 56), (byte) (h2 >>> 48), + (byte) (h2 >>> 40), (byte) (h2 >>> 32), + (byte) (h2 >>> 24), (byte) (h2 >>> 16), + (byte) (h2 >>> 8), (byte) h2, (byte) (h3 >>> 56), + (byte) (h3 >>> 48), (byte) (h3 >>> 40), + (byte) (h3 >>> 32), (byte) (h3 >>> 24), + (byte) (h3 >>> 16), (byte) (h3 >>> 8), (byte) h3, + (byte) (h4 >>> 56), (byte) (h4 >>> 48), + (byte) (h4 >>> 40), (byte) (h4 >>> 32), + (byte) (h4 >>> 24), (byte) (h4 >>> 16), + (byte) (h4 >>> 8), (byte) h4, (byte) (h5 >>> 56), + (byte) (h5 >>> 48), (byte) (h5 >>> 40), + (byte) (h5 >>> 32), (byte) (h5 >>> 24), + (byte) (h5 >>> 16), (byte) (h5 >>> 8), (byte) h5, + (byte) (h6 >>> 56), (byte) (h6 >>> 48), + (byte) (h6 >>> 40), (byte) (h6 >>> 32), + (byte) (h6 >>> 24), (byte) (h6 >>> 16), + (byte) (h6 >>> 8), (byte) h6, (byte) (h7 >>> 56), + (byte) (h7 >>> 48), (byte) (h7 >>> 40), + (byte) (h7 >>> 32), (byte) (h7 >>> 24), + (byte) (h7 >>> 16), (byte) (h7 >>> 8), (byte) h7 }; + } + + protected void resetContext() + { + // magic SHA-512 initialisation constants + h0 = 0x6a09e667f3bcc908L; + h1 = 0xbb67ae8584caa73bL; + h2 = 0x3c6ef372fe94f82bL; + h3 = 0xa54ff53a5f1d36f1L; + h4 = 0x510e527fade682d1L; + h5 = 0x9b05688c2b3e6c1fL; + h6 = 0x1f83d9abfb41bd6bL; + h7 = 0x5be0cd19137e2179L; + } + + public boolean selfTest() + { + if (valid == null) + { + Sha512 md = new Sha512(); + md.update((byte) 0x61); // a + md.update((byte) 0x62); // b + md.update((byte) 0x63); // c + String result = Util.toString(md.digest()); + valid = new Boolean(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + // SHA specific methods ---------------------------------------------------- + + private static final synchronized long[] sha(long hh0, long hh1, long hh2, + long hh3, long hh4, long hh5, + long hh6, long hh7, byte[] in, + int offset) + { + long A = hh0; + long B = hh1; + long C = hh2; + long D = hh3; + long E = hh4; + long F = hh5; + long G = hh6; + long H = hh7; + long T, T2; + int r; + + for (r = 0; r < 16; r++) + { + w[r] = (long) in[offset++] << 56 | ((long) in[offset++] & 0xFF) << 48 + | ((long) in[offset++] & 0xFF) << 40 + | ((long) in[offset++] & 0xFF) << 32 + | ((long) in[offset++] & 0xFF) << 24 + | ((long) in[offset++] & 0xFF) << 16 + | ((long) in[offset++] & 0xFF) << 8 + | ((long) in[offset++] & 0xFF); + } + for (r = 16; r < 80; r++) + { + T = w[r - 2]; + T2 = w[r - 15]; + w[r] = (((T >>> 19) | (T << 45)) ^ ((T >>> 61) | (T << 3)) ^ (T >>> 6)) + + w[r - 7] + + (((T2 >>> 1) | (T2 << 63)) ^ ((T2 >>> 8) | (T2 << 56)) ^ (T2 >>> 7)) + + w[r - 16]; + } + + for (r = 0; r < 80; r++) + { + T = H + + (((E >>> 14) | (E << 50)) ^ ((E >>> 18) | (E << 46)) ^ ((E >>> 41) | (E << 23))) + + ((E & F) ^ ((~E) & G)) + k[r] + w[r]; + T2 = (((A >>> 28) | (A << 36)) ^ ((A >>> 34) | (A << 30)) ^ ((A >>> 39) | (A << 25))) + + ((A & B) ^ (A & C) ^ (B & C)); + H = G; + G = F; + F = E; + E = D + T; + D = C; + C = B; + B = A; + A = T + T2; + } + + return new long[] { hh0 + A, hh1 + B, hh2 + C, hh3 + D, hh4 + E, hh5 + F, + hh6 + G, hh7 + H }; + } +} diff --git a/gnu/java/security/hash/Tiger.java b/gnu/java/security/hash/Tiger.java new file mode 100644 index 000000000..f39fed30d --- /dev/null +++ b/gnu/java/security/hash/Tiger.java @@ -0,0 +1,943 @@ +/* Tiger.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + * The Tiger message digest. Tiger was designed by Ross Anderson and Eli + * Biham, with the goal of producing a secure, fast hash function that + * performs especially well on next-generation 64-bit architectures, but + * is still efficient on 32- and 16-bit architectures. + * + *

Tiger processes data in 512-bit blocks and produces a 192-bit + * digest.

+ * + *

References:

+ *
    + *
  1. Tiger: A + * Fast New Hash Function, Ross Anderson and Eli Biham.
  2. + *
+ */ +public class Tiger extends BaseHash +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + private static final int HASH_SIZE = 24; + + private static final int BLOCK_SIZE = 64; + + /** Result when no data has been input. */ + private static final String DIGEST0 = "3293AC630C13F0245F92BBB1766E16167A4E58492DDE73F3"; + + private static final long A = 0x0123456789ABCDEFL; + + private static final long B = 0xFEDCBA9876543210L; + + private static final long C = 0xF096A5B4C3B2E187L; + + /** S-Box T1. */ + private static final long[] T1 = { 0x02AAB17CF7E90C5EL, 0xAC424B03E243A8ECL, + 0x72CD5BE30DD5FCD3L, 0x6D019B93F6F97F3AL, + 0xCD9978FFD21F9193L, 0x7573A1C9708029E2L, + 0xB164326B922A83C3L, 0x46883EEE04915870L, + 0xEAACE3057103ECE6L, 0xC54169B808A3535CL, + 0x4CE754918DDEC47CL, 0x0AA2F4DFDC0DF40CL, + 0x10B76F18A74DBEFAL, 0xC6CCB6235AD1AB6AL, + 0x13726121572FE2FFL, 0x1A488C6F199D921EL, + 0x4BC9F9F4DA0007CAL, 0x26F5E6F6E85241C7L, + 0x859079DBEA5947B6L, 0x4F1885C5C99E8C92L, + 0xD78E761EA96F864BL, 0x8E36428C52B5C17DL, + 0x69CF6827373063C1L, 0xB607C93D9BB4C56EL, + 0x7D820E760E76B5EAL, 0x645C9CC6F07FDC42L, + 0xBF38A078243342E0L, 0x5F6B343C9D2E7D04L, + 0xF2C28AEB600B0EC6L, 0x6C0ED85F7254BCACL, + 0x71592281A4DB4FE5L, 0x1967FA69CE0FED9FL, + 0xFD5293F8B96545DBL, 0xC879E9D7F2A7600BL, + 0x860248920193194EL, 0xA4F9533B2D9CC0B3L, + 0x9053836C15957613L, 0xDB6DCF8AFC357BF1L, + 0x18BEEA7A7A370F57L, 0x037117CA50B99066L, + 0x6AB30A9774424A35L, 0xF4E92F02E325249BL, + 0x7739DB07061CCAE1L, 0xD8F3B49CECA42A05L, + 0xBD56BE3F51382F73L, 0x45FAED5843B0BB28L, + 0x1C813D5C11BF1F83L, 0x8AF0E4B6D75FA169L, + 0x33EE18A487AD9999L, 0x3C26E8EAB1C94410L, + 0xB510102BC0A822F9L, 0x141EEF310CE6123BL, + 0xFC65B90059DDB154L, 0xE0158640C5E0E607L, + 0x884E079826C3A3CFL, 0x930D0D9523C535FDL, + 0x35638D754E9A2B00L, 0x4085FCCF40469DD5L, + 0xC4B17AD28BE23A4CL, 0xCAB2F0FC6A3E6A2EL, + 0x2860971A6B943FCDL, 0x3DDE6EE212E30446L, + 0x6222F32AE01765AEL, 0x5D550BB5478308FEL, + 0xA9EFA98DA0EDA22AL, 0xC351A71686C40DA7L, + 0x1105586D9C867C84L, 0xDCFFEE85FDA22853L, + 0xCCFBD0262C5EEF76L, 0xBAF294CB8990D201L, + 0xE69464F52AFAD975L, 0x94B013AFDF133E14L, + 0x06A7D1A32823C958L, 0x6F95FE5130F61119L, + 0xD92AB34E462C06C0L, 0xED7BDE33887C71D2L, + 0x79746D6E6518393EL, 0x5BA419385D713329L, + 0x7C1BA6B948A97564L, 0x31987C197BFDAC67L, + 0xDE6C23C44B053D02L, 0x581C49FED002D64DL, + 0xDD474D6338261571L, 0xAA4546C3E473D062L, + 0x928FCE349455F860L, 0x48161BBACAAB94D9L, + 0x63912430770E6F68L, 0x6EC8A5E602C6641CL, + 0x87282515337DDD2BL, 0x2CDA6B42034B701BL, + 0xB03D37C181CB096DL, 0xE108438266C71C6FL, + 0x2B3180C7EB51B255L, 0xDF92B82F96C08BBCL, + 0x5C68C8C0A632F3BAL, 0x5504CC861C3D0556L, + 0xABBFA4E55FB26B8FL, 0x41848B0AB3BACEB4L, + 0xB334A273AA445D32L, 0xBCA696F0A85AD881L, + 0x24F6EC65B528D56CL, 0x0CE1512E90F4524AL, + 0x4E9DD79D5506D35AL, 0x258905FAC6CE9779L, + 0x2019295B3E109B33L, 0xF8A9478B73A054CCL, + 0x2924F2F934417EB0L, 0x3993357D536D1BC4L, + 0x38A81AC21DB6FF8BL, 0x47C4FBF17D6016BFL, + 0x1E0FAADD7667E3F5L, 0x7ABCFF62938BEB96L, + 0xA78DAD948FC179C9L, 0x8F1F98B72911E50DL, + 0x61E48EAE27121A91L, 0x4D62F7AD31859808L, + 0xECEBA345EF5CEAEBL, 0xF5CEB25EBC9684CEL, + 0xF633E20CB7F76221L, 0xA32CDF06AB8293E4L, + 0x985A202CA5EE2CA4L, 0xCF0B8447CC8A8FB1L, + 0x9F765244979859A3L, 0xA8D516B1A1240017L, + 0x0BD7BA3EBB5DC726L, 0xE54BCA55B86ADB39L, + 0x1D7A3AFD6C478063L, 0x519EC608E7669EDDL, + 0x0E5715A2D149AA23L, 0x177D4571848FF194L, + 0xEEB55F3241014C22L, 0x0F5E5CA13A6E2EC2L, + 0x8029927B75F5C361L, 0xAD139FABC3D6E436L, + 0x0D5DF1A94CCF402FL, 0x3E8BD948BEA5DFC8L, + 0xA5A0D357BD3FF77EL, 0xA2D12E251F74F645L, + 0x66FD9E525E81A082L, 0x2E0C90CE7F687A49L, + 0xC2E8BCBEBA973BC5L, 0x000001BCE509745FL, + 0x423777BBE6DAB3D6L, 0xD1661C7EAEF06EB5L, + 0xA1781F354DAACFD8L, 0x2D11284A2B16AFFCL, + 0xF1FC4F67FA891D1FL, 0x73ECC25DCB920ADAL, + 0xAE610C22C2A12651L, 0x96E0A810D356B78AL, + 0x5A9A381F2FE7870FL, 0xD5AD62EDE94E5530L, + 0xD225E5E8368D1427L, 0x65977B70C7AF4631L, + 0x99F889B2DE39D74FL, 0x233F30BF54E1D143L, + 0x9A9675D3D9A63C97L, 0x5470554FF334F9A8L, + 0x166ACB744A4F5688L, 0x70C74CAAB2E4AEADL, + 0xF0D091646F294D12L, 0x57B82A89684031D1L, + 0xEFD95A5A61BE0B6BL, 0x2FBD12E969F2F29AL, + 0x9BD37013FEFF9FE8L, 0x3F9B0404D6085A06L, + 0x4940C1F3166CFE15L, 0x09542C4DCDF3DEFBL, + 0xB4C5218385CD5CE3L, 0xC935B7DC4462A641L, + 0x3417F8A68ED3B63FL, 0xB80959295B215B40L, + 0xF99CDAEF3B8C8572L, 0x018C0614F8FCB95DL, + 0x1B14ACCD1A3ACDF3L, 0x84D471F200BB732DL, + 0xC1A3110E95E8DA16L, 0x430A7220BF1A82B8L, + 0xB77E090D39DF210EL, 0x5EF4BD9F3CD05E9DL, + 0x9D4FF6DA7E57A444L, 0xDA1D60E183D4A5F8L, + 0xB287C38417998E47L, 0xFE3EDC121BB31886L, + 0xC7FE3CCC980CCBEFL, 0xE46FB590189BFD03L, + 0x3732FD469A4C57DCL, 0x7EF700A07CF1AD65L, + 0x59C64468A31D8859L, 0x762FB0B4D45B61F6L, + 0x155BAED099047718L, 0x68755E4C3D50BAA6L, + 0xE9214E7F22D8B4DFL, 0x2ADDBF532EAC95F4L, + 0x32AE3909B4BD0109L, 0x834DF537B08E3450L, + 0xFA209DA84220728DL, 0x9E691D9B9EFE23F7L, + 0x0446D288C4AE8D7FL, 0x7B4CC524E169785BL, + 0x21D87F0135CA1385L, 0xCEBB400F137B8AA5L, + 0x272E2B66580796BEL, 0x3612264125C2B0DEL, + 0x057702BDAD1EFBB2L, 0xD4BABB8EACF84BE9L, + 0x91583139641BC67BL, 0x8BDC2DE08036E024L, + 0x603C8156F49F68EDL, 0xF7D236F7DBEF5111L, + 0x9727C4598AD21E80L, 0xA08A0896670A5FD7L, + 0xCB4A8F4309EBA9CBL, 0x81AF564B0F7036A1L, + 0xC0B99AA778199ABDL, 0x959F1EC83FC8E952L, + 0x8C505077794A81B9L, 0x3ACAAF8F056338F0L, + 0x07B43F50627A6778L, 0x4A44AB49F5ECCC77L, + 0x3BC3D6E4B679EE98L, 0x9CC0D4D1CF14108CL, + 0x4406C00B206BC8A0L, 0x82A18854C8D72D89L, + 0x67E366B35C3C432CL, 0xB923DD61102B37F2L, + 0x56AB2779D884271DL, 0xBE83E1B0FF1525AFL, + 0xFB7C65D4217E49A9L, 0x6BDBE0E76D48E7D4L, + 0x08DF828745D9179EL, 0x22EA6A9ADD53BD34L, + 0xE36E141C5622200AL, 0x7F805D1B8CB750EEL, + 0xAFE5C7A59F58E837L, 0xE27F996A4FB1C23CL, + 0xD3867DFB0775F0D0L, 0xD0E673DE6E88891AL, + 0x123AEB9EAFB86C25L, 0x30F1D5D5C145B895L, + 0xBB434A2DEE7269E7L, 0x78CB67ECF931FA38L, + 0xF33B0372323BBF9CL, 0x52D66336FB279C74L, + 0x505F33AC0AFB4EAAL, 0xE8A5CD99A2CCE187L, + 0x534974801E2D30BBL, 0x8D2D5711D5876D90L, + 0x1F1A412891BC038EL, 0xD6E2E71D82E56648L, + 0x74036C3A497732B7L, 0x89B67ED96361F5ABL, + 0xFFED95D8F1EA02A2L, 0xE72B3BD61464D43DL, + 0xA6300F170BDC4820L, 0xEBC18760ED78A77AL }; + + /** S-Box T2. */ + private static final long[] T2 = { 0xE6A6BE5A05A12138L, 0xB5A122A5B4F87C98L, + 0x563C6089140B6990L, 0x4C46CB2E391F5DD5L, + 0xD932ADDBC9B79434L, 0x08EA70E42015AFF5L, + 0xD765A6673E478CF1L, 0xC4FB757EAB278D99L, + 0xDF11C6862D6E0692L, 0xDDEB84F10D7F3B16L, + 0x6F2EF604A665EA04L, 0x4A8E0F0FF0E0DFB3L, + 0xA5EDEEF83DBCBA51L, 0xFC4F0A2A0EA4371EL, + 0xE83E1DA85CB38429L, 0xDC8FF882BA1B1CE2L, + 0xCD45505E8353E80DL, 0x18D19A00D4DB0717L, + 0x34A0CFEDA5F38101L, 0x0BE77E518887CAF2L, + 0x1E341438B3C45136L, 0xE05797F49089CCF9L, + 0xFFD23F9DF2591D14L, 0x543DDA228595C5CDL, + 0x661F81FD99052A33L, 0x8736E641DB0F7B76L, + 0x15227725418E5307L, 0xE25F7F46162EB2FAL, + 0x48A8B2126C13D9FEL, 0xAFDC541792E76EEAL, + 0x03D912BFC6D1898FL, 0x31B1AAFA1B83F51BL, + 0xF1AC2796E42AB7D9L, 0x40A3A7D7FCD2EBACL, + 0x1056136D0AFBBCC5L, 0x7889E1DD9A6D0C85L, + 0xD33525782A7974AAL, 0xA7E25D09078AC09BL, + 0xBD4138B3EAC6EDD0L, 0x920ABFBE71EB9E70L, + 0xA2A5D0F54FC2625CL, 0xC054E36B0B1290A3L, + 0xF6DD59FF62FE932BL, 0x3537354511A8AC7DL, + 0xCA845E9172FADCD4L, 0x84F82B60329D20DCL, + 0x79C62CE1CD672F18L, 0x8B09A2ADD124642CL, + 0xD0C1E96A19D9E726L, 0x5A786A9B4BA9500CL, + 0x0E020336634C43F3L, 0xC17B474AEB66D822L, + 0x6A731AE3EC9BAAC2L, 0x8226667AE0840258L, + 0x67D4567691CAECA5L, 0x1D94155C4875ADB5L, + 0x6D00FD985B813FDFL, 0x51286EFCB774CD06L, + 0x5E8834471FA744AFL, 0xF72CA0AEE761AE2EL, + 0xBE40E4CDAEE8E09AL, 0xE9970BBB5118F665L, + 0x726E4BEB33DF1964L, 0x703B000729199762L, + 0x4631D816F5EF30A7L, 0xB880B5B51504A6BEL, + 0x641793C37ED84B6CL, 0x7B21ED77F6E97D96L, + 0x776306312EF96B73L, 0xAE528948E86FF3F4L, + 0x53DBD7F286A3F8F8L, 0x16CADCE74CFC1063L, + 0x005C19BDFA52C6DDL, 0x68868F5D64D46AD3L, + 0x3A9D512CCF1E186AL, 0x367E62C2385660AEL, + 0xE359E7EA77DCB1D7L, 0x526C0773749ABE6EL, + 0x735AE5F9D09F734BL, 0x493FC7CC8A558BA8L, + 0xB0B9C1533041AB45L, 0x321958BA470A59BDL, + 0x852DB00B5F46C393L, 0x91209B2BD336B0E5L, + 0x6E604F7D659EF19FL, 0xB99A8AE2782CCB24L, + 0xCCF52AB6C814C4C7L, 0x4727D9AFBE11727BL, + 0x7E950D0C0121B34DL, 0x756F435670AD471FL, + 0xF5ADD442615A6849L, 0x4E87E09980B9957AL, + 0x2ACFA1DF50AEE355L, 0xD898263AFD2FD556L, + 0xC8F4924DD80C8FD6L, 0xCF99CA3D754A173AL, + 0xFE477BACAF91BF3CL, 0xED5371F6D690C12DL, + 0x831A5C285E687094L, 0xC5D3C90A3708A0A4L, + 0x0F7F903717D06580L, 0x19F9BB13B8FDF27FL, + 0xB1BD6F1B4D502843L, 0x1C761BA38FFF4012L, + 0x0D1530C4E2E21F3BL, 0x8943CE69A7372C8AL, + 0xE5184E11FEB5CE66L, 0x618BDB80BD736621L, + 0x7D29BAD68B574D0BL, 0x81BB613E25E6FE5BL, + 0x071C9C10BC07913FL, 0xC7BEEB7909AC2D97L, + 0xC3E58D353BC5D757L, 0xEB017892F38F61E8L, + 0xD4EFFB9C9B1CC21AL, 0x99727D26F494F7ABL, + 0xA3E063A2956B3E03L, 0x9D4A8B9A4AA09C30L, + 0x3F6AB7D500090FB4L, 0x9CC0F2A057268AC0L, + 0x3DEE9D2DEDBF42D1L, 0x330F49C87960A972L, + 0xC6B2720287421B41L, 0x0AC59EC07C00369CL, + 0xEF4EAC49CB353425L, 0xF450244EEF0129D8L, + 0x8ACC46E5CAF4DEB6L, 0x2FFEAB63989263F7L, + 0x8F7CB9FE5D7A4578L, 0x5BD8F7644E634635L, + 0x427A7315BF2DC900L, 0x17D0C4AA2125261CL, + 0x3992486C93518E50L, 0xB4CBFEE0A2D7D4C3L, + 0x7C75D6202C5DDD8DL, 0xDBC295D8E35B6C61L, + 0x60B369D302032B19L, 0xCE42685FDCE44132L, + 0x06F3DDB9DDF65610L, 0x8EA4D21DB5E148F0L, + 0x20B0FCE62FCD496FL, 0x2C1B912358B0EE31L, + 0xB28317B818F5A308L, 0xA89C1E189CA6D2CFL, + 0x0C6B18576AAADBC8L, 0xB65DEAA91299FAE3L, + 0xFB2B794B7F1027E7L, 0x04E4317F443B5BEBL, + 0x4B852D325939D0A6L, 0xD5AE6BEEFB207FFCL, + 0x309682B281C7D374L, 0xBAE309A194C3B475L, + 0x8CC3F97B13B49F05L, 0x98A9422FF8293967L, + 0x244B16B01076FF7CL, 0xF8BF571C663D67EEL, + 0x1F0D6758EEE30DA1L, 0xC9B611D97ADEB9B7L, + 0xB7AFD5887B6C57A2L, 0x6290AE846B984FE1L, + 0x94DF4CDEACC1A5FDL, 0x058A5BD1C5483AFFL, + 0x63166CC142BA3C37L, 0x8DB8526EB2F76F40L, + 0xE10880036F0D6D4EL, 0x9E0523C9971D311DL, + 0x45EC2824CC7CD691L, 0x575B8359E62382C9L, + 0xFA9E400DC4889995L, 0xD1823ECB45721568L, + 0xDAFD983B8206082FL, 0xAA7D29082386A8CBL, + 0x269FCD4403B87588L, 0x1B91F5F728BDD1E0L, + 0xE4669F39040201F6L, 0x7A1D7C218CF04ADEL, + 0x65623C29D79CE5CEL, 0x2368449096C00BB1L, + 0xAB9BF1879DA503BAL, 0xBC23ECB1A458058EL, + 0x9A58DF01BB401ECCL, 0xA070E868A85F143DL, + 0x4FF188307DF2239EL, 0x14D565B41A641183L, + 0xEE13337452701602L, 0x950E3DCF3F285E09L, + 0x59930254B9C80953L, 0x3BF299408930DA6DL, + 0xA955943F53691387L, 0xA15EDECAA9CB8784L, + 0x29142127352BE9A0L, 0x76F0371FFF4E7AFBL, + 0x0239F450274F2228L, 0xBB073AF01D5E868BL, + 0xBFC80571C10E96C1L, 0xD267088568222E23L, + 0x9671A3D48E80B5B0L, 0x55B5D38AE193BB81L, + 0x693AE2D0A18B04B8L, 0x5C48B4ECADD5335FL, + 0xFD743B194916A1CAL, 0x2577018134BE98C4L, + 0xE77987E83C54A4ADL, 0x28E11014DA33E1B9L, + 0x270CC59E226AA213L, 0x71495F756D1A5F60L, + 0x9BE853FB60AFEF77L, 0xADC786A7F7443DBFL, + 0x0904456173B29A82L, 0x58BC7A66C232BD5EL, + 0xF306558C673AC8B2L, 0x41F639C6B6C9772AL, + 0x216DEFE99FDA35DAL, 0x11640CC71C7BE615L, + 0x93C43694565C5527L, 0xEA038E6246777839L, + 0xF9ABF3CE5A3E2469L, 0x741E768D0FD312D2L, + 0x0144B883CED652C6L, 0xC20B5A5BA33F8552L, + 0x1AE69633C3435A9DL, 0x97A28CA4088CFDECL, + 0x8824A43C1E96F420L, 0x37612FA66EEEA746L, + 0x6B4CB165F9CF0E5AL, 0x43AA1C06A0ABFB4AL, + 0x7F4DC26FF162796BL, 0x6CBACC8E54ED9B0FL, + 0xA6B7FFEFD2BB253EL, 0x2E25BC95B0A29D4FL, + 0x86D6A58BDEF1388CL, 0xDED74AC576B6F054L, + 0x8030BDBC2B45805DL, 0x3C81AF70E94D9289L, + 0x3EFF6DDA9E3100DBL, 0xB38DC39FDFCC8847L, + 0x123885528D17B87EL, 0xF2DA0ED240B1B642L, + 0x44CEFADCD54BF9A9L, 0x1312200E433C7EE6L, + 0x9FFCC84F3A78C748L, 0xF0CD1F72248576BBL, + 0xEC6974053638CFE4L, 0x2BA7B67C0CEC4E4CL, + 0xAC2F4DF3E5CE32EDL, 0xCB33D14326EA4C11L, + 0xA4E9044CC77E58BCL, 0x5F513293D934FCEFL, + 0x5DC9645506E55444L, 0x50DE418F317DE40AL, + 0x388CB31A69DDE259L, 0x2DB4A83455820A86L, + 0x9010A91E84711AE9L, 0x4DF7F0B7B1498371L, + 0xD62A2EABC0977179L, 0x22FAC097AA8D5C0EL }; + + /** S-Box T3. */ + private static final long[] T3 = { 0xF49FCC2FF1DAF39BL, 0x487FD5C66FF29281L, + 0xE8A30667FCDCA83FL, 0x2C9B4BE3D2FCCE63L, + 0xDA3FF74B93FBBBC2L, 0x2FA165D2FE70BA66L, + 0xA103E279970E93D4L, 0xBECDEC77B0E45E71L, + 0xCFB41E723985E497L, 0xB70AAA025EF75017L, + 0xD42309F03840B8E0L, 0x8EFC1AD035898579L, + 0x96C6920BE2B2ABC5L, 0x66AF4163375A9172L, + 0x2174ABDCCA7127FBL, 0xB33CCEA64A72FF41L, + 0xF04A4933083066A5L, 0x8D970ACDD7289AF5L, + 0x8F96E8E031C8C25EL, 0xF3FEC02276875D47L, + 0xEC7BF310056190DDL, 0xF5ADB0AEBB0F1491L, + 0x9B50F8850FD58892L, 0x4975488358B74DE8L, + 0xA3354FF691531C61L, 0x0702BBE481D2C6EEL, + 0x89FB24057DEDED98L, 0xAC3075138596E902L, + 0x1D2D3580172772EDL, 0xEB738FC28E6BC30DL, + 0x5854EF8F63044326L, 0x9E5C52325ADD3BBEL, + 0x90AA53CF325C4623L, 0xC1D24D51349DD067L, + 0x2051CFEEA69EA624L, 0x13220F0A862E7E4FL, + 0xCE39399404E04864L, 0xD9C42CA47086FCB7L, + 0x685AD2238A03E7CCL, 0x066484B2AB2FF1DBL, + 0xFE9D5D70EFBF79ECL, 0x5B13B9DD9C481854L, + 0x15F0D475ED1509ADL, 0x0BEBCD060EC79851L, + 0xD58C6791183AB7F8L, 0xD1187C5052F3EEE4L, + 0xC95D1192E54E82FFL, 0x86EEA14CB9AC6CA2L, + 0x3485BEB153677D5DL, 0xDD191D781F8C492AL, + 0xF60866BAA784EBF9L, 0x518F643BA2D08C74L, + 0x8852E956E1087C22L, 0xA768CB8DC410AE8DL, + 0x38047726BFEC8E1AL, 0xA67738B4CD3B45AAL, + 0xAD16691CEC0DDE19L, 0xC6D4319380462E07L, + 0xC5A5876D0BA61938L, 0x16B9FA1FA58FD840L, + 0x188AB1173CA74F18L, 0xABDA2F98C99C021FL, + 0x3E0580AB134AE816L, 0x5F3B05B773645ABBL, + 0x2501A2BE5575F2F6L, 0x1B2F74004E7E8BA9L, + 0x1CD7580371E8D953L, 0x7F6ED89562764E30L, + 0xB15926FF596F003DL, 0x9F65293DA8C5D6B9L, + 0x6ECEF04DD690F84CL, 0x4782275FFF33AF88L, + 0xE41433083F820801L, 0xFD0DFE409A1AF9B5L, + 0x4325A3342CDB396BL, 0x8AE77E62B301B252L, + 0xC36F9E9F6655615AL, 0x85455A2D92D32C09L, + 0xF2C7DEA949477485L, 0x63CFB4C133A39EBAL, + 0x83B040CC6EBC5462L, 0x3B9454C8FDB326B0L, + 0x56F56A9E87FFD78CL, 0x2DC2940D99F42BC6L, + 0x98F7DF096B096E2DL, 0x19A6E01E3AD852BFL, + 0x42A99CCBDBD4B40BL, 0xA59998AF45E9C559L, + 0x366295E807D93186L, 0x6B48181BFAA1F773L, + 0x1FEC57E2157A0A1DL, 0x4667446AF6201AD5L, + 0xE615EBCACFB0F075L, 0xB8F31F4F68290778L, + 0x22713ED6CE22D11EL, 0x3057C1A72EC3C93BL, + 0xCB46ACC37C3F1F2FL, 0xDBB893FD02AAF50EL, + 0x331FD92E600B9FCFL, 0xA498F96148EA3AD6L, + 0xA8D8426E8B6A83EAL, 0xA089B274B7735CDCL, + 0x87F6B3731E524A11L, 0x118808E5CBC96749L, + 0x9906E4C7B19BD394L, 0xAFED7F7E9B24A20CL, + 0x6509EADEEB3644A7L, 0x6C1EF1D3E8EF0EDEL, + 0xB9C97D43E9798FB4L, 0xA2F2D784740C28A3L, + 0x7B8496476197566FL, 0x7A5BE3E6B65F069DL, + 0xF96330ED78BE6F10L, 0xEEE60DE77A076A15L, + 0x2B4BEE4AA08B9BD0L, 0x6A56A63EC7B8894EL, + 0x02121359BA34FEF4L, 0x4CBF99F8283703FCL, + 0x398071350CAF30C8L, 0xD0A77A89F017687AL, + 0xF1C1A9EB9E423569L, 0x8C7976282DEE8199L, + 0x5D1737A5DD1F7ABDL, 0x4F53433C09A9FA80L, + 0xFA8B0C53DF7CA1D9L, 0x3FD9DCBC886CCB77L, + 0xC040917CA91B4720L, 0x7DD00142F9D1DCDFL, + 0x8476FC1D4F387B58L, 0x23F8E7C5F3316503L, + 0x032A2244E7E37339L, 0x5C87A5D750F5A74BL, + 0x082B4CC43698992EL, 0xDF917BECB858F63CL, + 0x3270B8FC5BF86DDAL, 0x10AE72BB29B5DD76L, + 0x576AC94E7700362BL, 0x1AD112DAC61EFB8FL, + 0x691BC30EC5FAA427L, 0xFF246311CC327143L, + 0x3142368E30E53206L, 0x71380E31E02CA396L, + 0x958D5C960AAD76F1L, 0xF8D6F430C16DA536L, + 0xC8FFD13F1BE7E1D2L, 0x7578AE66004DDBE1L, + 0x05833F01067BE646L, 0xBB34B5AD3BFE586DL, + 0x095F34C9A12B97F0L, 0x247AB64525D60CA8L, + 0xDCDBC6F3017477D1L, 0x4A2E14D4DECAD24DL, + 0xBDB5E6D9BE0A1EEBL, 0x2A7E70F7794301ABL, + 0xDEF42D8A270540FDL, 0x01078EC0A34C22C1L, + 0xE5DE511AF4C16387L, 0x7EBB3A52BD9A330AL, + 0x77697857AA7D6435L, 0x004E831603AE4C32L, + 0xE7A21020AD78E312L, 0x9D41A70C6AB420F2L, + 0x28E06C18EA1141E6L, 0xD2B28CBD984F6B28L, + 0x26B75F6C446E9D83L, 0xBA47568C4D418D7FL, + 0xD80BADBFE6183D8EL, 0x0E206D7F5F166044L, + 0xE258A43911CBCA3EL, 0x723A1746B21DC0BCL, + 0xC7CAA854F5D7CDD3L, 0x7CAC32883D261D9CL, + 0x7690C26423BA942CL, 0x17E55524478042B8L, + 0xE0BE477656A2389FL, 0x4D289B5E67AB2DA0L, + 0x44862B9C8FBBFD31L, 0xB47CC8049D141365L, + 0x822C1B362B91C793L, 0x4EB14655FB13DFD8L, + 0x1ECBBA0714E2A97BL, 0x6143459D5CDE5F14L, + 0x53A8FBF1D5F0AC89L, 0x97EA04D81C5E5B00L, + 0x622181A8D4FDB3F3L, 0xE9BCD341572A1208L, + 0x1411258643CCE58AL, 0x9144C5FEA4C6E0A4L, + 0x0D33D06565CF620FL, 0x54A48D489F219CA1L, + 0xC43E5EAC6D63C821L, 0xA9728B3A72770DAFL, + 0xD7934E7B20DF87EFL, 0xE35503B61A3E86E5L, + 0xCAE321FBC819D504L, 0x129A50B3AC60BFA6L, + 0xCD5E68EA7E9FB6C3L, 0xB01C90199483B1C7L, + 0x3DE93CD5C295376CL, 0xAED52EDF2AB9AD13L, + 0x2E60F512C0A07884L, 0xBC3D86A3E36210C9L, + 0x35269D9B163951CEL, 0x0C7D6E2AD0CDB5FAL, + 0x59E86297D87F5733L, 0x298EF221898DB0E7L, + 0x55000029D1A5AA7EL, 0x8BC08AE1B5061B45L, + 0xC2C31C2B6C92703AL, 0x94CC596BAF25EF42L, + 0x0A1D73DB22540456L, 0x04B6A0F9D9C4179AL, + 0xEFFDAFA2AE3D3C60L, 0xF7C8075BB49496C4L, + 0x9CC5C7141D1CD4E3L, 0x78BD1638218E5534L, + 0xB2F11568F850246AL, 0xEDFABCFA9502BC29L, + 0x796CE5F2DA23051BL, 0xAAE128B0DC93537CL, + 0x3A493DA0EE4B29AEL, 0xB5DF6B2C416895D7L, + 0xFCABBD25122D7F37L, 0x70810B58105DC4B1L, + 0xE10FDD37F7882A90L, 0x524DCAB5518A3F5CL, + 0x3C9E85878451255BL, 0x4029828119BD34E2L, + 0x74A05B6F5D3CECCBL, 0xB610021542E13ECAL, + 0x0FF979D12F59E2ACL, 0x6037DA27E4F9CC50L, + 0x5E92975A0DF1847DL, 0xD66DE190D3E623FEL, + 0x5032D6B87B568048L, 0x9A36B7CE8235216EL, + 0x80272A7A24F64B4AL, 0x93EFED8B8C6916F7L, + 0x37DDBFF44CCE1555L, 0x4B95DB5D4B99BD25L, + 0x92D3FDA169812FC0L, 0xFB1A4A9A90660BB6L, + 0x730C196946A4B9B2L, 0x81E289AA7F49DA68L, + 0x64669A0F83B1A05FL, 0x27B3FF7D9644F48BL, + 0xCC6B615C8DB675B3L, 0x674F20B9BCEBBE95L, + 0x6F31238275655982L, 0x5AE488713E45CF05L, + 0xBF619F9954C21157L, 0xEABAC46040A8EAE9L, + 0x454C6FE9F2C0C1CDL, 0x419CF6496412691CL, + 0xD3DC3BEF265B0F70L, 0x6D0E60F5C3578A9EL }; + + /** S-Box T4. */ + private static final long[] T4 = { 0x5B0E608526323C55L, 0x1A46C1A9FA1B59F5L, + 0xA9E245A17C4C8FFAL, 0x65CA5159DB2955D7L, + 0x05DB0A76CE35AFC2L, 0x81EAC77EA9113D45L, + 0x528EF88AB6AC0A0DL, 0xA09EA253597BE3FFL, + 0x430DDFB3AC48CD56L, 0xC4B3A67AF45CE46FL, + 0x4ECECFD8FBE2D05EL, 0x3EF56F10B39935F0L, + 0x0B22D6829CD619C6L, 0x17FD460A74DF2069L, + 0x6CF8CC8E8510ED40L, 0xD6C824BF3A6ECAA7L, + 0x61243D581A817049L, 0x048BACB6BBC163A2L, + 0xD9A38AC27D44CC32L, 0x7FDDFF5BAAF410ABL, + 0xAD6D495AA804824BL, 0xE1A6A74F2D8C9F94L, + 0xD4F7851235DEE8E3L, 0xFD4B7F886540D893L, + 0x247C20042AA4BFDAL, 0x096EA1C517D1327CL, + 0xD56966B4361A6685L, 0x277DA5C31221057DL, + 0x94D59893A43ACFF7L, 0x64F0C51CCDC02281L, + 0x3D33BCC4FF6189DBL, 0xE005CB184CE66AF1L, + 0xFF5CCD1D1DB99BEAL, 0xB0B854A7FE42980FL, + 0x7BD46A6A718D4B9FL, 0xD10FA8CC22A5FD8CL, + 0xD31484952BE4BD31L, 0xC7FA975FCB243847L, + 0x4886ED1E5846C407L, 0x28CDDB791EB70B04L, + 0xC2B00BE2F573417FL, 0x5C9590452180F877L, + 0x7A6BDDFFF370EB00L, 0xCE509E38D6D9D6A4L, + 0xEBEB0F00647FA702L, 0x1DCC06CF76606F06L, + 0xE4D9F28BA286FF0AL, 0xD85A305DC918C262L, + 0x475B1D8732225F54L, 0x2D4FB51668CCB5FEL, + 0xA679B9D9D72BBA20L, 0x53841C0D912D43A5L, + 0x3B7EAA48BF12A4E8L, 0x781E0E47F22F1DDFL, + 0xEFF20CE60AB50973L, 0x20D261D19DFFB742L, + 0x16A12B03062A2E39L, 0x1960EB2239650495L, + 0x251C16FED50EB8B8L, 0x9AC0C330F826016EL, + 0xED152665953E7671L, 0x02D63194A6369570L, + 0x5074F08394B1C987L, 0x70BA598C90B25CE1L, + 0x794A15810B9742F6L, 0x0D5925E9FCAF8C6CL, + 0x3067716CD868744EL, 0x910AB077E8D7731BL, + 0x6A61BBDB5AC42F61L, 0x93513EFBF0851567L, + 0xF494724B9E83E9D5L, 0xE887E1985C09648DL, + 0x34B1D3C675370CFDL, 0xDC35E433BC0D255DL, + 0xD0AAB84234131BE0L, 0x08042A50B48B7EAFL, + 0x9997C4EE44A3AB35L, 0x829A7B49201799D0L, + 0x263B8307B7C54441L, 0x752F95F4FD6A6CA6L, + 0x927217402C08C6E5L, 0x2A8AB754A795D9EEL, + 0xA442F7552F72943DL, 0x2C31334E19781208L, + 0x4FA98D7CEAEE6291L, 0x55C3862F665DB309L, + 0xBD0610175D53B1F3L, 0x46FE6CB840413F27L, + 0x3FE03792DF0CFA59L, 0xCFE700372EB85E8FL, + 0xA7BE29E7ADBCE118L, 0xE544EE5CDE8431DDL, + 0x8A781B1B41F1873EL, 0xA5C94C78A0D2F0E7L, + 0x39412E2877B60728L, 0xA1265EF3AFC9A62CL, + 0xBCC2770C6A2506C5L, 0x3AB66DD5DCE1CE12L, + 0xE65499D04A675B37L, 0x7D8F523481BFD216L, + 0x0F6F64FCEC15F389L, 0x74EFBE618B5B13C8L, + 0xACDC82B714273E1DL, 0xDD40BFE003199D17L, + 0x37E99257E7E061F8L, 0xFA52626904775AAAL, + 0x8BBBF63A463D56F9L, 0xF0013F1543A26E64L, + 0xA8307E9F879EC898L, 0xCC4C27A4150177CCL, + 0x1B432F2CCA1D3348L, 0xDE1D1F8F9F6FA013L, + 0x606602A047A7DDD6L, 0xD237AB64CC1CB2C7L, + 0x9B938E7225FCD1D3L, 0xEC4E03708E0FF476L, + 0xFEB2FBDA3D03C12DL, 0xAE0BCED2EE43889AL, + 0x22CB8923EBFB4F43L, 0x69360D013CF7396DL, + 0x855E3602D2D4E022L, 0x073805BAD01F784CL, + 0x33E17A133852F546L, 0xDF4874058AC7B638L, + 0xBA92B29C678AA14AL, 0x0CE89FC76CFAADCDL, + 0x5F9D4E0908339E34L, 0xF1AFE9291F5923B9L, + 0x6E3480F60F4A265FL, 0xEEBF3A2AB29B841CL, + 0xE21938A88F91B4ADL, 0x57DFEFF845C6D3C3L, + 0x2F006B0BF62CAAF2L, 0x62F479EF6F75EE78L, + 0x11A55AD41C8916A9L, 0xF229D29084FED453L, + 0x42F1C27B16B000E6L, 0x2B1F76749823C074L, + 0x4B76ECA3C2745360L, 0x8C98F463B91691BDL, + 0x14BCC93CF1ADE66AL, 0x8885213E6D458397L, + 0x8E177DF0274D4711L, 0xB49B73B5503F2951L, + 0x10168168C3F96B6BL, 0x0E3D963B63CAB0AEL, + 0x8DFC4B5655A1DB14L, 0xF789F1356E14DE5CL, + 0x683E68AF4E51DAC1L, 0xC9A84F9D8D4B0FD9L, + 0x3691E03F52A0F9D1L, 0x5ED86E46E1878E80L, + 0x3C711A0E99D07150L, 0x5A0865B20C4E9310L, + 0x56FBFC1FE4F0682EL, 0xEA8D5DE3105EDF9BL, + 0x71ABFDB12379187AL, 0x2EB99DE1BEE77B9CL, + 0x21ECC0EA33CF4523L, 0x59A4D7521805C7A1L, + 0x3896F5EB56AE7C72L, 0xAA638F3DB18F75DCL, + 0x9F39358DABE9808EL, 0xB7DEFA91C00B72ACL, + 0x6B5541FD62492D92L, 0x6DC6DEE8F92E4D5BL, + 0x353F57ABC4BEEA7EL, 0x735769D6DA5690CEL, + 0x0A234AA642391484L, 0xF6F9508028F80D9DL, + 0xB8E319A27AB3F215L, 0x31AD9C1151341A4DL, + 0x773C22A57BEF5805L, 0x45C7561A07968633L, + 0xF913DA9E249DBE36L, 0xDA652D9B78A64C68L, + 0x4C27A97F3BC334EFL, 0x76621220E66B17F4L, + 0x967743899ACD7D0BL, 0xF3EE5BCAE0ED6782L, + 0x409F753600C879FCL, 0x06D09A39B5926DB6L, + 0x6F83AEB0317AC588L, 0x01E6CA4A86381F21L, + 0x66FF3462D19F3025L, 0x72207C24DDFD3BFBL, + 0x4AF6B6D3E2ECE2EBL, 0x9C994DBEC7EA08DEL, + 0x49ACE597B09A8BC4L, 0xB38C4766CF0797BAL, + 0x131B9373C57C2A75L, 0xB1822CCE61931E58L, + 0x9D7555B909BA1C0CL, 0x127FAFDD937D11D2L, + 0x29DA3BADC66D92E4L, 0xA2C1D57154C2ECBCL, + 0x58C5134D82F6FE24L, 0x1C3AE3515B62274FL, + 0xE907C82E01CB8126L, 0xF8ED091913E37FCBL, + 0x3249D8F9C80046C9L, 0x80CF9BEDE388FB63L, + 0x1881539A116CF19EL, 0x5103F3F76BD52457L, + 0x15B7E6F5AE47F7A8L, 0xDBD7C6DED47E9CCFL, + 0x44E55C410228BB1AL, 0xB647D4255EDB4E99L, + 0x5D11882BB8AAFC30L, 0xF5098BBB29D3212AL, + 0x8FB5EA14E90296B3L, 0x677B942157DD025AL, + 0xFB58E7C0A390ACB5L, 0x89D3674C83BD4A01L, + 0x9E2DA4DF4BF3B93BL, 0xFCC41E328CAB4829L, + 0x03F38C96BA582C52L, 0xCAD1BDBD7FD85DB2L, + 0xBBB442C16082AE83L, 0xB95FE86BA5DA9AB0L, + 0xB22E04673771A93FL, 0x845358C9493152D8L, + 0xBE2A488697B4541EL, 0x95A2DC2DD38E6966L, + 0xC02C11AC923C852BL, 0x2388B1990DF2A87BL, + 0x7C8008FA1B4F37BEL, 0x1F70D0C84D54E503L, + 0x5490ADEC7ECE57D4L, 0x002B3C27D9063A3AL, + 0x7EAEA3848030A2BFL, 0xC602326DED2003C0L, + 0x83A7287D69A94086L, 0xC57A5FCB30F57A8AL, + 0xB56844E479EBE779L, 0xA373B40F05DCBCE9L, + 0xD71A786E88570EE2L, 0x879CBACDBDE8F6A0L, + 0x976AD1BCC164A32FL, 0xAB21E25E9666D78BL, + 0x901063AAE5E5C33CL, 0x9818B34448698D90L, + 0xE36487AE3E1E8ABBL, 0xAFBDF931893BDCB4L, + 0x6345A0DC5FBBD519L, 0x8628FE269B9465CAL, + 0x1E5D01603F9C51ECL, 0x4DE44006A15049B7L, + 0xBF6C70E5F776CBB1L, 0x411218F2EF552BEDL, + 0xCB0C0708705A36A3L, 0xE74D14754F986044L, + 0xCD56D9430EA8280EL, 0xC12591D7535F5065L, + 0xC83223F1720AEF96L, 0xC3A0396F7363A51FL }; + + // The cached self-test result. + private static Boolean valid; + + // The context. + private long a, b, c; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * Trivial 0-arguments constructor. + */ + public Tiger() + { + super(Registry.TIGER_HASH, HASH_SIZE, BLOCK_SIZE); + } + + /** + * Private copying constructor for cloning. + * + * @param that The instance being cloned. + */ + private Tiger(Tiger that) + { + this(); + this.a = that.a; + this.b = that.b; + this.c = that.c; + this.count = that.count; + this.buffer = (that.buffer != null) ? (byte[]) that.buffer.clone() : null; + } + + // Instance methods implementing BaseHash. + // ----------------------------------------------------------------------- + + public Object clone() + { + return new Tiger(this); + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean(DIGEST0.equals(Util.toString(new Tiger().digest()))); + } + return valid.booleanValue(); + } + + protected byte[] padBuffer() + { + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] pad = new byte[padding + 8]; + + pad[0] = 1; + long bits = count << 3; + + pad[padding++] = (byte) bits; + pad[padding++] = (byte) (bits >>> 8); + pad[padding++] = (byte) (bits >>> 16); + pad[padding++] = (byte) (bits >>> 24); + pad[padding++] = (byte) (bits >>> 32); + pad[padding++] = (byte) (bits >>> 40); + pad[padding++] = (byte) (bits >>> 48); + pad[padding] = (byte) (bits >>> 56); + + return pad; + } + + protected byte[] getResult() + { + return new byte[] { (byte) a, (byte) (a >>> 8), (byte) (a >>> 16), + (byte) (a >>> 24), (byte) (a >>> 32), (byte) (a >>> 40), + (byte) (a >>> 48), (byte) (a >>> 56), (byte) b, + (byte) (b >>> 8), (byte) (b >>> 16), (byte) (b >>> 24), + (byte) (b >>> 32), (byte) (b >>> 40), (byte) (b >>> 48), + (byte) (b >>> 56), (byte) c, (byte) (c >>> 8), + (byte) (c >>> 16), (byte) (c >>> 24), (byte) (c >>> 32), + (byte) (c >>> 40), (byte) (c >>> 48), (byte) (c >>> 56) }; + } + + protected void resetContext() + { + a = A; + b = B; + c = C; + } + + protected void transform(byte[] in, int offset) + { + long x0, x1, x2, x3, x4, x5, x6, x7; + + x0 = ((long) in[offset++] & 0xFF) | ((long) (in[offset++] & 0xFF) << 8) + | ((long) (in[offset++] & 0xFF) << 16) + | ((long) (in[offset++] & 0xFF) << 24) + | ((long) (in[offset++] & 0xFF) << 32) + | ((long) (in[offset++] & 0xFF) << 40) + | ((long) (in[offset++] & 0xFF) << 48) + | ((long) (in[offset++] & 0xFF) << 56); + x1 = ((long) in[offset++] & 0xFF) | ((long) (in[offset++] & 0xFF) << 8) + | ((long) (in[offset++] & 0xFF) << 16) + | ((long) (in[offset++] & 0xFF) << 24) + | ((long) (in[offset++] & 0xFF) << 32) + | ((long) (in[offset++] & 0xFF) << 40) + | ((long) (in[offset++] & 0xFF) << 48) + | ((long) (in[offset++] & 0xFF) << 56); + x2 = ((long) in[offset++] & 0xFF) | ((long) (in[offset++] & 0xFF) << 8) + | ((long) (in[offset++] & 0xFF) << 16) + | ((long) (in[offset++] & 0xFF) << 24) + | ((long) (in[offset++] & 0xFF) << 32) + | ((long) (in[offset++] & 0xFF) << 40) + | ((long) (in[offset++] & 0xFF) << 48) + | ((long) (in[offset++] & 0xFF) << 56); + x3 = ((long) in[offset++] & 0xFF) | ((long) (in[offset++] & 0xFF) << 8) + | ((long) (in[offset++] & 0xFF) << 16) + | ((long) (in[offset++] & 0xFF) << 24) + | ((long) (in[offset++] & 0xFF) << 32) + | ((long) (in[offset++] & 0xFF) << 40) + | ((long) (in[offset++] & 0xFF) << 48) + | ((long) (in[offset++] & 0xFF) << 56); + x4 = ((long) in[offset++] & 0xFF) | ((long) (in[offset++] & 0xFF) << 8) + | ((long) (in[offset++] & 0xFF) << 16) + | ((long) (in[offset++] & 0xFF) << 24) + | ((long) (in[offset++] & 0xFF) << 32) + | ((long) (in[offset++] & 0xFF) << 40) + | ((long) (in[offset++] & 0xFF) << 48) + | ((long) (in[offset++] & 0xFF) << 56); + x5 = ((long) in[offset++] & 0xFF) | ((long) (in[offset++] & 0xFF) << 8) + | ((long) (in[offset++] & 0xFF) << 16) + | ((long) (in[offset++] & 0xFF) << 24) + | ((long) (in[offset++] & 0xFF) << 32) + | ((long) (in[offset++] & 0xFF) << 40) + | ((long) (in[offset++] & 0xFF) << 48) + | ((long) (in[offset++] & 0xFF) << 56); + x6 = ((long) in[offset++] & 0xFF) | ((long) (in[offset++] & 0xFF) << 8) + | ((long) (in[offset++] & 0xFF) << 16) + | ((long) (in[offset++] & 0xFF) << 24) + | ((long) (in[offset++] & 0xFF) << 32) + | ((long) (in[offset++] & 0xFF) << 40) + | ((long) (in[offset++] & 0xFF) << 48) + | ((long) (in[offset++] & 0xFF) << 56); + x7 = ((long) in[offset++] & 0xFF) | ((long) (in[offset++] & 0xFF) << 8) + | ((long) (in[offset++] & 0xFF) << 16) + | ((long) (in[offset++] & 0xFF) << 24) + | ((long) (in[offset++] & 0xFF) << 32) + | ((long) (in[offset++] & 0xFF) << 40) + | ((long) (in[offset++] & 0xFF) << 48) + | ((long) (in[offset] & 0xFF) << 56); + + // save_abc ::= + long aa = a, bb = b, cc = c; + + // pass(aa, bb, cc, 5) ::= + cc ^= x0; + aa -= T1[(int) cc & 0xff] ^ T2[(int) (cc >> 16) & 0xff] + ^ T3[(int) (cc >> 32) & 0xff] ^ T4[(int) (cc >> 48) & 0xff]; + bb += T4[(int) (cc >> 8) & 0xff] ^ T3[(int) (cc >> 24) & 0xff] + ^ T2[(int) (cc >> 40) & 0xff] ^ T1[(int) (cc >> 56) & 0xff]; + bb *= 5; + aa ^= x1; + bb -= T1[(int) aa & 0xff] ^ T2[(int) (aa >> 16) & 0xff] + ^ T3[(int) (aa >> 32) & 0xff] ^ T4[(int) (aa >> 48) & 0xff]; + cc += T4[(int) (aa >> 8) & 0xff] ^ T3[(int) (aa >> 24) & 0xff] + ^ T2[(int) (aa >> 40) & 0xff] ^ T1[(int) (aa >> 56) & 0xff]; + cc *= 5; + bb ^= x2; + cc -= T1[(int) bb & 0xff] ^ T2[(int) (bb >> 16) & 0xff] + ^ T3[(int) (bb >> 32) & 0xff] ^ T4[(int) (bb >> 48) & 0xff]; + aa += T4[(int) (bb >> 8) & 0xff] ^ T3[(int) (bb >> 24) & 0xff] + ^ T2[(int) (bb >> 40) & 0xff] ^ T1[(int) (bb >> 56) & 0xff]; + aa *= 5; + cc ^= x3; + aa -= T1[(int) cc & 0xff] ^ T2[(int) (cc >> 16) & 0xff] + ^ T3[(int) (cc >> 32) & 0xff] ^ T4[(int) (cc >> 48) & 0xff]; + bb += T4[(int) (cc >> 8) & 0xff] ^ T3[(int) (cc >> 24) & 0xff] + ^ T2[(int) (cc >> 40) & 0xff] ^ T1[(int) (cc >> 56) & 0xff]; + bb *= 5; + aa ^= x4; + bb -= T1[(int) aa & 0xff] ^ T2[(int) (aa >> 16) & 0xff] + ^ T3[(int) (aa >> 32) & 0xff] ^ T4[(int) (aa >> 48) & 0xff]; + cc += T4[(int) (aa >> 8) & 0xff] ^ T3[(int) (aa >> 24) & 0xff] + ^ T2[(int) (aa >> 40) & 0xff] ^ T1[(int) (aa >> 56) & 0xff]; + cc *= 5; + bb ^= x5; + cc -= T1[(int) bb & 0xff] ^ T2[(int) (bb >> 16) & 0xff] + ^ T3[(int) (bb >> 32) & 0xff] ^ T4[(int) (bb >> 48) & 0xff]; + aa += T4[(int) (bb >> 8) & 0xff] ^ T3[(int) (bb >> 24) & 0xff] + ^ T2[(int) (bb >> 40) & 0xff] ^ T1[(int) (bb >> 56) & 0xff]; + aa *= 5; + cc ^= x6; + aa -= T1[(int) cc & 0xff] ^ T2[(int) (cc >> 16) & 0xff] + ^ T3[(int) (cc >> 32) & 0xff] ^ T4[(int) (cc >> 48) & 0xff]; + bb += T4[(int) (cc >> 8) & 0xff] ^ T3[(int) (cc >> 24) & 0xff] + ^ T2[(int) (cc >> 40) & 0xff] ^ T1[(int) (cc >> 56) & 0xff]; + bb *= 5; + aa ^= x7; + bb -= T1[(int) aa & 0xff] ^ T2[(int) (aa >> 16) & 0xff] + ^ T3[(int) (aa >> 32) & 0xff] ^ T4[(int) (aa >> 48) & 0xff]; + cc += T4[(int) (aa >> 8) & 0xff] ^ T3[(int) (aa >> 24) & 0xff] + ^ T2[(int) (aa >> 40) & 0xff] ^ T1[(int) (aa >> 56) & 0xff]; + cc *= 5; + + // key_schedule ::= + x0 -= x7 ^ 0xA5A5A5A5A5A5A5A5L; + x1 ^= x0; + x2 += x1; + x3 -= x2 ^ ((~x1) << 19); + x4 ^= x3; + x5 += x4; + x6 -= x5 ^ ((~x4) >>> 23); + x7 ^= x6; + x0 += x7; + x1 -= x0 ^ ((~x7) << 19); + x2 ^= x1; + x3 += x2; + x4 -= x3 ^ ((~x2) >>> 23); + x5 ^= x4; + x6 += x5; + x7 -= x6 ^ 0x0123456789ABCDEFL; + + // pass(cc, aa, bb, 7) ::= + bb ^= x0; + cc -= T1[(int) bb & 0xff] ^ T2[(int) (bb >> 16) & 0xff] + ^ T3[(int) (bb >> 32) & 0xff] ^ T4[(int) (bb >> 48) & 0xff]; + aa += T4[(int) (bb >> 8) & 0xff] ^ T3[(int) (bb >> 24) & 0xff] + ^ T2[(int) (bb >> 40) & 0xff] ^ T1[(int) (bb >> 56) & 0xff]; + aa *= 7; + cc ^= x1; + aa -= T1[(int) cc & 0xff] ^ T2[(int) (cc >> 16) & 0xff] + ^ T3[(int) (cc >> 32) & 0xff] ^ T4[(int) (cc >> 48) & 0xff]; + bb += T4[(int) (cc >> 8) & 0xff] ^ T3[(int) (cc >> 24) & 0xff] + ^ T2[(int) (cc >> 40) & 0xff] ^ T1[(int) (cc >> 56) & 0xff]; + bb *= 7; + aa ^= x2; + bb -= T1[(int) aa & 0xff] ^ T2[(int) (aa >> 16) & 0xff] + ^ T3[(int) (aa >> 32) & 0xff] ^ T4[(int) (aa >> 48) & 0xff]; + cc += T4[(int) (aa >> 8) & 0xff] ^ T3[(int) (aa >> 24) & 0xff] + ^ T2[(int) (aa >> 40) & 0xff] ^ T1[(int) (aa >> 56) & 0xff]; + cc *= 7; + bb ^= x3; + cc -= T1[(int) bb & 0xff] ^ T2[(int) (bb >> 16) & 0xff] + ^ T3[(int) (bb >> 32) & 0xff] ^ T4[(int) (bb >> 48) & 0xff]; + aa += T4[(int) (bb >> 8) & 0xff] ^ T3[(int) (bb >> 24) & 0xff] + ^ T2[(int) (bb >> 40) & 0xff] ^ T1[(int) (bb >> 56) & 0xff]; + aa *= 7; + cc ^= x4; + aa -= T1[(int) cc & 0xff] ^ T2[(int) (cc >> 16) & 0xff] + ^ T3[(int) (cc >> 32) & 0xff] ^ T4[(int) (cc >> 48) & 0xff]; + bb += T4[(int) (cc >> 8) & 0xff] ^ T3[(int) (cc >> 24) & 0xff] + ^ T2[(int) (cc >> 40) & 0xff] ^ T1[(int) (cc >> 56) & 0xff]; + bb *= 7; + aa ^= x5; + bb -= T1[(int) aa & 0xff] ^ T2[(int) (aa >> 16) & 0xff] + ^ T3[(int) (aa >> 32) & 0xff] ^ T4[(int) (aa >> 48) & 0xff]; + cc += T4[(int) (aa >> 8) & 0xff] ^ T3[(int) (aa >> 24) & 0xff] + ^ T2[(int) (aa >> 40) & 0xff] ^ T1[(int) (aa >> 56) & 0xff]; + cc *= 7; + bb ^= x6; + cc -= T1[(int) bb & 0xff] ^ T2[(int) (bb >> 16) & 0xff] + ^ T3[(int) (bb >> 32) & 0xff] ^ T4[(int) (bb >> 48) & 0xff]; + aa += T4[(int) (bb >> 8) & 0xff] ^ T3[(int) (bb >> 24) & 0xff] + ^ T2[(int) (bb >> 40) & 0xff] ^ T1[(int) (bb >> 56) & 0xff]; + aa *= 7; + cc ^= x7; + aa -= T1[(int) cc & 0xff] ^ T2[(int) (cc >> 16) & 0xff] + ^ T3[(int) (cc >> 32) & 0xff] ^ T4[(int) (cc >> 48) & 0xff]; + bb += T4[(int) (cc >> 8) & 0xff] ^ T3[(int) (cc >> 24) & 0xff] + ^ T2[(int) (cc >> 40) & 0xff] ^ T1[(int) (cc >> 56) & 0xff]; + bb *= 7; + + // key_schedule ::= + x0 -= x7 ^ 0xA5A5A5A5A5A5A5A5L; + x1 ^= x0; + x2 += x1; + x3 -= x2 ^ ((~x1) << 19); + x4 ^= x3; + x5 += x4; + x6 -= x5 ^ ((~x4) >>> 23); + x7 ^= x6; + x0 += x7; + x1 -= x0 ^ ((~x7) << 19); + x2 ^= x1; + x3 += x2; + x4 -= x3 ^ ((~x2) >>> 23); + x5 ^= x4; + x6 += x5; + x7 -= x6 ^ 0x0123456789ABCDEFL; + + // pass(bb,cc,aa,9) ::= + aa ^= x0; + bb -= T1[(int) aa & 0xff] ^ T2[(int) (aa >> 16) & 0xff] + ^ T3[(int) (aa >> 32) & 0xff] ^ T4[(int) (aa >> 48) & 0xff]; + cc += T4[(int) (aa >> 8) & 0xff] ^ T3[(int) (aa >> 24) & 0xff] + ^ T2[(int) (aa >> 40) & 0xff] ^ T1[(int) (aa >> 56) & 0xff]; + cc *= 9; + bb ^= x1; + cc -= T1[(int) bb & 0xff] ^ T2[(int) (bb >> 16) & 0xff] + ^ T3[(int) (bb >> 32) & 0xff] ^ T4[(int) (bb >> 48) & 0xff]; + aa += T4[(int) (bb >> 8) & 0xff] ^ T3[(int) (bb >> 24) & 0xff] + ^ T2[(int) (bb >> 40) & 0xff] ^ T1[(int) (bb >> 56) & 0xff]; + aa *= 9; + cc ^= x2; + aa -= T1[(int) cc & 0xff] ^ T2[(int) (cc >> 16) & 0xff] + ^ T3[(int) (cc >> 32) & 0xff] ^ T4[(int) (cc >> 48) & 0xff]; + bb += T4[(int) (cc >> 8) & 0xff] ^ T3[(int) (cc >> 24) & 0xff] + ^ T2[(int) (cc >> 40) & 0xff] ^ T1[(int) (cc >> 56) & 0xff]; + bb *= 9; + aa ^= x3; + bb -= T1[(int) aa & 0xff] ^ T2[(int) (aa >> 16) & 0xff] + ^ T3[(int) (aa >> 32) & 0xff] ^ T4[(int) (aa >> 48) & 0xff]; + cc += T4[(int) (aa >> 8) & 0xff] ^ T3[(int) (aa >> 24) & 0xff] + ^ T2[(int) (aa >> 40) & 0xff] ^ T1[(int) (aa >> 56) & 0xff]; + cc *= 9; + bb ^= x4; + cc -= T1[(int) bb & 0xff] ^ T2[(int) (bb >> 16) & 0xff] + ^ T3[(int) (bb >> 32) & 0xff] ^ T4[(int) (bb >> 48) & 0xff]; + aa += T4[(int) (bb >> 8) & 0xff] ^ T3[(int) (bb >> 24) & 0xff] + ^ T2[(int) (bb >> 40) & 0xff] ^ T1[(int) (bb >> 56) & 0xff]; + aa *= 9; + cc ^= x5; + aa -= T1[(int) cc & 0xff] ^ T2[(int) (cc >> 16) & 0xff] + ^ T3[(int) (cc >> 32) & 0xff] ^ T4[(int) (cc >> 48) & 0xff]; + bb += T4[(int) (cc >> 8) & 0xff] ^ T3[(int) (cc >> 24) & 0xff] + ^ T2[(int) (cc >> 40) & 0xff] ^ T1[(int) (cc >> 56) & 0xff]; + bb *= 9; + aa ^= x6; + bb -= T1[(int) aa & 0xff] ^ T2[(int) (aa >> 16) & 0xff] + ^ T3[(int) (aa >> 32) & 0xff] ^ T4[(int) (aa >> 48) & 0xff]; + cc += T4[(int) (aa >> 8) & 0xff] ^ T3[(int) (aa >> 24) & 0xff] + ^ T2[(int) (aa >> 40) & 0xff] ^ T1[(int) (aa >> 56) & 0xff]; + cc *= 9; + bb ^= x7; + cc -= T1[(int) bb & 0xff] ^ T2[(int) (bb >> 16) & 0xff] + ^ T3[(int) (bb >> 32) & 0xff] ^ T4[(int) (bb >> 48) & 0xff]; + aa += T4[(int) (bb >> 8) & 0xff] ^ T3[(int) (bb >> 24) & 0xff] + ^ T2[(int) (bb >> 40) & 0xff] ^ T1[(int) (bb >> 56) & 0xff]; + aa *= 9; + + // feedforward ::= + a ^= aa; + b = bb - b; + c += cc; + } +} diff --git a/gnu/java/security/hash/Whirlpool.java b/gnu/java/security/hash/Whirlpool.java new file mode 100644 index 000000000..8c5d9f360 --- /dev/null +++ b/gnu/java/security/hash/Whirlpool.java @@ -0,0 +1,626 @@ +/* Whirlpool.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + *

Whirlpool, a new 512-bit hashing function operating on messages less than + * 2 ** 256 bits in length. The function structure is designed according to the + * Wide Trail strategy and permits a wide variety of implementation trade-offs. + *

+ * + *

IMPORTANT: This implementation is not thread-safe.

+ * + *

References:

+ * + *
    + *
  1. + * The WHIRLPOOL Hashing Function.
    + * Paulo S.L.M. Barreto and + * Vincent Rijmen.
  2. + *
+ */ +public final class Whirlpool extends BaseHash +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + + private static final int debuglevel = 3; + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + /** The digest of the 0-bit long message. */ + private static final String DIGEST0 = "470F0409ABAA446E49667D4EBE12A14387CEDBD10DD17B8243CAD550A089DC0F" + + "EEA7AA40F6C2AAAB71C6EBD076E43C7CFCA0AD32567897DCB5969861049A0F5A"; + + private static final int R = 10; // default number of rounds + + private static final String Sd = // p. 19 [WHIRLPOOL] + "\u1823\uc6E8\u87B8\u014F\u36A6\ud2F5\u796F\u9152" + + "\u60Bc\u9B8E\uA30c\u7B35\u1dE0\ud7c2\u2E4B\uFE57" + + "\u1577\u37E5\u9FF0\u4AdA\u58c9\u290A\uB1A0\u6B85" + + "\uBd5d\u10F4\ucB3E\u0567\uE427\u418B\uA77d\u95d8" + + "\uFBEE\u7c66\udd17\u479E\ucA2d\uBF07\uAd5A\u8333" + + "\u6302\uAA71\uc819\u49d9\uF2E3\u5B88\u9A26\u32B0" + + "\uE90F\ud580\uBEcd\u3448\uFF7A\u905F\u2068\u1AAE" + + "\uB454\u9322\u64F1\u7312\u4008\uc3Ec\udBA1\u8d3d" + + "\u9700\ucF2B\u7682\ud61B\uB5AF\u6A50\u45F3\u30EF" + + "\u3F55\uA2EA\u65BA\u2Fc0\udE1c\uFd4d\u9275\u068A" + + "\uB2E6\u0E1F\u62d4\uA896\uF9c5\u2559\u8472\u394c" + + "\u5E78\u388c\ud1A5\uE261\uB321\u9c1E\u43c7\uFc04" + + "\u5199\u6d0d\uFAdF\u7E24\u3BAB\ucE11\u8F4E\uB7EB" + + "\u3c81\u94F7\uB913\u2cd3\uE76E\uc403\u5644\u7FA9" + + "\u2ABB\uc153\udc0B\u9d6c\u3174\uF646\uAc89\u14E1" + + "\u163A\u6909\u70B6\ud0Ed\ucc42\u98A4\u285c\uF886"; + + private static final long[] T0 = new long[256]; + + private static final long[] T1 = new long[256]; + + private static final long[] T2 = new long[256]; + + private static final long[] T3 = new long[256]; + + private static final long[] T4 = new long[256]; + + private static final long[] T5 = new long[256]; + + private static final long[] T6 = new long[256]; + + private static final long[] T7 = new long[256]; + + private static final long[] rc = new long[R]; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** The 512-bit context as 8 longs. */ + private long H0, H1, H2, H3, H4, H5, H6, H7; + + /** Work area for computing the round key schedule. */ + private long k00, k01, k02, k03, k04, k05, k06, k07; + + private long Kr0, Kr1, Kr2, Kr3, Kr4, Kr5, Kr6, Kr7; + + /** work area for transforming the 512-bit buffer. */ + private long n0, n1, n2, n3, n4, n5, n6, n7; + + private long nn0, nn1, nn2, nn3, nn4, nn5, nn6, nn7; + + /** work area for holding block cipher's intermediate values. */ + private long w0, w1, w2, w3, w4, w5, w6, w7; + + // Static code - to intialise lookup tables -------------------------------- + + static + { + long time = System.currentTimeMillis(); + + int ROOT = 0x11d; // para. 2.1 [WHIRLPOOL] + int i, r, j; + long s, s2, s3, s4, s5, s8, s9, t; + char c; + final byte[] S = new byte[256]; + for (i = 0; i < 256; i++) + { + c = Sd.charAt(i >>> 1); + + s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFFL; + s2 = s << 1; + if (s2 > 0xFFL) + { + s2 ^= ROOT; + } + s3 = s2 ^ s; + s4 = s2 << 1; + if (s4 > 0xFFL) + { + s4 ^= ROOT; + } + s5 = s4 ^ s; + s8 = s4 << 1; + if (s8 > 0xFFL) + { + s8 ^= ROOT; + } + s9 = s8 ^ s; + + S[i] = (byte) s; + T0[i] = t = s << 56 | s << 48 | s3 << 40 | s << 32 | s5 << 24 + | s8 << 16 | s9 << 8 | s5; + T1[i] = t >>> 8 | t << 56; + T2[i] = t >>> 16 | t << 48; + T3[i] = t >>> 24 | t << 40; + T4[i] = t >>> 32 | t << 32; + T5[i] = t >>> 40 | t << 24; + T6[i] = t >>> 48 | t << 16; + T7[i] = t >>> 56 | t << 8; + } + + for (r = 1, i = 0, j = 0; r < R + 1; r++) + { + rc[i++] = (S[j++] & 0xFFL) << 56 | (S[j++] & 0xFFL) << 48 + | (S[j++] & 0xFFL) << 40 | (S[j++] & 0xFFL) << 32 + | (S[j++] & 0xFFL) << 24 | (S[j++] & 0xFFL) << 16 + | (S[j++] & 0xFFL) << 8 | (S[j++] & 0xFFL); + } + + time = System.currentTimeMillis() - time; + + if (DEBUG && debuglevel > 8) + { + System.out.println("=========="); + System.out.println(); + System.out.println("Static data"); + System.out.println(); + + System.out.println(); + System.out.println("T0[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T0[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T1[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T1[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T2[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T2[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T3[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T3[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T4[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T4[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T5[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T6[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T7[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("rc[]:"); + for (i = 0; i < R; i++) + { + System.out.println("0x" + Util.toString(rc[i])); + } + System.out.println(); + + System.out.println(); + System.out.println("Total initialization time: " + time + " ms."); + System.out.println(); + } + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Whirlpool() + { + super(Registry.WHIRLPOOL_HASH, 20, BLOCK_SIZE); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param md the instance to clone. + */ + private Whirlpool(Whirlpool md) + { + this(); + + this.H0 = md.H0; + this.H1 = md.H1; + this.H2 = md.H2; + this.H3 = md.H3; + this.H4 = md.H4; + this.H5 = md.H5; + this.H6 = md.H6; + this.H7 = md.H7; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return (new Whirlpool(this)); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected void transform(byte[] in, int offset) + { + // apply mu to the input + n0 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL); + n1 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL); + n2 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL); + n3 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL); + n4 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL); + n5 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL); + n6 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL); + n7 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL); + + // transform K into the key schedule Kr; 0 <= r <= R + k00 = H0; + k01 = H1; + k02 = H2; + k03 = H3; + k04 = H4; + k05 = H5; + k06 = H6; + k07 = H7; + + nn0 = n0 ^ k00; + nn1 = n1 ^ k01; + nn2 = n2 ^ k02; + nn3 = n3 ^ k03; + nn4 = n4 ^ k04; + nn5 = n5 ^ k05; + nn6 = n6 ^ k06; + nn7 = n7 ^ k07; + + // intermediate cipher output + w0 = w1 = w2 = w3 = w4 = w5 = w6 = w7 = 0L; + + for (int r = 0; r < R; r++) + { + // 1. compute intermediate round key schedule by applying ro[rc] + // to the previous round key schedule --rc being the round constant + Kr0 = T0[(int) ((k00 >> 56) & 0xFFL)] ^ T1[(int) ((k07 >> 48) & 0xFFL)] + ^ T2[(int) ((k06 >> 40) & 0xFFL)] + ^ T3[(int) ((k05 >> 32) & 0xFFL)] + ^ T4[(int) ((k04 >> 24) & 0xFFL)] + ^ T5[(int) ((k03 >> 16) & 0xFFL)] + ^ T6[(int) ((k02 >> 8) & 0xFFL)] ^ T7[(int) (k01 & 0xFFL)] + ^ rc[r]; + + Kr1 = T0[(int) ((k01 >> 56) & 0xFFL)] ^ T1[(int) ((k00 >> 48) & 0xFFL)] + ^ T2[(int) ((k07 >> 40) & 0xFFL)] + ^ T3[(int) ((k06 >> 32) & 0xFFL)] + ^ T4[(int) ((k05 >> 24) & 0xFFL)] + ^ T5[(int) ((k04 >> 16) & 0xFFL)] + ^ T6[(int) ((k03 >> 8) & 0xFFL)] ^ T7[(int) (k02 & 0xFFL)]; + + Kr2 = T0[(int) ((k02 >> 56) & 0xFFL)] ^ T1[(int) ((k01 >> 48) & 0xFFL)] + ^ T2[(int) ((k00 >> 40) & 0xFFL)] + ^ T3[(int) ((k07 >> 32) & 0xFFL)] + ^ T4[(int) ((k06 >> 24) & 0xFFL)] + ^ T5[(int) ((k05 >> 16) & 0xFFL)] + ^ T6[(int) ((k04 >> 8) & 0xFFL)] ^ T7[(int) (k03 & 0xFFL)]; + + Kr3 = T0[(int) ((k03 >> 56) & 0xFFL)] ^ T1[(int) ((k02 >> 48) & 0xFFL)] + ^ T2[(int) ((k01 >> 40) & 0xFFL)] + ^ T3[(int) ((k00 >> 32) & 0xFFL)] + ^ T4[(int) ((k07 >> 24) & 0xFFL)] + ^ T5[(int) ((k06 >> 16) & 0xFFL)] + ^ T6[(int) ((k05 >> 8) & 0xFFL)] ^ T7[(int) (k04 & 0xFFL)]; + + Kr4 = T0[(int) ((k04 >> 56) & 0xFFL)] ^ T1[(int) ((k03 >> 48) & 0xFFL)] + ^ T2[(int) ((k02 >> 40) & 0xFFL)] + ^ T3[(int) ((k01 >> 32) & 0xFFL)] + ^ T4[(int) ((k00 >> 24) & 0xFFL)] + ^ T5[(int) ((k07 >> 16) & 0xFFL)] + ^ T6[(int) ((k06 >> 8) & 0xFFL)] ^ T7[(int) (k05 & 0xFFL)]; + + Kr5 = T0[(int) ((k05 >> 56) & 0xFFL)] ^ T1[(int) ((k04 >> 48) & 0xFFL)] + ^ T2[(int) ((k03 >> 40) & 0xFFL)] + ^ T3[(int) ((k02 >> 32) & 0xFFL)] + ^ T4[(int) ((k01 >> 24) & 0xFFL)] + ^ T5[(int) ((k00 >> 16) & 0xFFL)] + ^ T6[(int) ((k07 >> 8) & 0xFFL)] ^ T7[(int) (k06 & 0xFFL)]; + + Kr6 = T0[(int) ((k06 >> 56) & 0xFFL)] ^ T1[(int) ((k05 >> 48) & 0xFFL)] + ^ T2[(int) ((k04 >> 40) & 0xFFL)] + ^ T3[(int) ((k03 >> 32) & 0xFFL)] + ^ T4[(int) ((k02 >> 24) & 0xFFL)] + ^ T5[(int) ((k01 >> 16) & 0xFFL)] + ^ T6[(int) ((k00 >> 8) & 0xFFL)] ^ T7[(int) (k07 & 0xFFL)]; + + Kr7 = T0[(int) ((k07 >> 56) & 0xFFL)] ^ T1[(int) ((k06 >> 48) & 0xFFL)] + ^ T2[(int) ((k05 >> 40) & 0xFFL)] + ^ T3[(int) ((k04 >> 32) & 0xFFL)] + ^ T4[(int) ((k03 >> 24) & 0xFFL)] + ^ T5[(int) ((k02 >> 16) & 0xFFL)] + ^ T6[(int) ((k01 >> 8) & 0xFFL)] ^ T7[(int) (k00 & 0xFFL)]; + + k00 = Kr0; + k01 = Kr1; + k02 = Kr2; + k03 = Kr3; + k04 = Kr4; + k05 = Kr5; + k06 = Kr6; + k07 = Kr7; + + // 2. incrementally compute the cipher output + w0 = T0[(int) ((nn0 >> 56) & 0xFFL)] ^ T1[(int) ((nn7 >> 48) & 0xFFL)] + ^ T2[(int) ((nn6 >> 40) & 0xFFL)] + ^ T3[(int) ((nn5 >> 32) & 0xFFL)] + ^ T4[(int) ((nn4 >> 24) & 0xFFL)] + ^ T5[(int) ((nn3 >> 16) & 0xFFL)] ^ T6[(int) ((nn2 >> 8) & 0xFFL)] + ^ T7[(int) (nn1 & 0xFFL)] ^ Kr0; + w1 = T0[(int) ((nn1 >> 56) & 0xFFL)] ^ T1[(int) ((nn0 >> 48) & 0xFFL)] + ^ T2[(int) ((nn7 >> 40) & 0xFFL)] + ^ T3[(int) ((nn6 >> 32) & 0xFFL)] + ^ T4[(int) ((nn5 >> 24) & 0xFFL)] + ^ T5[(int) ((nn4 >> 16) & 0xFFL)] ^ T6[(int) ((nn3 >> 8) & 0xFFL)] + ^ T7[(int) (nn2 & 0xFFL)] ^ Kr1; + w2 = T0[(int) ((nn2 >> 56) & 0xFFL)] ^ T1[(int) ((nn1 >> 48) & 0xFFL)] + ^ T2[(int) ((nn0 >> 40) & 0xFFL)] + ^ T3[(int) ((nn7 >> 32) & 0xFFL)] + ^ T4[(int) ((nn6 >> 24) & 0xFFL)] + ^ T5[(int) ((nn5 >> 16) & 0xFFL)] ^ T6[(int) ((nn4 >> 8) & 0xFFL)] + ^ T7[(int) (nn3 & 0xFFL)] ^ Kr2; + w3 = T0[(int) ((nn3 >> 56) & 0xFFL)] ^ T1[(int) ((nn2 >> 48) & 0xFFL)] + ^ T2[(int) ((nn1 >> 40) & 0xFFL)] + ^ T3[(int) ((nn0 >> 32) & 0xFFL)] + ^ T4[(int) ((nn7 >> 24) & 0xFFL)] + ^ T5[(int) ((nn6 >> 16) & 0xFFL)] ^ T6[(int) ((nn5 >> 8) & 0xFFL)] + ^ T7[(int) (nn4 & 0xFFL)] ^ Kr3; + w4 = T0[(int) ((nn4 >> 56) & 0xFFL)] ^ T1[(int) ((nn3 >> 48) & 0xFFL)] + ^ T2[(int) ((nn2 >> 40) & 0xFFL)] + ^ T3[(int) ((nn1 >> 32) & 0xFFL)] + ^ T4[(int) ((nn0 >> 24) & 0xFFL)] + ^ T5[(int) ((nn7 >> 16) & 0xFFL)] ^ T6[(int) ((nn6 >> 8) & 0xFFL)] + ^ T7[(int) (nn5 & 0xFFL)] ^ Kr4; + w5 = T0[(int) ((nn5 >> 56) & 0xFFL)] ^ T1[(int) ((nn4 >> 48) & 0xFFL)] + ^ T2[(int) ((nn3 >> 40) & 0xFFL)] + ^ T3[(int) ((nn2 >> 32) & 0xFFL)] + ^ T4[(int) ((nn1 >> 24) & 0xFFL)] + ^ T5[(int) ((nn0 >> 16) & 0xFFL)] ^ T6[(int) ((nn7 >> 8) & 0xFFL)] + ^ T7[(int) (nn6 & 0xFFL)] ^ Kr5; + w6 = T0[(int) ((nn6 >> 56) & 0xFFL)] ^ T1[(int) ((nn5 >> 48) & 0xFFL)] + ^ T2[(int) ((nn4 >> 40) & 0xFFL)] + ^ T3[(int) ((nn3 >> 32) & 0xFFL)] + ^ T4[(int) ((nn2 >> 24) & 0xFFL)] + ^ T5[(int) ((nn1 >> 16) & 0xFFL)] ^ T6[(int) ((nn0 >> 8) & 0xFFL)] + ^ T7[(int) (nn7 & 0xFFL)] ^ Kr6; + w7 = T0[(int) ((nn7 >> 56) & 0xFFL)] ^ T1[(int) ((nn6 >> 48) & 0xFFL)] + ^ T2[(int) ((nn5 >> 40) & 0xFFL)] + ^ T3[(int) ((nn4 >> 32) & 0xFFL)] + ^ T4[(int) ((nn3 >> 24) & 0xFFL)] + ^ T5[(int) ((nn2 >> 16) & 0xFFL)] ^ T6[(int) ((nn1 >> 8) & 0xFFL)] + ^ T7[(int) (nn0 & 0xFFL)] ^ Kr7; + + nn0 = w0; + nn1 = w1; + nn2 = w2; + nn3 = w3; + nn4 = w4; + nn5 = w5; + nn6 = w6; + nn7 = w7; + } + + // apply the Miyaguchi-Preneel hash scheme + H0 ^= w0 ^ n0; + H1 ^= w1 ^ n1; + H2 ^= w2 ^ n2; + H3 ^= w3 ^ n3; + H4 ^= w4 ^ n4; + H5 ^= w5 ^ n5; + H6 ^= w6 ^ n6; + H7 ^= w7 ^ n7; + } + + protected byte[] padBuffer() + { + // [WHIRLPOOL] p. 6: + // "...padded with a 1-bit, then with as few 0-bits as necessary to + // obtain a bit string whose length is an odd multiple of 256, and + // finally with the 256-bit right-justified binary representation of L." + // in this implementation we use 'count' as the number of bytes hashed + // so far. hence the minimal number of bytes added to the message proper + // are 33 (1 for the 1-bit followed by the 0-bits and the encoding of + // the count framed in a 256-bit block). our formula is then: + // count + 33 + padding = 0 (mod BLOCK_SIZE) + int n = (int) ((count + 33) % BLOCK_SIZE); + int padding = n == 0 ? 33 : BLOCK_SIZE - n + 33; + + byte[] result = new byte[padding]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + + // save (right justified) the number of bits hashed + long bits = count * 8; + int i = padding - 8; + result[i++] = (byte) (bits >>> 56); + result[i++] = (byte) (bits >>> 48); + result[i++] = (byte) (bits >>> 40); + result[i++] = (byte) (bits >>> 32); + result[i++] = (byte) (bits >>> 24); + result[i++] = (byte) (bits >>> 16); + result[i++] = (byte) (bits >>> 8); + result[i] = (byte) bits; + + return result; + } + + protected byte[] getResult() + { + // apply inverse mu to the context + byte[] result = new byte[] { (byte) (H0 >>> 56), (byte) (H0 >>> 48), + (byte) (H0 >>> 40), (byte) (H0 >>> 32), + (byte) (H0 >>> 24), (byte) (H0 >>> 16), + (byte) (H0 >>> 8), (byte) H0, + (byte) (H1 >>> 56), (byte) (H1 >>> 48), + (byte) (H1 >>> 40), (byte) (H1 >>> 32), + (byte) (H1 >>> 24), (byte) (H1 >>> 16), + (byte) (H1 >>> 8), (byte) H1, + (byte) (H2 >>> 56), (byte) (H2 >>> 48), + (byte) (H2 >>> 40), (byte) (H2 >>> 32), + (byte) (H2 >>> 24), (byte) (H2 >>> 16), + (byte) (H2 >>> 8), (byte) H2, + (byte) (H3 >>> 56), (byte) (H3 >>> 48), + (byte) (H3 >>> 40), (byte) (H3 >>> 32), + (byte) (H3 >>> 24), (byte) (H3 >>> 16), + (byte) (H3 >>> 8), (byte) H3, + (byte) (H4 >>> 56), (byte) (H4 >>> 48), + (byte) (H4 >>> 40), (byte) (H4 >>> 32), + (byte) (H4 >>> 24), (byte) (H4 >>> 16), + (byte) (H4 >>> 8), (byte) H4, + (byte) (H5 >>> 56), (byte) (H5 >>> 48), + (byte) (H5 >>> 40), (byte) (H5 >>> 32), + (byte) (H5 >>> 24), (byte) (H5 >>> 16), + (byte) (H5 >>> 8), (byte) H5, + (byte) (H6 >>> 56), (byte) (H6 >>> 48), + (byte) (H6 >>> 40), (byte) (H6 >>> 32), + (byte) (H6 >>> 24), (byte) (H6 >>> 16), + (byte) (H6 >>> 8), (byte) H6, + (byte) (H7 >>> 56), (byte) (H7 >>> 48), + (byte) (H7 >>> 40), (byte) (H7 >>> 32), + (byte) (H7 >>> 24), (byte) (H7 >>> 16), + (byte) (H7 >>> 8), (byte) H7 }; + + return result; + } + + protected void resetContext() + { + H0 = H1 = H2 = H3 = H4 = H5 = H6 = H7 = 0L; + } + + public boolean selfTest() + { + if (valid == null) + { + valid = new Boolean( + DIGEST0.equals(Util.toString(new Whirlpool().digest()))); + } + return valid.booleanValue(); + } +} diff --git a/gnu/java/security/jce/hash/HavalSpi.java b/gnu/java/security/jce/hash/HavalSpi.java new file mode 100644 index 000000000..e127779ef --- /dev/null +++ b/gnu/java/security/jce/hash/HavalSpi.java @@ -0,0 +1,68 @@ +/* HavalSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the HAVAL Service Provider Interface + * (SPI) Adapter.

+ * + * @version Revision: $ + */ +public class HavalSpi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public HavalSpi() + { + super(Registry.HAVAL_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/MD2Spi.java b/gnu/java/security/jce/hash/MD2Spi.java new file mode 100644 index 000000000..3fc382138 --- /dev/null +++ b/gnu/java/security/jce/hash/MD2Spi.java @@ -0,0 +1,69 @@ +/* MD2Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + *

The implementation of the MD2 Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class MD2Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public MD2Spi() + { + super(Registry.MD2_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/MD4Spi.java b/gnu/java/security/jce/hash/MD4Spi.java new file mode 100644 index 000000000..52ad9ea74 --- /dev/null +++ b/gnu/java/security/jce/hash/MD4Spi.java @@ -0,0 +1,69 @@ +/* MD4Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + *

The implementation of the MD4 Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class MD4Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public MD4Spi() + { + super(Registry.MD4_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/MD5Spi.java b/gnu/java/security/jce/hash/MD5Spi.java new file mode 100644 index 000000000..39aee85c7 --- /dev/null +++ b/gnu/java/security/jce/hash/MD5Spi.java @@ -0,0 +1,68 @@ +/* MD5Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the MD5 Service Provider Interface (SPI) + * adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class MD5Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public MD5Spi() + { + super(Registry.MD5_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/MessageDigestAdapter.java b/gnu/java/security/jce/hash/MessageDigestAdapter.java new file mode 100644 index 000000000..c804f5f00 --- /dev/null +++ b/gnu/java/security/jce/hash/MessageDigestAdapter.java @@ -0,0 +1,147 @@ +/* MessageDigestAdapter.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.hash.HashFactory; + +import java.security.DigestException; +import java.security.MessageDigestSpi; + +/** + * The implementation of a generic {@link java.security.MessageDigest} adapter + * class to wrap gnu.crypto hash instances.

+ * + * This class defines the Service Provider Interface (SPI) for the + * {@link java.security.MessageDigest} class, which provides the functionality + * of a message digest algorithm, such as MD5 or SHA. Message digests are secure + * one-way hash functions that take arbitrary-sized data and output a fixed- + * length hash value.

+ * + * All the abstract methods in the {@link java.security.MessageDigestSpi} class + * are implemented by this class and all its sub-classes.

+ * + * All the implementations which subclass this object, and which are serviced by + * the GNU Crypto provider implement the {@link java.lang.Cloneable} interface.

+ * + * @version $Revision: 1.1.4.1 $ + */ +class MessageDigestAdapter extends MessageDigestSpi implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Our underlying hash instance. */ + private IMessageDigest adaptee; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial protected constructor. + * + * @param mdName the canonical name of the hash algorithm. + */ + protected MessageDigestAdapter(String mdName) + { + this(HashFactory.getInstance(mdName)); + } + + /** + * Private constructor for cloning purposes. + * + * @param adaptee a clone of the underlying hash algorithm instance. + */ + private MessageDigestAdapter(IMessageDigest adaptee) + { + super(); + + this.adaptee = adaptee; + } + + // Class methods + // ------------------------------------------------------------------------- + + // java.security.MessageDigestSpi interface implementation + // ------------------------------------------------------------------------- + + public Object clone() + { + return new MessageDigestAdapter((IMessageDigest) adaptee.clone()); + } + + public int engineGetDigestLength() + { + return adaptee.hashSize(); + } + + public void engineUpdate(byte input) + { + adaptee.update(input); + } + + public void engineUpdate(byte[] input, int offset, int len) + { + adaptee.update(input, offset, len); + } + + public byte[] engineDigest() + { + return adaptee.digest(); + } + + public int engineDigest(byte[] buf, int offset, int len) + throws DigestException + { + int result = adaptee.hashSize(); + if (len < result) + { + throw new DigestException(); + } + byte[] md = adaptee.digest(); + System.arraycopy(md, 0, buf, offset, result); + return result; + } + + public void engineReset() + { + adaptee.reset(); + } +} diff --git a/gnu/java/security/jce/hash/RipeMD128Spi.java b/gnu/java/security/jce/hash/RipeMD128Spi.java new file mode 100644 index 000000000..c5f45ea5b --- /dev/null +++ b/gnu/java/security/jce/hash/RipeMD128Spi.java @@ -0,0 +1,68 @@ +/* RipeMD128Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the RIPEMD-128 Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class RipeMD128Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RipeMD128Spi() + { + super(Registry.RIPEMD128_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/RipeMD160Spi.java b/gnu/java/security/jce/hash/RipeMD160Spi.java new file mode 100644 index 000000000..408a9b54d --- /dev/null +++ b/gnu/java/security/jce/hash/RipeMD160Spi.java @@ -0,0 +1,68 @@ +/* RipeMD160Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the RIPEMD-160 Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class RipeMD160Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RipeMD160Spi() + { + super(Registry.RIPEMD160_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/Sha160Spi.java b/gnu/java/security/jce/hash/Sha160Spi.java new file mode 100644 index 000000000..55075dee8 --- /dev/null +++ b/gnu/java/security/jce/hash/Sha160Spi.java @@ -0,0 +1,68 @@ +/* Sha160Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the SHA-1 (160-bit) Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class Sha160Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha160Spi() + { + super(Registry.SHA160_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/Sha256Spi.java b/gnu/java/security/jce/hash/Sha256Spi.java new file mode 100644 index 000000000..7bb321cde --- /dev/null +++ b/gnu/java/security/jce/hash/Sha256Spi.java @@ -0,0 +1,68 @@ +/* Sha256Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + *

The implementation of the SHA-2-1 (256-bit) Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class Sha256Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha256Spi() + { + super(Registry.SHA256_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/Sha384Spi.java b/gnu/java/security/jce/hash/Sha384Spi.java new file mode 100644 index 000000000..2fd7ff4a9 --- /dev/null +++ b/gnu/java/security/jce/hash/Sha384Spi.java @@ -0,0 +1,68 @@ +/* Sha384Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + *

The implementation of the SHA-2-2 (384-bit) Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class Sha384Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha384Spi() + { + super(Registry.SHA384_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/Sha512Spi.java b/gnu/java/security/jce/hash/Sha512Spi.java new file mode 100644 index 000000000..8b38a442b --- /dev/null +++ b/gnu/java/security/jce/hash/Sha512Spi.java @@ -0,0 +1,68 @@ +/* Sha512Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + *

The implementation of the SHA-2-3 (512-bit) Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class Sha512Spi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha512Spi() + { + super(Registry.SHA512_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/TigerSpi.java b/gnu/java/security/jce/hash/TigerSpi.java new file mode 100644 index 000000000..fe0f8d67a --- /dev/null +++ b/gnu/java/security/jce/hash/TigerSpi.java @@ -0,0 +1,69 @@ +/* TigerSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + *

The implementation of the Tiger Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class TigerSpi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public TigerSpi() + { + super(Registry.TIGER_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/hash/WhirlpoolSpi.java b/gnu/java/security/jce/hash/WhirlpoolSpi.java new file mode 100644 index 000000000..d37464ef0 --- /dev/null +++ b/gnu/java/security/jce/hash/WhirlpoolSpi.java @@ -0,0 +1,68 @@ +/* WhirlpoolSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the Whirlpool Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class WhirlpoolSpi extends MessageDigestAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public WhirlpoolSpi() + { + super(Registry.WHIRLPOOL_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/HavalRandomSpi.java b/gnu/java/security/jce/prng/HavalRandomSpi.java new file mode 100644 index 000000000..0c39a37fd --- /dev/null +++ b/gnu/java/security/jce/prng/HavalRandomSpi.java @@ -0,0 +1,66 @@ +/* HavalRandomSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the HAVAL-based SecureRandom Service Provider + * Interface (SPI) Adapter.

+ */ +public class HavalRandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public HavalRandomSpi() + { + super(Registry.HAVAL_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/MD2RandomSpi.java b/gnu/java/security/jce/prng/MD2RandomSpi.java new file mode 100644 index 000000000..72a7f4873 --- /dev/null +++ b/gnu/java/security/jce/prng/MD2RandomSpi.java @@ -0,0 +1,66 @@ +/* MD2RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the MD2-based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class MD2RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public MD2RandomSpi() + { + super(Registry.MD2_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/MD4RandomSpi.java b/gnu/java/security/jce/prng/MD4RandomSpi.java new file mode 100644 index 000000000..f5f98f8f3 --- /dev/null +++ b/gnu/java/security/jce/prng/MD4RandomSpi.java @@ -0,0 +1,66 @@ +/* MD4RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the MD4-based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class MD4RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public MD4RandomSpi() + { + super(Registry.MD4_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/MD5RandomSpi.java b/gnu/java/security/jce/prng/MD5RandomSpi.java new file mode 100644 index 000000000..0181247bc --- /dev/null +++ b/gnu/java/security/jce/prng/MD5RandomSpi.java @@ -0,0 +1,66 @@ +/* MD5RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the MD5-based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class MD5RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public MD5RandomSpi() + { + super(Registry.MD5_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/RipeMD128RandomSpi.java b/gnu/java/security/jce/prng/RipeMD128RandomSpi.java new file mode 100644 index 000000000..5580716a4 --- /dev/null +++ b/gnu/java/security/jce/prng/RipeMD128RandomSpi.java @@ -0,0 +1,66 @@ +/* RipeMD128RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + *

The implementation of the RIPEMD128-based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class RipeMD128RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RipeMD128RandomSpi() + { + super(Registry.RIPEMD128_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/RipeMD160RandomSpi.java b/gnu/java/security/jce/prng/RipeMD160RandomSpi.java new file mode 100644 index 000000000..734fe824a --- /dev/null +++ b/gnu/java/security/jce/prng/RipeMD160RandomSpi.java @@ -0,0 +1,66 @@ +/* RipeMD160RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the RIPEMD160-based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class RipeMD160RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RipeMD160RandomSpi() + { + super(Registry.RIPEMD160_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/SecureRandomAdapter.java b/gnu/java/security/jce/prng/SecureRandomAdapter.java new file mode 100644 index 000000000..e7cb72091 --- /dev/null +++ b/gnu/java/security/jce/prng/SecureRandomAdapter.java @@ -0,0 +1,126 @@ +/* SecureRandomAdapter.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.prng.MDGenerator; + +import java.security.SecureRandomSpi; +import java.util.HashMap; + +/** + *

The implementation of a generic {@link java.security.SecureRandom} adapter + * class to wrap gnu.crypto prng instances based on Message Digest algorithms.

+ * + *

This class defines the Service Provider Interface (SPI) for + * the {@link java.security.SecureRandom} class, which provides the + * functionality of a cryptographically strong pseudo-random number generator.

+ * + *

All the abstract methods in the {@link SecureRandomSpi} class are + * implemented by this class and all its sub-classes.

+ */ +abstract class SecureRandomAdapter extends SecureRandomSpi +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Our underlying prng instance. */ + private MDGenerator adaptee = new MDGenerator(); + + /** The name of the message digest algorithm used by the adaptee. */ + private String mdName; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial protected constructor.

+ * + * @param mdName the canonical name of the underlying hash algorithm. + */ + protected SecureRandomAdapter(String mdName) + { + super(); + + this.mdName = mdName; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.SecureRandomSpi interface implementation ------------------ + + public byte[] engineGenerateSeed(int numBytes) + { + if (numBytes < 1) + { + return new byte[0]; + } + byte[] result = new byte[numBytes]; + this.engineNextBytes(result); + return result; + } + + public void engineNextBytes(byte[] bytes) + { + if (!adaptee.isInitialised()) + { + this.engineSetSeed(new byte[0]); + } + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + } + catch (LimitReachedException ignored) + { + } + } + + public void engineSetSeed(byte[] seed) + { + HashMap attributes = new HashMap(); + attributes.put(MDGenerator.MD_NAME, mdName); + attributes.put(MDGenerator.SEEED, seed); + adaptee.init(attributes); + } +} diff --git a/gnu/java/security/jce/prng/Sha160RandomSpi.java b/gnu/java/security/jce/prng/Sha160RandomSpi.java new file mode 100644 index 000000000..c93b02d3f --- /dev/null +++ b/gnu/java/security/jce/prng/Sha160RandomSpi.java @@ -0,0 +1,66 @@ +/* Sha160RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the SHA1-based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class Sha160RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha160RandomSpi() + { + super(Registry.SHA160_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/Sha256RandomSpi.java b/gnu/java/security/jce/prng/Sha256RandomSpi.java new file mode 100644 index 000000000..736996430 --- /dev/null +++ b/gnu/java/security/jce/prng/Sha256RandomSpi.java @@ -0,0 +1,66 @@ +/* Sha256RandomSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + *

The implementation of the SHA-256 based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class Sha256RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha256RandomSpi() + { + super(Registry.SHA256_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/Sha384RandomSpi.java b/gnu/java/security/jce/prng/Sha384RandomSpi.java new file mode 100644 index 000000000..afbf19303 --- /dev/null +++ b/gnu/java/security/jce/prng/Sha384RandomSpi.java @@ -0,0 +1,66 @@ +/* Sha384RandomSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + *

The implementation of the SHA-384 based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class Sha384RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha384RandomSpi() + { + super(Registry.SHA384_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/Sha512RandomSpi.java b/gnu/java/security/jce/prng/Sha512RandomSpi.java new file mode 100644 index 000000000..b2b337760 --- /dev/null +++ b/gnu/java/security/jce/prng/Sha512RandomSpi.java @@ -0,0 +1,66 @@ +/* Sha512RandomSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + *

The implementation of the SHA-512 based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class Sha512RandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Sha512RandomSpi() + { + super(Registry.SHA512_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/TigerRandomSpi.java b/gnu/java/security/jce/prng/TigerRandomSpi.java new file mode 100644 index 000000000..b4795b98e --- /dev/null +++ b/gnu/java/security/jce/prng/TigerRandomSpi.java @@ -0,0 +1,66 @@ +/* TigerRandomSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the Tiger based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class TigerRandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public TigerRandomSpi() + { + super(Registry.TIGER_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java b/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java new file mode 100644 index 000000000..f327f9df2 --- /dev/null +++ b/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java @@ -0,0 +1,66 @@ +/* WhirlpoolRandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the Whirlpool-based SecureRandom Service Provider + * Interface (SPI) adapter.

+ */ +public class WhirlpoolRandomSpi extends SecureRandomAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public WhirlpoolRandomSpi() + { + super(Registry.WHIRLPOOL_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/sig/DSSKeyFactory.java b/gnu/java/security/jce/sig/DSSKeyFactory.java new file mode 100644 index 000000000..bb4d85c89 --- /dev/null +++ b/gnu/java/security/jce/sig/DSSKeyFactory.java @@ -0,0 +1,238 @@ +/* DSSKeyFactory.java -- JCE DSA key factory Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec; +import gnu.java.security.key.dss.DSSKeyPairX509Codec; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.dss.DSSPublicKey; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** + * DSA key factory. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class DSSKeyFactory extends KeyFactorySpi +{ + // implicit 0-arguments constructor + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DSAPublicKeySpec) + { + DSAPublicKeySpec spec = (DSAPublicKeySpec) keySpec; + BigInteger p = spec.getP(); + BigInteger q = spec.getQ(); + BigInteger g = spec.getG(); + BigInteger y = spec.getY(); + return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); + } + + if (keySpec instanceof X509EncodedKeySpec) + { + X509EncodedKeySpec spec = (X509EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PublicKey result; + try + { + result = new DSSKeyPairX509Codec().decodePublicKey(encoded); + return result; + } + catch (RuntimeException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DSAPrivateKeySpec) + { + DSAPrivateKeySpec spec = (DSAPrivateKeySpec) keySpec; + BigInteger p = spec.getP(); + BigInteger q = spec.getQ(); + BigInteger g = spec.getG(); + BigInteger x = spec.getX(); + return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); + } + + if (keySpec instanceof PKCS8EncodedKeySpec) + { + PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PrivateKey result; + try + { + result = new DSSKeyPairPKCS8Codec().decodePrivateKey(encoded); + return result; + } + catch (RuntimeException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + throw new InvalidKeySpecException("Unsupported (private) key specification"); + } + + protected KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof DSAPublicKey) + { + if (keySpec.isAssignableFrom(DSAPublicKeySpec.class)) + { + DSAPublicKey dsaKey = (DSAPublicKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger q = dsaKey.getParams().getQ(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger y = dsaKey.getY(); + return new DSAPublicKeySpec(y, p, q, g); + } + + if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) + { + if (key instanceof DSSPublicKey) + { + DSSPublicKey dssKey = (DSSPublicKey) key; + byte[] encoded = dssKey.getEncoded(Registry.X509_ENCODING_ID); + return new X509EncodedKeySpec(encoded); + } + + if (Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new X509EncodedKeySpec(encoded); + } + + throw new InvalidKeySpecException("Wrong key type or unsupported (public) key specification"); + } + + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + + if (key instanceof DSAPrivateKey) + { + if (keySpec.isAssignableFrom(DSAPrivateKeySpec.class)) + { + DSAPrivateKey dsaKey = (DSAPrivateKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger q = dsaKey.getParams().getQ(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger x = dsaKey.getX(); + return new DSAPrivateKeySpec(x, p, q, g); + } + + if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) + { + if (key instanceof DSSPrivateKey) + { + DSSPrivateKey dssKey = (DSSPrivateKey) key; + byte[] encoded = dssKey.getEncoded(Registry.PKCS8_ENCODING_ID); + return new PKCS8EncodedKeySpec(encoded); + } + + if (Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new PKCS8EncodedKeySpec(encoded); + } + + throw new InvalidKeySpecException("Wrong key type or unsupported (private) key specification"); + } + + throw new InvalidKeySpecException("Unsupported (private) key specification"); + } + + throw new InvalidKeySpecException("Wrong key type or unsupported key specification"); + } + + protected Key engineTranslateKey(Key key) throws InvalidKeyException + { + if ((key instanceof DSSPublicKey) || (key instanceof DSSPrivateKey)) + return key; + + if (key instanceof DSAPublicKey) + { + DSAPublicKey dsaKey = (DSAPublicKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger q = dsaKey.getParams().getQ(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger y = dsaKey.getY(); + return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); + } + + if (key instanceof DSAPrivateKey) + { + DSAPrivateKey dsaKey = (DSAPrivateKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger q = dsaKey.getParams().getQ(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger x = dsaKey.getX(); + return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); + } + + throw new InvalidKeyException("Wrong key type"); + } +} diff --git a/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java b/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java new file mode 100644 index 000000000..49a64afbd --- /dev/null +++ b/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java @@ -0,0 +1,169 @@ +/* DSSKeyPairGeneratorSpi.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairGenerator; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.SecureRandom; +import java.security.interfaces.DSAKeyPairGenerator; +import java.security.interfaces.DSAParams; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.DSAParameterSpec; +import java.util.HashMap; + +/** + * The implementation of a {@link java.security.KeyPairGenerator} adapter class + * to wrap gnu.crypto DSS keypair generator instances.

+ * + * In case the client does not explicitly initialize the KeyPairGenerator (via + * a call to an initialize() method), the GNU Crypto provider + * uses a default modulus size (keysize) of 1024 bits.

+ * + * @version $Revision: 1.3.2.1 $ + */ +public class DSSKeyPairGeneratorSpi extends KeyPairGeneratorAdapter implements + DSAKeyPairGenerator +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public DSSKeyPairGeneratorSpi() + { + super(Registry.DSS_KPG); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public void initialize(int keysize, SecureRandom random) + { + this.initialize(keysize, false, random); + } + + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + HashMap attributes = new HashMap(); + if (params != null) + { + if (!(params instanceof DSAParameterSpec)) + throw new InvalidAlgorithmParameterException( + "Parameters argument is not a non-null instance, or " + + "sub-instance, of java.security.spec.DSAParameterSpec"); + + attributes.put(DSSKeyPairGenerator.DSS_PARAMETERS, params); + } + + if (random != null) + { + attributes.put(DSSKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + } + + attributes.put(DSSKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + new Integer(Registry.ASN1_ENCODING_ID)); + try + { + adaptee.setup(attributes); + } + catch (IllegalArgumentException x) + { + InvalidAlgorithmParameterException y = + new InvalidAlgorithmParameterException(); + y.initCause(x); + throw y; + } + } + + // java.security.interfaces.DSAKeyPairGenerator interface implementation ----- + + public void initialize(DSAParams params, SecureRandom random) + throws InvalidParameterException + { + if (params == null || !(params instanceof DSAParameterSpec)) + throw new InvalidParameterException( + "Parameters argument is either null or is not an instance, or " + + "sub-instance, of java.security.spec.DSAParameterSpec"); + DSAParameterSpec spec = (DSAParameterSpec) params; + try + { + this.initialize((AlgorithmParameterSpec) spec, random); + } + catch (InvalidAlgorithmParameterException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + } + + public void initialize(int modlen, boolean genParams, SecureRandom random) + throws InvalidParameterException + { + HashMap attributes = new HashMap(); + attributes.put(DSSKeyPairGenerator.MODULUS_LENGTH, new Integer(modlen)); + if (random != null) + attributes.put(DSSKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(DSSKeyPairGenerator.USE_DEFAULTS, + Boolean.valueOf(!genParams)); + attributes.put(DSSKeyPairGenerator.STRICT_DEFAULTS, Boolean.TRUE); + attributes.put(DSSKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + new Integer(Registry.ASN1_ENCODING_ID)); + try + { + adaptee.setup(attributes); + } + catch (IllegalArgumentException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + } +} diff --git a/gnu/java/security/jce/sig/DSSParameters.java b/gnu/java/security/jce/sig/DSSParameters.java new file mode 100644 index 000000000..ba1f414fa --- /dev/null +++ b/gnu/java/security/jce/sig/DSSParameters.java @@ -0,0 +1,220 @@ +/* DSSParameters.java -- DSS parameters DAO + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.AlgorithmParametersSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.DSAParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.ArrayList; + +/** + * A JCE-specific Data Access Object (DAO) for DSS parameters. + */ +public class DSSParameters + extends AlgorithmParametersSpi +{ + /** + * A prime modulus, where 2L-1 < p < 2L + * for 512 <= L <= 1024 and L a multiple of + * 64. + */ + private BigInteger p; + + /** + * A prime divisor of p - 1, where 2159 < q + * < 2160. + */ + private BigInteger q; + + /** + * g = h(p-1)/q mod p, where h is any + * integer with 1 < h < p - 1 such that h + * (p-1)/q mod p > 1 (g has order q mod p + * ). + */ + private BigInteger g; + + // default 0-arguments constructor + + protected void engineInit(AlgorithmParameterSpec spec) + throws InvalidParameterSpecException + { + if (! (spec instanceof DSAParameterSpec)) + throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: " + + spec.getClass().getName()); + DSAParameterSpec dsaSpec = (DSAParameterSpec) spec; + p = dsaSpec.getP(); + q = dsaSpec.getQ(); + g = dsaSpec.getG(); + } + + /** + * Decodes the set of DSS parameters as per RFC-2459; i.e. the DER-encoded + * form of the following ASN.1 construct: + * + *

+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * 
+ */ + protected void engineInit(byte[] params) throws IOException + { + DERReader der = new DERReader(params); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + } + + protected void engineInit(byte[] params, String format) throws IOException + { + if (format != null) + { + format = format.trim(); + if (format.length() == 0) + throw new IOException("Format MUST NOT be an empty string"); + + if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME)) + throw new IOException("Unknown or unsupported format: " + format); + } + + engineInit(params); + } + + protected AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException + { + if (! paramSpec.isAssignableFrom(DSAParameterSpec.class)) + throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: " + + paramSpec.getName()); + return new DSAParameterSpec(p, q, g); + } + + /** + * Encodes the set of DSS parameters as per RFC-2459; i.e. as the DER-encoded + * form of the following ASN.1 construct: + * + *
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * 
+ */ + protected byte[] engineGetEncoded() throws IOException + { + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derQ = new DERValue(DER.INTEGER, q); + DERValue derG = new DERValue(DER.INTEGER, g); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derQ); + params.add(derG); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DERWriter.write(baos, derParams); + byte[] result = baos.toByteArray(); + + return result; + } + + protected byte[] engineGetEncoded(String format) throws IOException + { + if (format != null) + { + format = format.trim(); + if (format.length() == 0) + throw new IOException("Format MUST NOT be an empty string"); + + if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME)) + throw new IOException("Unknown or unsupported format: " + format); + } + + return engineGetEncoded(); + } + + protected String engineToString() + { + StringBuffer sb = new StringBuffer("p="); + if (p == null) + sb.append("???"); + else + sb.append("0x").append(p.toString(16)); + + sb.append(", q="); + if (q == null) + sb.append("???"); + else + sb.append("0x").append(q.toString(16)); + + sb.append(", g="); + if (g == null) + sb.append("???"); + else + sb.append("0x").append(g.toString(16)); + + return sb.toString(); + } +} diff --git a/gnu/java/security/jce/sig/DSSParametersGenerator.java b/gnu/java/security/jce/sig/DSSParametersGenerator.java new file mode 100644 index 000000000..09c138610 --- /dev/null +++ b/gnu/java/security/jce/sig/DSSParametersGenerator.java @@ -0,0 +1,125 @@ +/* DSSParametersGenerator.java -- JCE Adapter for a generator of DSS parameters + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairGenerator; +import gnu.java.security.key.dss.FIPS186; +import gnu.java.security.provider.Gnu; + +import java.math.BigInteger; +import java.security.AlgorithmParameterGeneratorSpi; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.DSAParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +/** + * A JCE Adapter for a generator of DSS parameters. + */ +public class DSSParametersGenerator + extends AlgorithmParameterGeneratorSpi +{ + private static final Provider GNU = new Gnu(); + + /** Size of the public modulus in bits. */ + private int modulusLength = -1; + + /** User specified source of randomness. */ + private SecureRandom rnd; + + /** Our concrete DSS parameters generator. */ + private FIPS186 fips; + + // default 0-arguments constructor + + protected void engineInit(int size, SecureRandom random) + { + if ((size % 64) != 0 || size < 512 || size > 1024) + throw new InvalidParameterException("Modulus size/length (in bits) MUST " + + "be a multiple of 64, greater than " + + "or equal to 512, and less than or " + + "equal to 1024"); + this.modulusLength = size; + this.rnd = random; + } + + protected void engineInit(AlgorithmParameterSpec spec, SecureRandom random) + throws InvalidAlgorithmParameterException + { + if (! (spec instanceof DSAParameterSpec)) + throw new InvalidAlgorithmParameterException("Wrong AlgorithmParameterSpec type: " + + spec.getClass().getName()); + DSAParameterSpec dsaSpec = (DSAParameterSpec) spec; + BigInteger p = dsaSpec.getP(); + int size = p.bitLength(); + this.engineInit(size, random); + } + + protected AlgorithmParameters engineGenerateParameters() + { + if (modulusLength < 1) + modulusLength = DSSKeyPairGenerator.DEFAULT_MODULUS_LENGTH; + + fips = new FIPS186(modulusLength, rnd); + BigInteger[] params = fips.generateParameters(); + BigInteger p = params[3]; + BigInteger q = params[2]; + BigInteger g = params[5]; + DSAParameterSpec spec = new DSAParameterSpec(p, q, g); + AlgorithmParameters result = null; + try + { + result = AlgorithmParameters.getInstance(Registry.DSS_KPG, GNU); + result.init(spec); + } + catch (NoSuchAlgorithmException ignore) + { + } + catch (InvalidParameterSpecException ignore) + { + } + return result; + } +} diff --git a/gnu/java/security/jce/sig/DSSRawSignatureSpi.java b/gnu/java/security/jce/sig/DSSRawSignatureSpi.java new file mode 100644 index 000000000..5573b39f3 --- /dev/null +++ b/gnu/java/security/jce/sig/DSSRawSignatureSpi.java @@ -0,0 +1,70 @@ +/* DSSRawSignatureSpi.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.dss.DSSSignatureRawCodec; + +/** + * The implementation of Service Provider Interface (SPI) adapter + * for the DSS (Digital Signature Standard) signature scheme, encoded and/or + * decoded in RAW format.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class DSSRawSignatureSpi extends SignatureAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public DSSRawSignatureSpi() + { + super(Registry.DSS_SIG, new DSSSignatureRawCodec()); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/sig/EncodedKeyFactory.java b/gnu/java/security/jce/sig/EncodedKeyFactory.java new file mode 100644 index 000000000..6c1a19abd --- /dev/null +++ b/gnu/java/security/jce/sig/EncodedKeyFactory.java @@ -0,0 +1,423 @@ +/* EncodedKeyFactory.java -- JCE Encoded key factory Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.key.rsa.GnuRSAPrivateKey; +import gnu.java.security.key.rsa.GnuRSAPublicKey; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHPrivateKeySpec; +import javax.crypto.spec.DHPublicKeySpec; + +/** + * A factory for keys encoded in either the X.509 format (for public keys) or + * the PKCS#8 format (for private keys). + */ +public class EncodedKeyFactory + extends KeyFactorySpi +{ + // implicit 0-arguments constructor + + // Class methods + // -------------------------------------------------------------------------- + + private static Object invokeConstructor(String className, Object[] params) + throws InvalidKeySpecException + { + Class clazz = getConcreteClass(className); + try + { + Constructor ctor = getConcreteCtor(clazz); + Object result = ctor.newInstance(params); + return result; + } + catch (InstantiationException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + catch (IllegalAccessException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(y); + throw y; + } + catch (InvocationTargetException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + private static Class getConcreteClass(String className) + throws InvalidKeySpecException + { + try + { + Class result = Class.forName(className); + return result; + } + catch (ClassNotFoundException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + private static Constructor getConcreteCtor(Class clazz) + throws InvalidKeySpecException + { + try + { + Constructor result = clazz.getConstructor(new Class[] {int.class, + BigInteger.class, + BigInteger.class, + BigInteger.class, + BigInteger.class}); + return result; + } + catch (NoSuchMethodException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + private static Object invokeValueOf(String className, byte[] encoded) + throws InvalidKeySpecException + { + Class clazz = getConcreteClass(className); + try + { + Method valueOf = getValueOfMethod(clazz); + Object result = valueOf.invoke(null, new Object[] { encoded }); + return result; + } + catch (IllegalAccessException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + catch (InvocationTargetException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + private static Method getValueOfMethod(Class clazz) + throws InvalidKeySpecException + { + try + { + Method result = clazz.getMethod("valueOf", new Class[] {byte[].class}); + return result; + } + catch (NoSuchMethodException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + // Instance methods + // -------------------------------------------------------------------------- + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DSAPublicKeySpec) + return decodeDSSPublicKey((DSAPublicKeySpec) keySpec); + + if (keySpec instanceof RSAPublicKeySpec) + return decodeRSAPublicKey((RSAPublicKeySpec) keySpec); + + if (keySpec instanceof DHPublicKeySpec) + return decodeDHPublicKey((DHPublicKeySpec) keySpec); + + if (! (keySpec instanceof X509EncodedKeySpec)) + throw new InvalidKeySpecException("Unsupported key specification"); + + byte[] input = ((X509EncodedKeySpec) keySpec).getEncoded(); + + // try DSS + try + { + return DSSPublicKey.valueOf(input); + } + catch (InvalidParameterException ignored) + { + } + + // try RSA + try + { + return GnuRSAPublicKey.valueOf(input); + } + catch (InvalidParameterException ignored) + { + } + + // try DH + return decodeDHPublicKey(input); + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DSAPrivateKeySpec) + return decodeDSSPrivateKey((DSAPrivateKeySpec) keySpec); + + if (keySpec instanceof RSAPrivateCrtKeySpec) + return decodeRSAPrivateKey((RSAPrivateCrtKeySpec) keySpec); + + if (keySpec instanceof DHPrivateKeySpec) + return decodeDHPrivateKey((DHPrivateKeySpec) keySpec); + + if (! (keySpec instanceof PKCS8EncodedKeySpec)) + throw new InvalidKeySpecException("Unsupported key specification"); + + byte[] input = ((PKCS8EncodedKeySpec) keySpec).getEncoded(); + + // try DSS + try + { + return DSSPrivateKey.valueOf(input); + } + catch (InvalidParameterException ignored) + { + } + + // try RSA + try + { + return GnuRSAPrivateKey.valueOf(input); + } + catch (InvalidParameterException ignored) + { + } + + // try DH + return decodeDHPrivateKey(input); + } + + protected KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof PublicKey + && Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat()) + && keySpec.isAssignableFrom(X509EncodedKeySpec.class)) + return new X509EncodedKeySpec(key.getEncoded()); + + if (key instanceof PrivateKey + && Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat()) + && keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) + return new PKCS8EncodedKeySpec(key.getEncoded()); + + throw new InvalidKeySpecException("Unsupported format or invalid key spec class"); + } + + protected Key engineTranslateKey(Key key) throws InvalidKeyException + { + throw new InvalidKeyException("Key translation not supported"); + } + + /** + * @param spec an instance of {@link DSAPublicKeySpec} to decode. + * @return an instance of {@link DSSPublicKey} constructed from the + * information in the designated key-specification. + */ + private DSSPublicKey decodeDSSPublicKey(DSAPublicKeySpec spec) + { + BigInteger p = spec.getP(); + BigInteger q = spec.getQ(); + BigInteger g = spec.getG(); + BigInteger y = spec.getY(); + return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); + } + + /** + * @param spec an instance of {@link RSAPublicKeySpec} to decode. + * @return an instance of {@link GnuRSAPublicKey} constructed from the + * information in the designated key-specification. + */ + private GnuRSAPublicKey decodeRSAPublicKey(RSAPublicKeySpec spec) + { + BigInteger n = spec.getModulus(); + BigInteger e = spec.getPublicExponent(); + return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e); + } + + /** + * @param spec an instance of {@link DHPublicKeySpec} to decode. + * @return an instance of a {@link DHPublicKey} constructed from the + * information in the designated key-specification. + * @throws InvalidKeySpecException if no concrete implementation of the + * {@link DHPublicKey} interface exists at run-time, or if an + * exception occurs during its instantiation. + */ + private DHPublicKey decodeDHPublicKey(DHPublicKeySpec spec) + throws InvalidKeySpecException + { + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + BigInteger y = spec.getY(); + Object[] params = new Object[] {new Integer(Registry.X509_ENCODING_ID), + null, p, g, y}; + Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPublicKey", + params); + return (DHPublicKey) obj; + } + + /** + * @param encoded the bytes to decode. + * @return an instance of a {@link DHPublicKey} constructed from the + * information in the designated key-specification. + * @throws InvalidKeySpecException if no concrete implementation of the + * {@link DHPublicKey} interface exists at run-time, or if an + * exception occurs during its instantiation. + */ + private DHPublicKey decodeDHPublicKey(byte[] encoded) + throws InvalidKeySpecException + { + Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPublicKey", + encoded); + return (DHPublicKey) obj; + } + + /** + * @param spec an instance of {@link DSAPrivateKeySpec} to decode. + * @return an instance of {@link DSSPrivateKey} constructed from the + * information in the designated key-specification. + */ + private PrivateKey decodeDSSPrivateKey(DSAPrivateKeySpec spec) + { + BigInteger p = spec.getP(); + BigInteger q = spec.getQ(); + BigInteger g = spec.getG(); + BigInteger x = spec.getX(); + return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); + } + + /** + * @param spec an instance of {@link RSAPrivateCrtKeySpec} to decode. + * @return an instance of {@link GnuRSAPrivateKey} constructed from the + * information in the designated key-specification. + */ + private PrivateKey decodeRSAPrivateKey(RSAPrivateCrtKeySpec spec) + { + BigInteger n = spec.getModulus(); + BigInteger e = spec.getPublicExponent(); + BigInteger d = spec.getPrivateExponent(); + BigInteger p = spec.getPrimeP(); + BigInteger q = spec.getPrimeQ(); + BigInteger dP = spec.getPrimeExponentP(); + BigInteger dQ = spec.getPrimeExponentQ(); + BigInteger qInv = spec.getCrtCoefficient(); + return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, + n, e, d, p, q, dP, dQ, qInv); + } + + /** + * @param spec an instance of {@link DHPrivateKeySpec} to decode. + * @return an instance of a {@link DHPrivateKey} constructed from the + * information in the designated key-specification. + * @throws InvalidKeySpecException if no concrete implementation of the + * {@link DHPrivateKey} interface exists at run-time, or if an + * exception occurs during its instantiation. + */ + private DHPrivateKey decodeDHPrivateKey(DHPrivateKeySpec spec) + throws InvalidKeySpecException + { + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + BigInteger x = spec.getX(); + Object[] params = new Object[] {new Integer(Registry.PKCS8_ENCODING_ID), + null, p, g, x}; + Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPrivateKey", + params); + return (DHPrivateKey) obj; + } + + /** + * @param encoded the bytes to decode. + * @return an instance of a {@link DHPrivateKey} constructed from the + * information in the designated key-specification. + * @throws InvalidKeySpecException if no concrete implementation of the + * {@link DHPrivateKey} interface exists at run-time, or if an + * exception occurs during its instantiation. + */ + private DHPrivateKey decodeDHPrivateKey(byte[] encoded) + throws InvalidKeySpecException + { + Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPrivateKey", + encoded); + return (DHPrivateKey) obj; + } +} diff --git a/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java b/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java new file mode 100644 index 000000000..29a10ecf9 --- /dev/null +++ b/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java @@ -0,0 +1,109 @@ +/* KeyPairGeneratorAdapter.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.key.KeyPairGeneratorFactory; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +/** + * The implementation of a generic {@link java.security.KeyPairGenerator} + * adapter class to wrap gnu.crypto keypair generator instances.

+ * + * This class defines the Service Provider Interface (SPI) for the + * {@link java.security.KeyPairGenerator} class, which is used to generate pairs + * of public and private keys.

+ * + * All the abstract methods in the {@link java.security.KeyPairGeneratorSpi} + * class are implemented by this class and all its sub-classes.

+ * + * In case the client does not explicitly initialize the KeyPairGenerator (via + * a call to an initialize() method), the GNU Crypto provider + * supplies (and document) default values to be used. For example, the GNU + * Crypto provider uses a default modulus size (keysize) of 1024 bits for + * the DSS (Digital Signature Standard) a.k.a DSA.

+ * + * @version $Revision: 1.3.2.1 $ + */ +public abstract class KeyPairGeneratorAdapter extends KeyPairGenerator +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Our underlying keypair instance. */ + protected IKeyPairGenerator adaptee; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial protected constructor. + * + * @param kpgName the canonical name of the keypair generator algorithm. + */ + protected KeyPairGeneratorAdapter(String kpgName) + { + super(kpgName); + + this.adaptee = KeyPairGeneratorFactory.getInstance(kpgName); + } + + // Class methods + // ------------------------------------------------------------------------- + + // java.security.KeyPairGeneratorSpi interface implementation + // ------------------------------------------------------------------------- + + public abstract void initialize(int keysize, SecureRandom random); + + public abstract void initialize(AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException; + + public KeyPair generateKeyPair() + { + return adaptee.generate(); + } +} diff --git a/gnu/java/security/jce/sig/MD2withRSA.java b/gnu/java/security/jce/sig/MD2withRSA.java new file mode 100644 index 000000000..353be2185 --- /dev/null +++ b/gnu/java/security/jce/sig/MD2withRSA.java @@ -0,0 +1,56 @@ +/* MD2WithRSA.java -- RSA PKCS1 with MD2 JCE signature Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; + +/** + * A JCE Adapter for the RSA PKCS1 (v1.5) signature with MD2 hash and X.509 + * encoding format. + */ +public class MD2withRSA + extends SignatureAdapter +{ + public MD2withRSA() + { + super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD2_HASH, + new RSAPKCS1V1_5SignatureX509Codec()); + } +} diff --git a/gnu/java/security/jce/sig/MD5withRSA.java b/gnu/java/security/jce/sig/MD5withRSA.java new file mode 100644 index 000000000..42c481b0a --- /dev/null +++ b/gnu/java/security/jce/sig/MD5withRSA.java @@ -0,0 +1,56 @@ +/* MD5withRSA.java -- RSA PKCS1 with MD5 JCE signature Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; + +/** + * A JCE Adapter for the RSA PKCS1 (v1.5) signature with MD5 hash and X.509 + * encoding format. + */ +public class MD5withRSA + extends SignatureAdapter +{ + public MD5withRSA() + { + super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD5_HASH, + new RSAPKCS1V1_5SignatureX509Codec()); + } +} diff --git a/gnu/java/security/jce/sig/RSAKeyFactory.java b/gnu/java/security/jce/sig/RSAKeyFactory.java new file mode 100644 index 000000000..fecf54cb8 --- /dev/null +++ b/gnu/java/security/jce/sig/RSAKeyFactory.java @@ -0,0 +1,265 @@ +/* RSAKeyFactory.java -- RSA key-factory JCE Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.key.rsa.GnuRSAPrivateKey; +import gnu.java.security.key.rsa.GnuRSAPublicKey; +import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec; +import gnu.java.security.key.rsa.RSAKeyPairX509Codec; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPrivateKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.security.spec.X509EncodedKeySpec; + +public class RSAKeyFactory + extends KeyFactorySpi +{ + // implicit 0-arguments constructor + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof RSAPublicKeySpec) + { + RSAPublicKeySpec spec = (RSAPublicKeySpec) keySpec; + BigInteger n = spec.getModulus(); + BigInteger e = spec.getPublicExponent(); + return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e); + } + + if (keySpec instanceof X509EncodedKeySpec) + { + X509EncodedKeySpec spec = (X509EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PublicKey result; + try + { + result = new RSAKeyPairX509Codec().decodePublicKey(encoded); + } + catch (RuntimeException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof RSAPrivateCrtKeySpec) + { + RSAPrivateCrtKeySpec spec = (RSAPrivateCrtKeySpec) keySpec; + BigInteger n = spec.getModulus(); + BigInteger e = spec.getPublicExponent(); + BigInteger d = spec.getPrivateExponent(); + BigInteger p = spec.getPrimeP(); + BigInteger q = spec.getPrimeQ(); + BigInteger dP = spec.getPrimeExponentP(); + BigInteger dQ = spec.getPrimeExponentQ(); + BigInteger qInv = spec.getCrtCoefficient(); + return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, + n, e, d, p, q, dP, dQ, qInv); + } + +// if (keySpec instanceof RSAPrivateKeySpec) +// { +// RSAPrivateKeySpec spec = (RSAPrivateKeySpec) keySpec; +// BigInteger n = spec.getModulus(); +// BigInteger d = spec.getPrivateExponent(); +// return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, +// n, null, d, null, null, null, null, null); +// } + + if (keySpec instanceof PKCS8EncodedKeySpec) + { + PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PrivateKey result; + try + { + result = new RSAKeyPairPKCS8Codec().decodePrivateKey(encoded); + } + catch (RuntimeException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + throw new InvalidKeySpecException("Unsupported (private) key specification"); + } + + protected KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof RSAPublicKey) + { + if (keySpec.isAssignableFrom(RSAPublicKeySpec.class)) + { + RSAPublicKey rsaKey = (RSAPublicKey) key; + BigInteger n = rsaKey.getModulus(); + BigInteger e = rsaKey.getPublicExponent(); + return new RSAPublicKeySpec(n, e); + } + + if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) + { + if (key instanceof GnuRSAPublicKey) + { + GnuRSAPublicKey rsaKey = (GnuRSAPublicKey) key; + byte[] encoded = rsaKey.getEncoded(Registry.X509_ENCODING_ID); + return new X509EncodedKeySpec(encoded); + } + + if (Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new X509EncodedKeySpec(encoded); + } + + throw new InvalidKeySpecException("Wrong key type or unsupported (public) key specification"); + } + + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + + if ((key instanceof RSAPrivateCrtKey) + && keySpec.isAssignableFrom(RSAPrivateCrtKeySpec.class)) + { + RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key; + BigInteger n = rsaKey.getModulus(); + BigInteger e = rsaKey.getPublicExponent(); + BigInteger d = rsaKey.getPrivateExponent(); + BigInteger p = rsaKey.getPrimeP(); + BigInteger q = rsaKey.getPrimeQ(); + BigInteger dP = rsaKey.getPrimeExponentP(); + BigInteger dQ = rsaKey.getPrimeExponentQ(); + BigInteger qInv = rsaKey.getCrtCoefficient(); + return new RSAPrivateCrtKeySpec(n, e, d, p, q, dP, dQ, qInv); + } + + if ((key instanceof RSAPrivateKey) + && keySpec.isAssignableFrom(RSAPrivateKeySpec.class)) + { + RSAPrivateKey rsaKey = (RSAPrivateKey) key; + BigInteger n = rsaKey.getModulus(); + BigInteger d = rsaKey.getPrivateExponent(); + return new RSAPrivateKeySpec(n, d); + } + + if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) + { + if (key instanceof GnuRSAPrivateKey) + { + GnuRSAPrivateKey rsaKey = (GnuRSAPrivateKey) key; + byte[] encoded = rsaKey.getEncoded(Registry.PKCS8_ENCODING_ID); + return new PKCS8EncodedKeySpec(encoded); + } + + if (Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new PKCS8EncodedKeySpec(encoded); + } + + throw new InvalidKeySpecException("Wrong key type or unsupported (private) key specification"); + } + + throw new InvalidKeySpecException("Wrong key type or unsupported key specification"); + } + + protected Key engineTranslateKey(Key key) throws InvalidKeyException + { + if ((key instanceof GnuRSAPublicKey) || (key instanceof GnuRSAPrivateKey)) + return key; + + if (key instanceof RSAPublicKey) + { + RSAPublicKey rsaKey = (RSAPublicKey) key; + BigInteger n = rsaKey.getModulus(); + BigInteger e = rsaKey.getPublicExponent(); + return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e); + } + + if (key instanceof RSAPrivateCrtKey) + { + RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key; + BigInteger n = rsaKey.getModulus(); + BigInteger e = rsaKey.getPublicExponent(); + BigInteger d = rsaKey.getPrivateExponent(); + BigInteger p = rsaKey.getPrimeP(); + BigInteger q = rsaKey.getPrimeQ(); + BigInteger dP = rsaKey.getPrimeExponentP(); + BigInteger dQ = rsaKey.getPrimeExponentQ(); + BigInteger qInv = rsaKey.getCrtCoefficient(); + return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, + n, e, d, p, q, dP, dQ, qInv); + } + +// if (key instanceof RSAPrivateKey) +// { +// RSAPrivateKey rsaKey = (RSAPrivateKey) key; +// BigInteger n = rsaKey.getModulus(); +// BigInteger d = rsaKey.getPrivateExponent(); +// return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, +// n, null, d, null, null, null, null, null); +// } + + throw new InvalidKeyException("Unsupported key type"); + } +} diff --git a/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java b/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java new file mode 100644 index 000000000..24dc7c501 --- /dev/null +++ b/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java @@ -0,0 +1,115 @@ +/* RSAKeyPairGeneratorSpi.java -- JCE RSA KeyPairGenerator Adapter + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.key.rsa.RSAKeyPairGenerator; + +import java.security.InvalidAlgorithmParameterException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.RSAKeyGenParameterSpec; +import java.util.HashMap; + +/** + * The implementation of a {@link java.security.KeyPairGenerator} adapter class + * to wrap gnu.crypto RSA keypair generator instances.

+ * + * In case the client does not explicitly initialize the KeyPairGenerator (via + * a call to an initialize() method), the GNU Crypto provider + * uses a default modulus size (keysize) of 1024 bits.

+ */ +public class RSAKeyPairGeneratorSpi extends KeyPairGeneratorAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RSAKeyPairGeneratorSpi() + { + super(Registry.RSA_KPG); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public void initialize(int keysize, SecureRandom random) + { + HashMap attributes = new HashMap(); + attributes.put(RSAKeyPairGenerator.MODULUS_LENGTH, new Integer(keysize)); + if (random != null) + { + attributes.put(RSAKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + } + + attributes.put(RSAKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + new Integer(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } + + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + HashMap attributes = new HashMap(); + if (params != null) + { + if (!(params instanceof RSAKeyGenParameterSpec)) + { + throw new InvalidAlgorithmParameterException("params"); + } + + attributes.put(RSAKeyPairGenerator.RSA_PARAMETERS, params); + } + + if (random != null) + { + attributes.put(RSAKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + } + + attributes.put(RSAKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + new Integer(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } +} diff --git a/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java b/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java new file mode 100644 index 000000000..d2e15f819 --- /dev/null +++ b/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java @@ -0,0 +1,69 @@ +/* RSAPSSRawSignatureSpi.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPSSSignatureRawCodec; + +/** + * The implementation of Service Provider Interface (SPI) adapter + * for the RSA-PSS signature scheme, encoded and/or decoded in RAW format.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class RSAPSSRawSignatureSpi extends SignatureAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RSAPSSRawSignatureSpi() + { + super(Registry.RSA_PSS_SIG, new RSAPSSSignatureRawCodec()); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/jce/sig/SHA160withDSS.java b/gnu/java/security/jce/sig/SHA160withDSS.java new file mode 100644 index 000000000..c55139f46 --- /dev/null +++ b/gnu/java/security/jce/sig/SHA160withDSS.java @@ -0,0 +1,54 @@ +/* SHA160withDSS.java -- JCE Adapter for DSS with SHA1 signatures + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.dss.DSSSignatureX509Codec; + +/** + * A JCE Adapter for providing X.509 formatted DSS with SHA1 signatures. + */ +public class SHA160withDSS + extends SignatureAdapter +{ + public SHA160withDSS() + { + super(Registry.DSS_SIG, new DSSSignatureX509Codec()); + } +} diff --git a/gnu/java/security/jce/sig/SHA160withRSA.java b/gnu/java/security/jce/sig/SHA160withRSA.java new file mode 100644 index 000000000..d3b2054e0 --- /dev/null +++ b/gnu/java/security/jce/sig/SHA160withRSA.java @@ -0,0 +1,56 @@ +/* SHA160withRSA.java -- RSA PKCS1 with SHA160 JCE signature Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; + +/** + * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA160 hash and X.509 + * encoding format. + */ +public class SHA160withRSA + extends SignatureAdapter +{ + public SHA160withRSA() + { + super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA160_HASH, + new RSAPKCS1V1_5SignatureX509Codec()); + } +} diff --git a/gnu/java/security/jce/sig/SHA256withRSA.java b/gnu/java/security/jce/sig/SHA256withRSA.java new file mode 100644 index 000000000..d21888b59 --- /dev/null +++ b/gnu/java/security/jce/sig/SHA256withRSA.java @@ -0,0 +1,56 @@ +/* SHA256withRSA.java -- RSA PKCS1 with SHA256 JCE signature Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; + +/** + * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA256 hash and X.509 + * encoding format. + */ +public class SHA256withRSA + extends SignatureAdapter +{ + public SHA256withRSA() + { + super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA256_HASH, + new RSAPKCS1V1_5SignatureX509Codec()); + } +} diff --git a/gnu/java/security/jce/sig/SHA384withRSA.java b/gnu/java/security/jce/sig/SHA384withRSA.java new file mode 100644 index 000000000..5495ec1ca --- /dev/null +++ b/gnu/java/security/jce/sig/SHA384withRSA.java @@ -0,0 +1,56 @@ +/* SHA384withRSA.java -- RSA PKCS1 with SHA384 JCE signature Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; + +/** + * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA384 hash and X.509 + * encoding format. + */ +public class SHA384withRSA + extends SignatureAdapter +{ + public SHA384withRSA() + { + super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA384_HASH, + new RSAPKCS1V1_5SignatureX509Codec()); + } +} diff --git a/gnu/java/security/jce/sig/SHA512withRSA.java b/gnu/java/security/jce/sig/SHA512withRSA.java new file mode 100644 index 000000000..f7632290a --- /dev/null +++ b/gnu/java/security/jce/sig/SHA512withRSA.java @@ -0,0 +1,56 @@ +/* SHA512withRSA.java -- RSA PKCS1 with SHA512 JCE signature Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; + +/** + * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA512 hash and X.509 + * encoding format. + */ +public class SHA512withRSA + extends SignatureAdapter +{ + public SHA512withRSA() + { + super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA512_HASH, + new RSAPKCS1V1_5SignatureX509Codec()); + } +} diff --git a/gnu/java/security/jce/sig/SignatureAdapter.java b/gnu/java/security/jce/sig/SignatureAdapter.java new file mode 100644 index 000000000..62ed9cc5f --- /dev/null +++ b/gnu/java/security/jce/sig/SignatureAdapter.java @@ -0,0 +1,258 @@ +/* SignatureAdapter.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.sig.BaseSignature; +import gnu.java.security.sig.ISignature; +import gnu.java.security.sig.ISignatureCodec; +import gnu.java.security.sig.SignatureFactory; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.SignatureSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; + +/** + * The implementation of a generic {@link java.security.Signature} adapter class + * to wrap gnu.crypto signature instances.

+ * + * This class defines the Service Provider Interface (SPI) for the + * {@link java.security.Signature} class, which provides the functionality of a + * digital signature algorithm. Digital signatures are used for authentication + * and integrity assurance of digital data.

+ * + * All the abstract methods in the {@link java.security.SignatureSpi} class are + * implemented by this class and all its sub-classes.

+ * + * All the implementations which subclass this object, and which are serviced by + * the GNU Crypto provider implement the {@link java.lang.Cloneable} interface.

+ * + * @version $Revision: 1.2.2.1 $ + */ +class SignatureAdapter extends SignatureSpi implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Our underlying signature instance. */ + private ISignature adaptee; + + /** Our underlying signature encoder/decoder engine. */ + private ISignatureCodec codec; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial protected constructor.

+ * + * @param sigName the canonical name of the signature scheme. + * @param codec the signature codec engine to use with this scheme. + */ + protected SignatureAdapter(String sigName, ISignatureCodec codec) + { + this(SignatureFactory.getInstance(sigName), codec); + } + + /** + * Private constructor for cloning purposes.

+ * + * @param adaptee a clone of the underlying signature scheme instance. + * @param codec the signature codec engine to use with this scheme. + */ + private SignatureAdapter(ISignature adaptee, ISignatureCodec codec) + { + super(); + + this.adaptee = adaptee; + this.codec = codec; + } + + // Class methods + // ------------------------------------------------------------------------- + + // java.security.SignatureSpi interface implementation + // ------------------------------------------------------------------------- + + public Object clone() + { + return new SignatureAdapter((ISignature) adaptee.clone(), codec); + } + + public void engineInitVerify(PublicKey publicKey) throws InvalidKeyException + { + HashMap attributes = new HashMap(); + attributes.put(BaseSignature.VERIFIER_KEY, publicKey); + try + { + adaptee.setupVerify(attributes); + } + catch (IllegalArgumentException x) + { + throw new InvalidKeyException(String.valueOf(x)); + } + } + + public void engineInitSign(PrivateKey privateKey) throws InvalidKeyException + { + HashMap attributes = new HashMap(); + attributes.put(BaseSignature.SIGNER_KEY, privateKey); + try + { + adaptee.setupSign(attributes); + } + catch (IllegalArgumentException x) + { + throw new InvalidKeyException(String.valueOf(x)); + } + } + + public void engineInitSign(PrivateKey privateKey, SecureRandom random) + throws InvalidKeyException + { + HashMap attributes = new HashMap(); + attributes.put(BaseSignature.SIGNER_KEY, privateKey); + attributes.put(BaseSignature.SOURCE_OF_RANDOMNESS, random); + try + { + adaptee.setupSign(attributes); + } + catch (IllegalArgumentException x) + { + throw new InvalidKeyException(String.valueOf(x)); + } + } + + public void engineUpdate(byte b) throws SignatureException + { + try + { + adaptee.update(b); + } + catch (IllegalStateException x) + { + throw new SignatureException(String.valueOf(x)); + } + } + + public void engineUpdate(byte[] b, int off, int len) + throws SignatureException + { + try + { + adaptee.update(b, off, len); + } + catch (IllegalStateException x) + { + throw new SignatureException(String.valueOf(x)); + } + } + + public byte[] engineSign() throws SignatureException + { + Object signature = null; + try + { + signature = adaptee.sign(); + } + catch (IllegalStateException x) + { + throw new SignatureException(String.valueOf(x)); + } + + byte[] result = codec.encodeSignature(signature); + return result; + } + + public int engineSign(byte[] outbuf, int offset, int len) + throws SignatureException + { + byte[] signature = this.engineSign(); + int result = signature.length; + if (result > len) + { + throw new SignatureException("len"); + } + + System.arraycopy(signature, 0, outbuf, offset, result); + return result; + } + + public boolean engineVerify(byte[] sigBytes) throws SignatureException + { + Object signature = codec.decodeSignature(sigBytes); + boolean result = false; + try + { + result = adaptee.verify(signature); + } + catch (IllegalStateException x) + { + throw new SignatureException(String.valueOf(x)); + } + + return result; + } + + // Deprecated. Replaced by engineSetParameter. + public void engineSetParameter(String param, Object value) + throws InvalidParameterException + { + throw new InvalidParameterException("deprecated"); + } + + public void engineSetParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException + { + } + + // Deprecated + public Object engineGetParameter(String param) + throws InvalidParameterException + { + throw new InvalidParameterException("deprecated"); + } +} diff --git a/gnu/java/security/key/IKeyPairCodec.java b/gnu/java/security/key/IKeyPairCodec.java new file mode 100644 index 000000000..4a234173f --- /dev/null +++ b/gnu/java/security/key/IKeyPairCodec.java @@ -0,0 +1,132 @@ +/* IKeyPairCodec.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import gnu.java.security.Registry; + +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + *

The visible methods of an object that knows how to encode and decode + * cryptographic asymmetric keypairs. Codecs are useful for (a) externalising + * public and private keys for storage and on-the-wire transmission, as well as + * (b) re-creating their internal Java representation from external sources.

+ * + * @version $Revision: 1.2.2.1 $ + */ +public interface IKeyPairCodec +{ + // Constants + // ------------------------------------------------------------------------- + + /** Constant identifying the Raw encoding format. */ + int RAW_FORMAT = Registry.RAW_ENCODING_ID; + + /** Constant identifying the X.509 encoding format. */ + int X509_FORMAT = Registry.X509_ENCODING_ID; + + /** Constant identifying the PKCS#8 encoding format. */ + int PKCS8_FORMAT = Registry.PKCS8_ENCODING_ID; + + /** + * Constant identifying the ASN.1 encoding format: a combined encoding + * of X.509 for public keys, and PKCS#8 for private ones. + */ + int ASN1_FORMAT = Registry.ASN1_ENCODING_ID; + + // Method(s) + // ------------------------------------------------------------------------- + + /** + *

Returns the unique identifier (within this library) of the format used + * to externalise public and private keys.

+ * + * @return the identifier of the format, the object supports. + */ + int getFormatID(); + + /** + *

Encodes an instance of a public key for storage or transmission purposes.

+ * + * @param key the non-null key to encode. + * @return a byte sequence representing the encoding of the designated key + * according to the format supported by this codec. + * @exception IllegalArgumentException if the designated key is not supported + * by this codec. + */ + byte[] encodePublicKey(PublicKey key); + + /** + *

Encodes an instance of a private key for storage or transmission purposes.

+ * + * @param key the non-null key to encode. + * @return a byte sequence representing the encoding of the designated key + * according to the format supported by this codec. + * @exception IllegalArgumentException if the designated key is not supported + * by this codec. + */ + byte[] encodePrivateKey(PrivateKey key); + + /** + *

Decodes an instance of an external public key into its native Java + * representation.

+ * + * @param input the source of the externalised key to decode. + * @return a concrete instance of a public key, reconstructed from the + * designated input. + * @exception IllegalArgumentException if the designated input does not + * contain a known representation of a public key for the format supported by + * the concrete codec. + */ + PublicKey decodePublicKey(byte[] input); + + /** + *

Decodes an instance of an external private key into its native Java + * representation.

+ * + * @param input the source of the externalised key to decode. + * @return a concrete instance of a private key, reconstructed from the + * designated input. + * @exception IllegalArgumentException if the designated input does not + * contain a known representation of a private key for the format supported + * by the concrete codec. + */ + PrivateKey decodePrivateKey(byte[] input); +} diff --git a/gnu/java/security/key/IKeyPairGenerator.java b/gnu/java/security/key/IKeyPairGenerator.java new file mode 100644 index 000000000..8287ec607 --- /dev/null +++ b/gnu/java/security/key/IKeyPairGenerator.java @@ -0,0 +1,82 @@ +/* IKeyPairGenerator.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import java.security.KeyPair; +import java.util.Map; + +/** + * The visible methods of every asymmetric keypair generator.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public interface IKeyPairGenerator +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + * Returns the canonical name of this keypair generator.

+ * + * @return the canonical name of this instance. + */ + String name(); + + /** + * [Re]-initialises this instance for use with a given set of attributes.

+ * + * @param attributes a map of name/value pairs to use for setting up the + * instance. + * @exception IllegalArgumentException if at least one of the mandatory + * attributes is missing or an invalid value was specified. + */ + void setup(Map attributes); + + /** + * Generates a new keypair based on the attributes used to configure the + * instance. + * + * @return a new keypair. + */ + KeyPair generate(); +} diff --git a/gnu/java/security/key/KeyPairCodecFactory.java b/gnu/java/security/key/KeyPairCodecFactory.java new file mode 100644 index 000000000..1a8b8aa03 --- /dev/null +++ b/gnu/java/security/key/KeyPairCodecFactory.java @@ -0,0 +1,362 @@ +/* KeyPairCodecFactory.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec; +import gnu.java.security.key.dss.DSSKeyPairRawCodec; +import gnu.java.security.key.dss.DSSKeyPairX509Codec; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.key.rsa.GnuRSAPrivateKey; +import gnu.java.security.key.rsa.GnuRSAPublicKey; +import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec; +import gnu.java.security.key.rsa.RSAKeyPairRawCodec; +import gnu.java.security.key.rsa.RSAKeyPairX509Codec; +import gnu.java.security.util.FormatUtil; + +import java.lang.reflect.Constructor; +import java.security.Key; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory class to instantiate key encoder/decoder instances. + */ +public class KeyPairCodecFactory +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private KeyPairCodecFactory() + { + super(); + } + + /** + * Returns the appropriate codec given a composed key-pair generator algorithm + * and an encoding format. A composed name is formed by the concatenation of + * the canonical key-pair algorithm name, the forward slash character + * / and the canonical name of the encoding format. + *

+ * IMPORTANT: For backward compatibility, when the encoding format + * name is missing, the Raw encoding format is assumed. When this is the case + * the trailing forward slash is discarded from the name. + * + * @param name the case-insensitive key codec name. + * @return an instance of the keypair codec, or null if none + * found. + */ + public static IKeyPairCodec getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + if (name.length() == 0) + return null; + + if (name.startsWith("/")) + return null; + + if (name.endsWith("/")) + return getInstance(name.substring(0, name.length() - 1), + Registry.RAW_ENCODING_ID); + + int i = name.indexOf("/"); + if (i == -1) + return getInstance(name, Registry.RAW_ENCODING_ID); + + String kpgName = name.substring(0, i); + String formatName = name.substring(i + 1); + return getInstance(kpgName, formatName); + } + + /** + * Returns an instance of a keypair codec given the canonical name of the + * key-pair algorithm, and the name of the encoding format to use when + * externalizing the keys. + * + * @param name the case-insensitive key-pair algorithm name. + * @param format the name of the encoding format to use when externalizing the + * keys generated by the key-pair algorithm. + * @return an instance of the key-pair codec, or null if none + * found. + */ + public static IKeyPairCodec getInstance(String name, String format) + { + int formatID = FormatUtil.getFormatID(format); + if (formatID == 0) + return null; + + return getInstance(name, formatID); + } + + /** + * Returns an instance of a keypair codec given the canonical name of the + * key-pair algorithm, and the identifier of the format to use when + * externalizing the keys. + * + * @param name the case-insensitive key-pair algorithm name. + * @param formatID the identifier of the format to use when externalizing the + * keys generated by the key-pair algorithm. + * @return an instance of the key-pair codec, or null if none + * found. + */ + public static IKeyPairCodec getInstance(String name, int formatID) + { + if (name == null) + return null; + + name = name.trim(); + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + return getRawCodec(name); + case Registry.X509_ENCODING_ID: + return getX509Codec(name); + case Registry.PKCS8_ENCODING_ID: + return getPKCS8Codec(name); + } + + return null; + } + + /** + * Returns an instance of a keypair codec given a key. + * + * @param key the key to encode. + * @return an instance of the keypair codec, or null if none + * found. + */ + public static IKeyPairCodec getInstance(Key key) + { + if (key == null) + return null; + + String format = key.getFormat(); + int formatID = FormatUtil.getFormatID(format); + if (formatID == 0) + return null; + + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + return getRawCodec(key); + case Registry.X509_ENCODING_ID: + return getX509Codec(key); + case Registry.PKCS8_ENCODING_ID: + return getPKCS8Codec(key); + } + + return null; + } + + /** + * Returns a {@link Set} of supported key-pair codec names. + * + * @return a {@link Set} of the names of supported key-pair codec (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(Registry.DSS_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME); + hs.add(Registry.DSS_KPG + "/" + Registry.X509_ENCODING_SORT_NAME); + hs.add(Registry.DSS_KPG + "/" + Registry.PKCS8_ENCODING_SHORT_NAME); + hs.add(Registry.RSA_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME); + hs.add(Registry.RSA_KPG + "/" + Registry.X509_ENCODING_SORT_NAME); + hs.add(Registry.RSA_KPG + "/" + Registry.PKCS8_ENCODING_SHORT_NAME); + hs.add(Registry.DH_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME); + hs.add(Registry.SRP_KPG + "/" + Registry.RAW_ENCODING_SHORT_NAME); + + names = Collections.unmodifiableSet(hs); + } + + return names; + } + + private static IKeyPairCodec makeInstance (String clazz) + { + try + { + Class c = Class.forName (clazz); + Constructor ctor = c.getConstructor (new Class[0]); + return (IKeyPairCodec) ctor.newInstance (new Object[0]); + } + catch (Exception x) + { + IllegalArgumentException iae = + new IllegalArgumentException ("strong crypto key codec not available: " + + clazz); + iae.initCause (x); + throw iae; + } + } + + private static boolean matches (Object o, String clazz) + { + try + { + Class c = Class.forName (clazz); + return c.isAssignableFrom (o.getClass ()); + } + catch (Exception x) + { + // Can't match. + return false; + } + } + + /** + * @param name the trimmed name of a key-pair algorithm. + * @return a Raw format codec for the designated key-pair algorithm, or + * null if none exists. + */ + private static IKeyPairCodec getRawCodec(String name) + { + IKeyPairCodec result = null; + if (name.equalsIgnoreCase(Registry.DSA_KPG) + || name.equals(Registry.DSS_KPG)) + result = new DSSKeyPairRawCodec(); + else if (name.equalsIgnoreCase(Registry.RSA_KPG)) + result = new RSAKeyPairRawCodec(); + else if (name.equalsIgnoreCase(Registry.DH_KPG)) + result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairRawCodec"); + else if (name.equalsIgnoreCase(Registry.SRP_KPG)) + result = makeInstance("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec"); + + return result; + } + + /** + * @param name the trimmed name of a key-pair algorithm. + * @return a X.509 format codec for the designated key-pair algorithm, or + * null if none exists. + */ + private static IKeyPairCodec getX509Codec(String name) + { + IKeyPairCodec result = null; + if (name.equalsIgnoreCase(Registry.DSA_KPG) + || name.equals(Registry.DSS_KPG)) + result = new DSSKeyPairX509Codec(); + else if (name.equalsIgnoreCase(Registry.RSA_KPG)) + result = new RSAKeyPairX509Codec(); + else if (name.equalsIgnoreCase(Registry.DH_KPG)) + result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairX509Codec"); + + return result; + } + + /** + * @param name the trimmed name of a key-pair algorithm. + * @return a PKCS#8 format codec for the designated key-pair algorithm, or + * null if none exists. + */ + private static IKeyPairCodec getPKCS8Codec(String name) + { + IKeyPairCodec result = null; + if (name.equalsIgnoreCase(Registry.DSA_KPG) + || name.equals(Registry.DSS_KPG)) + result = new DSSKeyPairPKCS8Codec(); + else if (name.equalsIgnoreCase(Registry.RSA_KPG)) + result = new RSAKeyPairPKCS8Codec(); + else if (name.equalsIgnoreCase(Registry.DH_KPG)) + result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec"); + + return result; + } + + /** + * @param key a {@link Key} for which we want to return a Raw codec. + * @return the Raw codec corresponding to the key, or null if + * none exists for this key. + */ + private static IKeyPairCodec getRawCodec(Key key) + { + IKeyPairCodec result = null; + if ((key instanceof DSSPublicKey) || (key instanceof DSSPrivateKey)) + result = new DSSKeyPairRawCodec(); + else if ((key instanceof GnuRSAPublicKey) + || (key instanceof GnuRSAPrivateKey)) + result = new RSAKeyPairRawCodec(); + else if (matches(key, "gnu.javax.crypto.key.dh.GnuDHPublicKey") + || matches(key, "gnu.javax.crypto.key.dh.GnuDHPrivateKey")) + result = makeInstance("gnu.javax.crypto.key.dh.DHKeyPairRawCodec"); + else if (matches(key, "gnu.javax.crypto.key.srp6.SRPPublicKey") + || matches(key, "gnu.javax.crypto.key.srp6.SRPPrivateKey")) + result = makeInstance("gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec"); + + return result; + } + + /** + * @param key a {@link Key} for which we want to return an X.509 codec. + * @return the X.509 codec corresponding to the key, or null if + * none exists for this key. + */ + private static IKeyPairCodec getX509Codec(Key key) + { + IKeyPairCodec result = null; + if (key instanceof DSSPublicKey) + result = new DSSKeyPairX509Codec(); + else if (key instanceof GnuRSAPublicKey) + result = new RSAKeyPairX509Codec(); + + return result; + } + + /** + * @param key a {@link Key} for which we want to return a PKCS#8 codec. + * @return the PKCS#8 codec corresponding to the key, or null if + * none exists for this key. + */ + private static IKeyPairCodec getPKCS8Codec(Key key) + { + IKeyPairCodec result = null; + if (key instanceof DSSPrivateKey) + result = new DSSKeyPairPKCS8Codec(); + else if (key instanceof GnuRSAPrivateKey) + result = new RSAKeyPairPKCS8Codec(); + + return result; + } +} diff --git a/gnu/java/security/key/KeyPairGeneratorFactory.java b/gnu/java/security/key/KeyPairGeneratorFactory.java new file mode 100644 index 000000000..2121489ca --- /dev/null +++ b/gnu/java/security/key/KeyPairGeneratorFactory.java @@ -0,0 +1,148 @@ +/* KeyPairGeneratorFactory.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairGenerator; +import gnu.java.security.key.rsa.RSAKeyPairGenerator; + +import java.lang.reflect.Constructor; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + *

A Factory to instantiate asymmetric keypair generators.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class KeyPairGeneratorFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private KeyPairGeneratorFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a keypair generator given its name.

+ * + * @param name the case-insensitive key generator name. + * @return an instance of the keypair generator, or null if none + * found. + */ + public static IKeyPairGenerator getInstance(String name) + { + if (name == null) + { + return null; + } + + name = name.trim(); + IKeyPairGenerator result = null; + if (name.equalsIgnoreCase(Registry.DSA_KPG) + || name.equals(Registry.DSS_KPG)) + { + result = new DSSKeyPairGenerator(); + } + else if (name.equalsIgnoreCase(Registry.RSA_KPG)) + { + result = new RSAKeyPairGenerator(); + } + else if (name.equalsIgnoreCase(Registry.DH_KPG)) + { + result = makeInstance ("gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator"); + } + else if (name.equalsIgnoreCase(Registry.SRP_KPG)) + { + result = makeInstance ("gnu.javax.crypto.key.srp6.SRPKeyPairGenerator"); + } + + return result; + } + + /** + *

Returns a {@link Set} of keypair generator names supported by this + * Factory. Those keypair generators may be used in conjunction with + * the digital signature schemes with appendix supported by this library.

+ * + * @return a {@link Set} of keypair generator names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(Registry.DSS_KPG); + hs.add(Registry.RSA_KPG); + hs.add(Registry.DH_KPG); + hs.add(Registry.SRP_KPG); + + return Collections.unmodifiableSet(hs); + } + + private static IKeyPairGenerator makeInstance (String clazz) + { + try + { + Class c = Class.forName (clazz); + Constructor ctor = c.getConstructor (new Class[0]); + return (IKeyPairGenerator) ctor.newInstance (new Object[0]); + } + catch (Exception x) + { + IllegalArgumentException iae = + new IllegalArgumentException ("strong crypto key pair generator not available: " + + clazz); + iae.initCause (x); + throw iae; + } + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/key/dss/DSSKey.java b/gnu/java/security/key/dss/DSSKey.java new file mode 100644 index 000000000..6e60c3e84 --- /dev/null +++ b/gnu/java/security/key/dss/DSSKey.java @@ -0,0 +1,182 @@ +/* DSSKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Registry; +import gnu.java.security.util.FormatUtil; + +import java.math.BigInteger; +import java.security.Key; +import java.security.interfaces.DSAKey; +import java.security.interfaces.DSAParams; +import java.security.spec.DSAParameterSpec; + +/** + *

A base asbtract class for both public and private DSS (Digital Signature + * Standard) keys. It encapsulates the three DSS numbers: p, + * q and g.

+ * + *

According to the JDK, cryptographic Keys all have a format. + * The format used in this implementation is called Raw, and basically + * consists of the raw byte sequences of algorithm parameters. The exact order + * of the byte sequences and the implementation details are given in each of + * the relevant getEncoded() methods of each of the private and + * public keys.

+ * + * @version $Revision: 1.4.2.1 $ + * @see DSSPrivateKey#getEncoded + * @see DSSPublicKey#getEncoded + */ +public abstract class DSSKey implements Key, DSAKey +{ + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * A prime modulus, where 2L-1 < p < 2L + * for 512 <= L <= 1024 and L a multiple of + * 64. + */ + protected final BigInteger p; + + /** + * A prime divisor of p - 1, where 2159 < q + * < 2160. + */ + protected final BigInteger q; + + /** + * g = h(p-1)/q mod p, where h is any + * integer with 1 < h < p - 1 such that h + * (p-1)/q mod p > 1 (g has order q mod p + * ). + */ + protected final BigInteger g; + + /** + * Identifier of the default encoding format to use when externalizing the + * key material. + */ + protected final int defaultFormat; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial protected constructor. + * + * @param defaultFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param p the DSS parameter p. + * @param q the DSS parameter q. + * @param g the DSS parameter g. + */ + protected DSSKey(int defaultFormat, BigInteger p, BigInteger q, BigInteger g) + { + super(); + + this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID + : defaultFormat; + this.p = p; + this.q = q; + this.g = g; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.interfaces.DSAKey interface implementation ---------------- + + public DSAParams getParams() + { + return new DSAParameterSpec(p, q, g); + } + + // java.security.Key interface implementation ------------------------------ + + public String getAlgorithm() + { + return Registry.DSS_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(defaultFormat); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + // Other instance methods -------------------------------------------------- + + /** + *

Returns true if the designated object is an instance of + * {@link DSAKey} and has the same DSS (Digital Signature Standard) parameter + * values as this one.

+ * + * @param obj the other non-null DSS key to compare to. + * @return true if the designated object is of the same type and + * value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (!(obj instanceof DSAKey)) + { + return false; + } + DSAKey that = (DSAKey) obj; + return p.equals(that.getParams().getP()) + && q.equals(that.getParams().getQ()) + && g.equals(that.getParams().getG()); + } + + // abstract methods to be implemented by subclasses ------------------------ + + public abstract byte[] getEncoded(int format); +} diff --git a/gnu/java/security/key/dss/DSSKeyPairGenerator.java b/gnu/java/security/key/dss/DSSKeyPairGenerator.java new file mode 100644 index 000000000..5aa746147 --- /dev/null +++ b/gnu/java/security/key/dss/DSSKeyPairGenerator.java @@ -0,0 +1,445 @@ +/* DSSKeyPairGenerator.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Registry; +import gnu.java.security.hash.Sha160; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.io.PrintWriter; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.DSAParameterSpec; +import java.util.Map; + +/** + *

A key-pair generator for asymetric keys to use in conjunction with the DSS + * (Digital Signature Standard).

+ * + * References:
+ * Digital Signature + * Standard (DSS), Federal Information Processing Standards Publication 186. + * National Institute of Standards and Technology. + */ +public class DSSKeyPairGenerator implements IKeyPairGenerator +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "dss"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 5; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The BigInteger constant 2. */ + private static final BigInteger TWO = new BigInteger("2"); + + /** Property name of the length (Integer) of the modulus (p) of a DSS key. */ + public static final String MODULUS_LENGTH = "gnu.crypto.dss.L"; + + /** + * Property name of the Boolean indicating wether or not to use default pre- + * computed values of p, q and g for + * a given modulus length. The ultimate behaviour of this generator with + * regard to using pre-computed parameter sets will depend on the value of + * this property and of the following one {@link #STRICT_DEFAULTS}: + * + *
    + *
  1. If this property is {@link Boolean#FALSE} then this generator + * will accept being setup for generating parameters for any modulus length + * provided the modulus length is between 512 and + * 1024, and is of the form 512 + 64 * n. In + * addition, a new paramter set will always be generated; i.e. no pre- + * computed values are used.
  2. + * + *
  3. If this property is {@link Boolean#TRUE} and the value of + * {@link #STRICT_DEFAULTS} is also {@link Boolean#TRUE} then this generator + * will only accept being setup for generating parameters for modulus + * lengths of 512, 768 and 1024. Any + * other value, of the modulus length, even if between 512 and + * 1024, and of the form 512 + 64 * n, will cause + * an {@link IllegalArgumentException} to be thrown. When those modulus + * length (512, 768, and 1024) are + * specified, the paramter set is always the same.
  4. + * + *
  5. Finally, if this property is {@link Boolean#TRUE} and the value of + * {@link #STRICT_DEFAULTS} is {@link Boolean#FALSE} then this generator + * will behave as in point 1 above, except that it will use pre-computed + * values when possible; i.e. the modulus length is one of 512, + * 768, or 1024.
  6. + *
+ * + * The default value of this property is {@link Boolean#TRUE}. + */ + public static final String USE_DEFAULTS = "gnu.crypto.dss.use.defaults"; + + /** + * Property name of the Boolean indicating wether or not to generate new + * parameters, even if the modulus length L is not one of the pre- + * computed defaults (value {@link Boolean#FALSE}), or throw an exception + * (value {@link Boolean#TRUE}) -- the exception in this case is an + * {@link IllegalArgumentException}. The default value for this property is + * {@link Boolean#FALSE}. The ultimate behaviour of this generator will + * depend on the values of this and {@link #USE_DEFAULTS} properties -- see + * {@link #USE_DEFAULTS} for more information. + */ + public static final String STRICT_DEFAULTS = "gnu.crypto.dss.strict.defaults"; + + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dss.prng"; + + /** + * Property name of an optional {@link DSAParameterSpec} instance to use for + * this generator's p, q, and g values. + * The default is to generate these values or use pre-computed ones, + * depending on the value of the USE_DEFAULTS attribute. + */ + public static final String DSS_PARAMETERS = "gnu.crypto.dss.params"; + + /** + * Property name of the preferred encoding format to use when externalizing + * generated instance of key-pairs from this generator. The property is taken + * to be an {@link Integer} that encapsulates an encoding format identifier. + */ + public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dss.encoding"; + + /** Default value for the modulus length. */ + public static final int DEFAULT_MODULUS_LENGTH = 1024; + + /** Default encoding format to use when none was specified. */ + private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID; + + /** Initial SHS context. */ + private static final int[] T_SHS = new int[] { 0x67452301, 0xEFCDAB89, + 0x98BADCFE, 0x10325476, + 0xC3D2E1F0 }; + + // from jdk1.3.1/docs/guide/security/CryptoSpec.html#AppB + public static final DSAParameterSpec KEY_PARAMS_512 = new DSAParameterSpec( + new BigInteger( + "fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae" + + "01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", + 16), + new BigInteger( + "962eddcc369cba8ebb260ee6b6a126d9346e38c5", + 16), + new BigInteger( + "678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e" + + "35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", + 16)); + + public static final DSAParameterSpec KEY_PARAMS_768 = new DSAParameterSpec( + new BigInteger( + "e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d8901419" + + "22d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d77" + + "7d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", + 16), + new BigInteger( + "9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", + 16), + new BigInteger( + "30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4" + + "dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d8" + + "3c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", + 16)); + + public static final DSAParameterSpec KEY_PARAMS_1024 = new DSAParameterSpec( + new BigInteger( + "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669" + + "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7" + + "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb" + + "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", + 16), + new BigInteger( + "9760508f15230bccb292b982a2eb840bf0581cf5", + 16), + new BigInteger( + "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267" + + "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1" + + "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b" + + "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", + 16)); + + private static final BigInteger TWO_POW_160 = TWO.pow(160); + + /** The length of the modulus of DSS keys generated by this instance. */ + private int L; + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + private BigInteger seed; + + private BigInteger counter; + + private BigInteger p; + + private BigInteger q; + + private BigInteger e; + + private BigInteger g; + + private BigInteger XKEY; + + /** Our default source of randomness. */ + private PRNG prng = null; + + /** Preferred encoding format of generated keys. */ + private int preferredFormat; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.key.IKeyPairGenerator interface implementation --------------- + + public String name() + { + return Registry.DSS_KPG; + } + + /** + *

Configures this instance.

+ * + * @param attributes the map of name/value pairs to use. + * @exception IllegalArgumentException if the designated MODULUS_LENGTH + * value is not greater than 512, less than 1024 and not of the form + * 512 + 64j. + */ + public void setup(Map attributes) + { + // find out the modulus length + Integer l = (Integer) attributes.get(MODULUS_LENGTH); + L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue()); + if ((L % 64) != 0 || L < 512 || L > 1024) + throw new IllegalArgumentException(MODULUS_LENGTH); + + // should we use the default pre-computed params? + Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS); + if (useDefaults == null) + { + useDefaults = Boolean.TRUE; + } + + Boolean strictDefaults = (Boolean) attributes.get(STRICT_DEFAULTS); + if (strictDefaults == null) + strictDefaults = Boolean.FALSE; + + // are we given a set of DSA params or we shall use/generate our own? + DSAParameterSpec params = (DSAParameterSpec) attributes.get(DSS_PARAMETERS); + if (params != null) + { + p = params.getP(); + q = params.getQ(); + g = params.getG(); + } + else if (useDefaults.equals(Boolean.TRUE)) + { + switch (L) + { + case 512: + p = KEY_PARAMS_512.getP(); + q = KEY_PARAMS_512.getQ(); + g = KEY_PARAMS_512.getG(); + break; + case 768: + p = KEY_PARAMS_768.getP(); + q = KEY_PARAMS_768.getQ(); + g = KEY_PARAMS_768.getG(); + break; + case 1024: + p = KEY_PARAMS_1024.getP(); + q = KEY_PARAMS_1024.getQ(); + g = KEY_PARAMS_1024.getG(); + break; + default: + if (strictDefaults.equals(Boolean.TRUE)) + throw new IllegalArgumentException( + "Does not provide default parameters for " + L + + "-bit modulus length"); + else + { + p = null; + q = null; + g = null; + } + } + } + else + { + p = null; + q = null; + g = null; + } + + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + + // what is the preferred encoding format + Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT); + preferredFormat = formatID == null + ? DEFAULT_ENCODING_FORMAT + : formatID.intValue(); + + // set the seed-key + byte[] kb = new byte[20]; // we need 160 bits of randomness + nextRandomBytes(kb); + XKEY = new BigInteger(1, kb).setBit(159).setBit(0); + } + + public KeyPair generate() + { + if (p == null) + { + BigInteger[] params = new FIPS186(L, rnd).generateParameters(); + seed = params[FIPS186.DSA_PARAMS_SEED]; + counter = params[FIPS186.DSA_PARAMS_COUNTER]; + q = params[FIPS186.DSA_PARAMS_Q]; + p = params[FIPS186.DSA_PARAMS_P]; + e = params[FIPS186.DSA_PARAMS_E]; + g = params[FIPS186.DSA_PARAMS_G]; + if (DEBUG && debuglevel > 0) + { + debug("seed: " + seed.toString(16)); + debug("counter: " + counter.intValue()); + debug("q: " + q.toString(16)); + debug("p: " + p.toString(16)); + debug("e: " + e.toString(16)); + debug("g: " + g.toString(16)); + } + } + + BigInteger x = nextX(); + BigInteger y = g.modPow(x, p); + + PublicKey pubK = new DSSPublicKey(preferredFormat, p, q, g, y); + PrivateKey secK = new DSSPrivateKey(preferredFormat, p, q, g, x); + + return new KeyPair(pubK, secK); + } + + // Other instance methods -------------------------------------------------- + + /** + *

This method applies the following algorithm described in 3.1 of + * FIPS-186:

+ * + *
    + *
  1. XSEED = optional user input.
  2. + *
  3. XVAL = (XKEY + XSEED) mod 2b.
  4. + *
  5. x = G(t, XVAL) mod q.
  6. + *
  7. XKEY = (1 + XKEY + x) mod 2b.
  8. + *
+ * + *

Where b is the length of a secret b-bit seed-key (XKEY).

+ * + *

Note that in this implementation, XSEED, the optional user input, is + * always zero.

+ */ + private synchronized BigInteger nextX() + { + byte[] xk = XKEY.toByteArray(); + byte[] in = new byte[64]; // 512-bit block for SHS + System.arraycopy(xk, 0, in, 0, xk.length); + + int[] H = Sha160.G(T_SHS[0], T_SHS[1], T_SHS[2], T_SHS[3], T_SHS[4], in, 0); + byte[] h = new byte[20]; + for (int i = 0, j = 0; i < 5; i++) + { + h[j++] = (byte) (H[i] >>> 24); + h[j++] = (byte) (H[i] >>> 16); + h[j++] = (byte) (H[i] >>> 8); + h[j++] = (byte) H[i]; + } + BigInteger result = new BigInteger(1, h).mod(q); + XKEY = XKEY.add(result).add(BigInteger.ONE).mod(TWO_POW_160); + + return result; + } + + /** + *

Fills the designated byte array with random data.

+ * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java b/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java new file mode 100644 index 000000000..30e30bd14 --- /dev/null +++ b/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java @@ -0,0 +1,235 @@ +/* DSSKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; +import gnu.java.security.util.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +/** + * An implementation of an {@link IKeyPairCodec} that knows how to encode / + * decode PKCS#8 ASN.1 external representation of DSS private keys. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class DSSKeyPairPKCS8Codec + implements IKeyPairCodec +{ + private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return PKCS8_FORMAT; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePublicKey(PublicKey key) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * Returns the PKCS#8 ASN.1 PrivateKeyInfo representation of a DSA + * private key. The ASN.1 specification is as follows: + * + *
+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * 
+ * + * @return the DER encoded form of the ASN.1 representation of the + * PrivateKeyInfo field in an X.509 certificate. + * @throw InvalidParameterException if an error occurs during the marshalling + * process. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof DSSPrivateKey)) + throw new InvalidParameterException("Wrong key type"); + + DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID); + + DSSPrivateKey pk = (DSSPrivateKey) key; + BigInteger p = pk.getParams().getP(); + BigInteger q = pk.getParams().getQ(); + BigInteger g = pk.getParams().getG(); + BigInteger x = pk.getX(); + + ArrayList params = new ArrayList(3); + params.add(new DERValue(DER.INTEGER, p)); + params.add(new DERValue(DER.INTEGER, q)); + params.add(new DERValue(DER.INTEGER, g)); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, Util.trim(x)); + + ArrayList pki = new ArrayList(3); + pki.add(derVersion); + pki.add(derAlgorithmID); + pki.add(derPrivateKey); + DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derPKI); + result = baos.toByteArray(); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(e); + throw y; + } + + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PublicKey decodePublicKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DSS + * {@link PrivateKey} instance. MUST NOT be null. + * @return a new instance of a {@link DSSPrivateKey} decoded from the + * PrivateKeyInfo material fed as input. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger version, p, q, g, x; + DERReader der = new DERReader(input); + try + { + DERValue derPKI = der.read(); + DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field"); + + DERValue derVersion = der.read(); + if (! (derVersion.getValue() instanceof BigInteger)) + throw new InvalidParameterException("Wrong Version field"); + + version = (BigInteger) derVersion.getValue(); + if (version.compareTo(BigInteger.ZERO) != 0) + throw new InvalidParameterException("Unexpected Version: " + version); + + DERValue derAlgoritmID = der.read(); + DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DSA_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + + val = der.read(); + byte[] xBytes = (byte[]) val.getValue(); + x = new BigInteger(1, xBytes); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(e); + throw y; + } + + return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); + } +} diff --git a/gnu/java/security/key/dss/DSSKeyPairRawCodec.java b/gnu/java/security/key/dss/DSSKeyPairRawCodec.java new file mode 100644 index 000000000..1d4a0a7d7 --- /dev/null +++ b/gnu/java/security/key/dss/DSSKeyPairRawCodec.java @@ -0,0 +1,383 @@ +/* DSSKeyPairRawCodec.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + *

An object that implements the {@link IKeyPairCodec} operations for the + * Raw format to use with DSS keypairs.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class DSSKeyPairRawCodec implements IKeyPairCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.keys.IKeyPairCodec interface implementation ------------------ + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + *

Returns the encoded form of the designated DSS (Digital Signature + * Standard) public key according to the Raw format supported by + * this library.

+ * + *

The Raw format for a DSA public key, in this implementation, is + * a byte sequence consisting of the following:

+ *
    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DSS_PUBLIC_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the DSA parameter + * p in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter + * p,
  8. + *
  9. 4-byte count of following bytes representing the DSA parameter + * q,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter + * q,
  12. + *
  13. 4-byte count of following bytes representing the DSA parameter + * g,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter + * g,
  16. + *
  17. 4-byte count of following bytes representing the DSA parameter + * y,
  18. + *
  19. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter + * y,
  20. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not a DSS + * (Digital Signature Standard) one. + * @see Registry#MAGIC_RAW_DSS_PUBLIC_KEY + */ + public byte[] encodePublicKey(PublicKey key) + { + if (!(key instanceof DSSPublicKey)) + { + throw new IllegalArgumentException("key"); + } + + DSSPublicKey dssKey = (DSSPublicKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]); + baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[1]); + baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[2]); + baos.write(Registry.MAGIC_RAW_DSS_PUBLIC_KEY[3]); + + // version + baos.write(0x01); + + // p + byte[] buffer = dssKey.getParams().getP().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // q + buffer = dssKey.getParams().getQ().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // g + buffer = dssKey.getParams().getG().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // y + buffer = dssKey.getY().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + public PublicKey decodePublicKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0] + || k[1] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[1] + || k[2] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[2] + || k[3] != Registry.MAGIC_RAW_DSS_PUBLIC_KEY[3]) + { + throw new IllegalArgumentException("magic"); + } + + // version + if (k[4] != 0x01) + { + throw new IllegalArgumentException("version"); + } + int i = 5; + + int l; + byte[] buffer; + + // p + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + + // q + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + + // g + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + + // y + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger y = new BigInteger(1, buffer); + + return new DSSPublicKey(p, q, g, y); + } + + /** + *

Returns the encoded form of the designated DSS (Digital Signature + * Standard) private key according to the Raw format supported by + * this library.

+ * + *

The Raw format for a DSA private key, in this implementation, is + * a byte sequence consisting of the following:

+ *
    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DSS_PRIVATE_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the DSA parameter + * p in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter + * p,
  8. + *
  9. 4-byte count of following bytes representing the DSA parameter + * q,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter + * q,
  12. + *
  13. 4-byte count of following bytes representing the DSA parameter + * g,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter + * g,
  16. + *
  17. 4-byte count of following bytes representing the DSA parameter + * x,
  18. + *
  19. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSA parameter + * x,
  20. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not a DSS + * (Digital Signature Standard) one. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (!(key instanceof DSSPrivateKey)) + { + throw new IllegalArgumentException("key"); + } + + DSSPrivateKey dssKey = (DSSPrivateKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]); + baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[1]); + baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[2]); + baos.write(Registry.MAGIC_RAW_DSS_PRIVATE_KEY[3]); + + // version + baos.write(0x01); + + // p + byte[] buffer = dssKey.getParams().getP().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // q + buffer = dssKey.getParams().getQ().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // g + buffer = dssKey.getParams().getG().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // x + buffer = dssKey.getX().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + public PrivateKey decodePrivateKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0] + || k[1] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[1] + || k[2] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[2] + || k[3] != Registry.MAGIC_RAW_DSS_PRIVATE_KEY[3]) + { + throw new IllegalArgumentException("magic"); + } + + // version + if (k[4] != 0x01) + { + throw new IllegalArgumentException("version"); + } + int i = 5; + + int l; + byte[] buffer; + + // p + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + + // q + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + + // g + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + + // x + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger x = new BigInteger(1, buffer); + + return new DSSPrivateKey(p, q, g, x); + } +} diff --git a/gnu/java/security/key/dss/DSSKeyPairX509Codec.java b/gnu/java/security/key/dss/DSSKeyPairX509Codec.java new file mode 100644 index 000000000..516ef92af --- /dev/null +++ b/gnu/java/security/key/dss/DSSKeyPairX509Codec.java @@ -0,0 +1,248 @@ +/* DSSKeyPairX509Codec.java -- X.509 Encoding/Decoding handler + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +/** + * An implementation of an {@link IKeyPairCodec} that knows how to encode / + * decode X.509 ASN.1 external representation of DSS public keys. + */ +public class DSSKeyPairX509Codec + implements IKeyPairCodec +{ + private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return X509_FORMAT; + } + + /** + * Returns the X.509 ASN.1 SubjectPublicKeyInfo representation of a + * DSA public key. The ASN.1 specification, as defined in RFC-3280, and + * RFC-2459, is as follows: + * + *
+   *   SubjectPublicKeyInfo ::= SEQUENCE {
+   *     algorithm         AlgorithmIdentifier,
+   *     subjectPublicKey  BIT STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * 
+ * + *

The subjectPublicKey field, which is a BIT STRING, contains the + * DER-encoded form of the DSA public key as an INTEGER.

+ * + *
+   *       DSAPublicKey ::= INTEGER -- public key, Y
+   * 
+ * + * @param key the {@link PublicKey} instance to encode. MUST be an instance of + * {@link DSSPublicKey}. + * @return the ASN.1 representation of the SubjectPublicKeyInfo in an + * X.509 certificate. + * @throw InvalidParameterException if key is not an instance + * of {@link DSSPublicKey} or if an exception occurs during the + * marshalling process. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof DSSPublicKey)) + throw new InvalidParameterException("key"); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID); + + DSSPublicKey dssKey = (DSSPublicKey) key; + BigInteger p = dssKey.getParams().getP(); + BigInteger q = dssKey.getParams().getQ(); + BigInteger g = dssKey.getParams().getG(); + BigInteger y = dssKey.getY(); + + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derQ = new DERValue(DER.INTEGER, q); + DERValue derG = new DERValue(DER.INTEGER, g); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derQ); + params.add(derG); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + DERValue derDSAPublicKey = new DERValue(DER.INTEGER, y); + byte[] yBytes = derDSAPublicKey.getEncoded(); + DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes)); + + ArrayList spki = new ArrayList(2); + spki.add(derAlgorithmID); + spki.add(derSPK); + DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derSPKI); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(); + e.initCause(x); + throw e; + } + + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + throw new InvalidParameterException("Wrong format for private keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DSS + * {@link PublicKey} instance. MUST NOT be null. + * @return a new instance of a {@link DSSPublicKey} decoded from the + * SubjectPublicKeyInfo material in an X.509 certificate. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PublicKey decodePublicKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger p, g, q, y; + DERReader der = new DERReader(input); + try + { + DERValue derSPKI = der.read(); + DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); + + DERValue derAlgorithmID = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + if (! (derOID.getValue() instanceof OID)) + throw new InvalidParameterException("Wrong Algorithm field"); + + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DSA_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + + val = der.read(); + if (! (val.getValue() instanceof BitString)) + throw new InvalidParameterException("Wrong SubjectPublicKey field"); + + byte[] yBytes = ((BitString) val.getValue()).toByteArray(); + + DERReader dsaPub = new DERReader(yBytes); + val = dsaPub.read(); + DerUtil.checkIsBigInteger(val, "Wrong Y field"); + y = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(); + e.initCause(x); + throw e; + } + + return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for private keys"); + } +} diff --git a/gnu/java/security/key/dss/DSSPrivateKey.java b/gnu/java/security/key/dss/DSSPrivateKey.java new file mode 100644 index 000000000..6ace60207 --- /dev/null +++ b/gnu/java/security/key/dss/DSSPrivateKey.java @@ -0,0 +1,201 @@ +/* DSSPrivateKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.interfaces.DSAPrivateKey; + +/** + *

An object that embodies a DSS (Digital Signature Standard) private key.

+ * + * @version $Revision: 1.2.2.1 $ + * @see #getEncoded + */ +public class DSSPrivateKey extends DSSKey implements PrivateKey, DSAPrivateKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + *

A randomly or pseudorandomly generated integer with 0 < x < + * q.

+ */ + private final BigInteger x; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Convenience constructor. Calls the constructor with 5 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param x the private key part. + */ + public DSSPrivateKey(BigInteger p, BigInteger q, BigInteger g, BigInteger x) + { + this(Registry.RAW_ENCODING_ID, p, q, g, x); + } + + /** + * Constructs a new instance of a DSSPrivateKey given the + * designated arguments. + * + * @param preferredFormat the indetifier of the preferred encoding format to + * use when externalizing this key. + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param x the private key part. + */ + public DSSPrivateKey(int preferredFormat, BigInteger p, BigInteger q, + BigInteger g, BigInteger x) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID + : preferredFormat, + p, q, g); + + this.x = x; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * A class method that takes the output of the encodePrivateKey() + * method of a DSS keypair codec object (an instance implementing + * {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs + * an instance of this object. + * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an + * instance of this object. + * @exception IllegalArgumentException if the byte sequence does not represent + * a valid encoding of an instance of this object. + */ + public static DSSPrivateKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]) + try + { + return (DSSPrivateKey) new DSSKeyPairRawCodec().decodePrivateKey(k); + } + catch (IllegalArgumentException ignored) + { + } + + // try PKCS#8 codec + return (DSSPrivateKey) new DSSKeyPairPKCS8Codec().decodePrivateKey(k); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.interfaces.DSAPrivateKey interface implementation --------- + + public BigInteger getX() + { + return x; + } + + // Other instance methods -------------------------------------------------- + + /** + *

Returns the encoded form of this private key according to the + * designated format.

+ * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + * @see DSSKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DSSKeyPairRawCodec().encodePrivateKey(this); + break; + case IKeyPairCodec.PKCS8_FORMAT: + result = new DSSKeyPairPKCS8Codec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + *

Returns true if the designated object is an instance of + * {@link DSAPrivateKey} and has the same DSS (Digital Signature Standard) + * parameter values as this one.

+ * + * @param obj the other non-null DSS key to compare to. + * @return true if the designated object is of the same type and + * value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (!(obj instanceof DSAPrivateKey)) + { + return false; + } + DSAPrivateKey that = (DSAPrivateKey) obj; + return super.equals(that) && x.equals(that.getX()); + } +} diff --git a/gnu/java/security/key/dss/DSSPublicKey.java b/gnu/java/security/key/dss/DSSPublicKey.java new file mode 100644 index 000000000..51470e85f --- /dev/null +++ b/gnu/java/security/key/dss/DSSPublicKey.java @@ -0,0 +1,201 @@ +/* DSSPublicKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.interfaces.DSAPublicKey; + +/** + *

An object that embodies a DSS (Digital Signature Standard) public key.

+ * + * @version $Revision: 1.2.2.1 $ + * @see #getEncoded + */ +public class DSSPublicKey extends DSSKey implements PublicKey, DSAPublicKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * y = gx mod p where x is the private + * part of the DSA key. + */ + private final BigInteger y; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Conveience constructor. Calls the constructor with 5 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param y the public key part. + */ + public DSSPublicKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y) + { + this(Registry.RAW_ENCODING_ID, p, q, g, y); + } + + /** + * Constructs a new instance of DSSPublicKey given the designated + * arguments. + * + * @param preferredFormat the identifier of the preferred encoding format to + * use when externalizing this key. + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param y the public key part. + */ + public DSSPublicKey(int preferredFormat, BigInteger p, BigInteger q, + BigInteger g, BigInteger y) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID + : preferredFormat, + p, q, g); + + this.y = y; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * A class method that takes the output of the encodePublicKey() + * method of a DSS keypair codec object (an instance implementing + * {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs + * an instance of this object. + * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an + * instance of this object. + * @exception IllegalArgumentException if the byte sequence does not represent + * a valid encoding of an instance of this object. + */ + public static DSSPublicKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]) + try + { + return (DSSPublicKey) new DSSKeyPairRawCodec().decodePublicKey(k); + } + catch (IllegalArgumentException ignored) + { + } + + // try X.509 codec + return (DSSPublicKey) new DSSKeyPairX509Codec().decodePublicKey(k); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.interfaces.DSAPublicKey interface implementation ---------- + + public BigInteger getY() + { + return y; + } + + // Other instance methods -------------------------------------------------- + + /** + *

Returns the encoded form of this public key according to the designated + * format.

+ * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + * @see DSSKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DSSKeyPairRawCodec().encodePublicKey(this); + break; + case IKeyPairCodec.X509_FORMAT: + result = new DSSKeyPairX509Codec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + *

Returns true if the designated object is an instance of + * {@link DSAPublicKey} and has the same DSS (Digital Signature Standard) + * parameter values as this one.

+ * + * @param obj the other non-null DSS key to compare to. + * @return true if the designated object is of the same type and + * value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (!(obj instanceof DSAPublicKey)) + { + return false; + } + DSAPublicKey that = (DSAPublicKey) obj; + return super.equals(that) && y.equals(that.getY()); + } +} diff --git a/gnu/java/security/key/dss/FIPS186.java b/gnu/java/security/key/dss/FIPS186.java new file mode 100644 index 000000000..6b351d229 --- /dev/null +++ b/gnu/java/security/key/dss/FIPS186.java @@ -0,0 +1,296 @@ +/* FIPS186.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.hash.Sha160; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Prime2; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + *

An implementation of the DSA parameters generation as described in + * FIPS-186.

+ * + * References:
+ * Digital Signature + * Standard (DSS), Federal Information Processing Standards Publication 186. + * National Institute of Standards and Technology. + * + * @version $Revision: 1.2.2.1 $ + */ +public class FIPS186 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int DSA_PARAMS_SEED = 0; + + public static final int DSA_PARAMS_COUNTER = 1; + + public static final int DSA_PARAMS_Q = 2; + + public static final int DSA_PARAMS_P = 3; + + public static final int DSA_PARAMS_E = 4; + + public static final int DSA_PARAMS_G = 5; + + /** The BigInteger constant 2. */ + private static final BigInteger TWO = new BigInteger("2"); + + private static final BigInteger TWO_POW_160 = TWO.pow(160); + + /** The SHA instance to use. */ + private Sha160 sha = new Sha160(); + + /** The length of the modulus of DSS keys generated by this instance. */ + private int L; + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + /** Our default source of randomness. */ + private PRNG prng = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public FIPS186(int L, SecureRandom rnd) + { + super(); + + this.L = L; + this.rnd = rnd; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * This method generates the DSS p, q, and + * g parameters only when L (the modulus length) + * is not one of the following: 512, 768 and + * 1024. For those values of L, this implementation + * uses pre-computed values of p, q, and + * g given in the document CryptoSpec included in the + * security guide documentation of the standard JDK distribution.

+ * + * The DSS requires two primes , p and q, + * satisfying the following three conditions: + * + *

    + *
  • 2159 < q < 2160
  • + *
  • 2L-1 < p < 2L for a + * specified L, where L = 512 + 64j for some + * 0 <= j <= 8
  • + *
  • q divides p - 1.
  • + *
+ * + * The algorithm used to find these primes is as described in FIPS-186, + * section 2.2: GENERATION OF PRIMES. This prime generation scheme starts by + * using the {@link Sha160} and a user supplied SEED + * to construct a prime, q, in the range 2159 < q + * < 2160. Once this is accomplished, the same SEED + * value is used to construct an X in the range 2L-1 + * < X < 2L. The prime, p, is then + * formed by rounding X to a number congruent to 1 mod + * 2q. In this implementation we use the same SEED value given + * in FIPS-186, Appendix 5. + */ + public BigInteger[] generateParameters() + { + int counter, offset; + BigInteger SEED, alpha, U, q, OFFSET, SEED_PLUS_OFFSET, W, X, p, c, g; + byte[] a, u; + byte[] kb = new byte[20]; // to hold 160 bits of randomness + + // Let L-1 = n*160 + b, where b and n are integers and 0 <= b < 160. + int b = (L - 1) % 160; + int n = (L - 1 - b) / 160; + BigInteger[] V = new BigInteger[n + 1]; + algorithm: while (true) + { + step1: while (true) + { + // 1. Choose an arbitrary sequence of at least 160 bits and + // call it SEED. + nextRandomBytes(kb); + SEED = new BigInteger(1, kb).setBit(159).setBit(0); + // Let g be the length of SEED in bits. here always 160 + // 2. Compute: U = SHA[SEED] XOR SHA[(SEED+1) mod 2**g] + alpha = SEED.add(BigInteger.ONE).mod(TWO_POW_160); + synchronized (sha) + { + a = SEED.toByteArray(); + sha.update(a, 0, a.length); + a = sha.digest(); + u = alpha.toByteArray(); + sha.update(u, 0, u.length); + u = sha.digest(); + } + for (int i = 0; i < a.length; i++) + { + a[i] ^= u[i]; + } + U = new BigInteger(1, a); + // 3. Form q from U by setting the most significant bit (the + // 2**159 bit) and the least significant bit to 1. In terms of + // boolean operations, q = U OR 2**159 OR 1. Note that + // 2**159 < q < 2**160. + q = U.setBit(159).setBit(0); + // 4. Use a robust primality testing algorithm to test whether + // q is prime(1). A robust primality test is one where the + // probability of a non-prime number passing the test is at + // most 1/2**80. + // 5. If q is not prime, go to step 1. + if (Prime2.isProbablePrime(q)) + { + break step1; + } + } // step1 + + // 6. Let counter = 0 and offset = 2. + counter = 0; + offset = 2; + step7: while (true) + { + OFFSET = BigInteger.valueOf(offset & 0xFFFFFFFFL); + SEED_PLUS_OFFSET = SEED.add(OFFSET); + // 7. For k = 0,...,n let V[k] = SHA[(SEED + offset + k) mod 2**g]. + synchronized (sha) + { + for (int k = 0; k <= n; k++) + { + a = SEED_PLUS_OFFSET.add( + BigInteger.valueOf(k & 0xFFFFFFFFL)).mod( + TWO_POW_160).toByteArray(); + sha.update(a, 0, a.length); + V[k] = new BigInteger(1, sha.digest()); + } + } + // 8. Let W be the integer: + // V[0]+V[1]*2**160+...+V[n-1]*2**((n-1)*160)+(V[n]mod2**b)*2**(n*160) + // and let : X = W + 2**(L-1). + // Note that 0 <= W < 2**(L-1) and hence 2**(L-1) <= X < 2**L. + W = V[0]; + for (int k = 1; k < n; k++) + { + W = W.add(V[k].multiply(TWO.pow(k * 160))); + } + W = W.add(V[n].mod(TWO.pow(b)).multiply(TWO.pow(n * 160))); + X = W.add(TWO.pow(L - 1)); + // 9. Let c = X mod 2q and set p = X - (c - 1). + // Note that p is congruent to 1 mod 2q. + c = X.mod(TWO.multiply(q)); + p = X.subtract(c.subtract(BigInteger.ONE)); + // 10. If p < 2**(L-1), then go to step 13. + if (p.compareTo(TWO.pow(L - 1)) >= 0) + { + // 11. Perform a robust primality test on p. + // 12. If p passes the test performed in step 11, go to step 15. + if (Prime2.isProbablePrime(p)) + { + break algorithm; + } + } + // 13. Let counter = counter + 1 and offset = offset + n + 1. + counter++; + offset += n + 1; + // 14. If counter >= 4096 go to step 1, otherwise go to step 7. + if (counter >= 4096) + { + continue algorithm; + } + } // step7 + } // algorithm + + // compute g. from FIPS-186, Appendix 4: + // 1. Generate p and q as specified in Appendix 2. + // 2. Let e = (p - 1) / q + BigInteger e = p.subtract(BigInteger.ONE).divide(q); + BigInteger h = TWO; + BigInteger p_minus_1 = p.subtract(BigInteger.ONE); + g = TWO; + // 3. Set h = any integer, where 1 < h < p - 1 and + // h differs from any value previously tried + for (; h.compareTo(p_minus_1) < 0; h = h.add(BigInteger.ONE)) + { + // 4. Set g = h**e mod p + g = h.modPow(e, p); + // 5. If g = 1, go to step 3 + if (!g.equals(BigInteger.ONE)) + { + break; + } + } + + return new BigInteger[] { SEED, BigInteger.valueOf(counter), q, p, e, g }; + } + + // helper methods ---------------------------------------------------------- + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/gnu/java/security/key/rsa/GnuRSAKey.java b/gnu/java/security/key/rsa/GnuRSAKey.java new file mode 100644 index 000000000..7846323f6 --- /dev/null +++ b/gnu/java/security/key/rsa/GnuRSAKey.java @@ -0,0 +1,181 @@ +/* GnuRSAKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.FormatUtil; + +import java.math.BigInteger; +import java.security.Key; +import java.security.interfaces.RSAKey; + +/** + *

A base asbtract class for both public and private RSA keys.

+ * + * @version $Revision: 1.3.2.1 $ + */ +public abstract class GnuRSAKey implements Key, RSAKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The public modulus of an RSA key pair. */ + private final BigInteger n; + + /** The public exponent of an RSA key pair. */ + private final BigInteger e; + + /** + * Identifier of the default encoding format to use when externalizing the + * key material. + */ + protected final int defaultFormat; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial protected constructor. + * + * @param defaultFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param n the public modulus n. + * @param e the public exponent e. + */ + protected GnuRSAKey(int defaultFormat, BigInteger n, BigInteger e) + { + super(); + + this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID + : defaultFormat; + this.n = n; + this.e = e; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.interfaces.RSAKey interface implementation ---------------- + + public BigInteger getModulus() + { + return getN(); + } + + // java.security.Key interface implementation ------------------------------ + + public String getAlgorithm() + { + return Registry.RSA_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(IKeyPairCodec.RAW_FORMAT); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + // Other instance methods -------------------------------------------------- + + /** + *

Returns the modulus n.

+ * + * @return the modulus n. + */ + public BigInteger getN() + { + return n; + } + + /** + *

Returns the public exponent e.

+ * + * @return the public exponent e. + */ + public BigInteger getPublicExponent() + { + return getE(); + } + + /** + *

Same as {@link #getPublicExponent()}.

+ * + * @return the public exponent e. + */ + public BigInteger getE() + { + return e; + } + + /** + *

Returns true if the designated object is an instance of + * {@link RSAKey} and has the same RSA parameter values as this one.

+ * + * @param obj the other non-null RSA key to compare to. + * @return true if the designated object is of the same type and + * value as this one. + */ + public boolean equals(final Object obj) + { + if (obj == null) + { + return false; + } + if (!(obj instanceof RSAKey)) + { + return false; + } + final RSAKey that = (RSAKey) obj; + return n.equals(that.getModulus()); + } + + // abstract methods to be implemented by subclasses ------------------------ + + public abstract byte[] getEncoded(int format); +} diff --git a/gnu/java/security/key/rsa/GnuRSAPrivateKey.java b/gnu/java/security/key/rsa/GnuRSAPrivateKey.java new file mode 100644 index 000000000..b3b94d8e2 --- /dev/null +++ b/gnu/java/security/key/rsa/GnuRSAPrivateKey.java @@ -0,0 +1,299 @@ +/* GnuRSAPrivateKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; + +/** + *

An object that embodies an RSA private key.

+ * + *

References:

+ *
    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ * + * @version $Revision: 1.3.2.1 $ + */ +public class GnuRSAPrivateKey extends GnuRSAKey implements PrivateKey, + RSAPrivateCrtKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The first prime divisor of the modulus. */ + private final BigInteger p; + + /** The second prime divisor of the modulus. */ + private final BigInteger q; + + /** The public exponent of an RSA key. */ + // private final BigInteger e; + /** The private exponent of an RSA private key. */ + private final BigInteger d; + + /** The first factor's exponent. */ + private final BigInteger dP; + + /** The second factor's exponent. */ + private final BigInteger dQ; + + /** The CRT (Chinese Remainder Theorem) coefficient. */ + private final BigInteger qInv; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Convenience constructor. Calls the constructor with 5 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param p the modulus first prime divisor. + * @param q the modulus second prime divisor. + * @param e the public exponent. + * @param d the private exponent. + */ + public GnuRSAPrivateKey(BigInteger p, BigInteger q, BigInteger e, + BigInteger d) + { + this(Registry.RAW_ENCODING_ID, p, q, e, d); + } + + /** + * Constructs a new instance of a GnuRSAPrivateKey given the + * designated arguments. + * + * @param preferredFormat the indetifier of the preferred encoding format to + * use when externalizing this key. + * @param p the modulus first prime divisor. + * @param q the modulus second prime divisor. + * @param e the public exponent. + * @param d the private exponent. + */ + public GnuRSAPrivateKey(int preferredFormat, BigInteger p, BigInteger q, + BigInteger e, BigInteger d) + { + this(preferredFormat, p.multiply(q), e, d, p, q, + e.modInverse(p.subtract(BigInteger.ONE)), + e.modInverse(q.subtract(BigInteger.ONE)), + q.modInverse(p)); + } + + /** + * Constructs a new instance of a GnuRSAPrivateKey given the + * designated arguments. + * + * @param preferredFormat the indetifier of the preferred encoding format to + * use when externalizing this key. + * @param n the public modulus, which is also the product of p + * and q. + * @param e the public exponent. + * @param d the private exponent. + * @param p the modulus first prime divisor. + * @param q the modulus second prime divisor. + * @param dP the first prime's exponen. A positive integer less than + * p and q, satisfying e * dP = 1 (mod p-1) + * . + * @param dQ the second prime's exponent. A positive integer less than + * p and q, satisfying e * dQ = 1 (mod p-1) + * . + * @param qInv the Chinese Remainder Theorem coefiicient. A positive integer + * less than p, satisfying q * qInv = 1 (mod p). + */ + public GnuRSAPrivateKey(int preferredFormat, BigInteger n, BigInteger e, + BigInteger d, BigInteger p, BigInteger q, + BigInteger dP, BigInteger dQ, BigInteger qInv) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID + : preferredFormat, + n, e); + + this.d = d; + this.p = p; + this.q = q; + // the exponents dP and dQ are positive integers less than p and q + // respectively satisfying + // e * dP = 1 (mod p-1); + // e * dQ = 1 (mod q-1), + this.dP = dP; + this.dQ = dQ; + // the CRT coefficient qInv is a positive integer less than p satisfying + // q * qInv = 1 (mod p). + this.qInv = qInv; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * A class method that takes the output of the encodePrivateKey() + * method of an RSA keypair codec object (an instance implementing + * {@link IKeyPairCodec} for RSA keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an instance + * of this object. + * @throws IllegalArgumentException if the byte sequence does not represent a + * valid encoding of an instance of this object. + */ + public static GnuRSAPrivateKey valueOf(final byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_RSA_PRIVATE_KEY[0]) + try + { + return (GnuRSAPrivateKey) new RSAKeyPairRawCodec().decodePrivateKey(k); + } + catch (IllegalArgumentException ignored) + { + } + + // try PKCS#8 codec + return (GnuRSAPrivateKey) new RSAKeyPairPKCS8Codec().decodePrivateKey(k); + } + + // Instance methods + // ------------------------------------------------------------------------- + + public BigInteger getPrimeP() + { + return p; + } + + public BigInteger getPrimeQ() + { + return q; + } + + public BigInteger getPrimeExponentP() + { + return dP; + } + + public BigInteger getPrimeExponentQ() + { + return dQ; + } + + public BigInteger getCrtCoefficient() + { + return qInv; + } + + // java.security.interfaces.RSAPrivateKey interface implementation --------- + + public BigInteger getPrivateExponent() + { + return d; + } + + // Other instance methods -------------------------------------------------- + + /** + * Returns the encoded form of this private key according to the + * designated format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + * @see RSAKeyPairRawCodec + * @see RSAKeyPairPKCS8Codec + */ + public byte[] getEncoded(int format) + { + final byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new RSAKeyPairRawCodec().encodePrivateKey(this); + break; + case IKeyPairCodec.PKCS8_FORMAT: + result = new RSAKeyPairPKCS8Codec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + *

Returns true if the designated object is an instance of + * this class and has the same RSA parameter values as this one.

+ * + * @param obj the other non-null RSA key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(final Object obj) + { + if (obj == null) + { + return false; + } + if (obj instanceof RSAPrivateKey) + { + final RSAPrivateKey that = (RSAPrivateKey) obj; + return super.equals(that) && d.equals(that.getPrivateExponent()); + } + if (obj instanceof RSAPrivateCrtKey) + { + final RSAPrivateCrtKey that = (RSAPrivateCrtKey) obj; + return super.equals(that) && p.equals(that.getPrimeP()) + && q.equals(that.getPrimeQ()) + && dP.equals(that.getPrimeExponentP()) + && dQ.equals(that.getPrimeExponentQ()) + && qInv.equals(that.getCrtCoefficient()); + } + return false; + } +} diff --git a/gnu/java/security/key/rsa/GnuRSAPublicKey.java b/gnu/java/security/key/rsa/GnuRSAPublicKey.java new file mode 100644 index 000000000..4c8ca597d --- /dev/null +++ b/gnu/java/security/key/rsa/GnuRSAPublicKey.java @@ -0,0 +1,185 @@ +/* GnuRSAPublicKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; + +/** + *

An object that encapsulates an RSA public key.

+ * + *

References:

+ *
    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ * + * @version $Revision: 1.2.2.1 $ + */ +public class GnuRSAPublicKey extends GnuRSAKey implements PublicKey, + RSAPublicKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Conveience constructor. Calls the constructor with 3 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param n the modulus. + * @param e the public exponent. + */ + public GnuRSAPublicKey(final BigInteger n, final BigInteger e) + { + this(Registry.RAW_ENCODING_ID, n, e); + } + + /** + * Constructs a new instance of GnuRSAPublicKey given the + * designated arguments. + * + * @param preferredFormat the identifier of the preferred encoding format to + * use when externalizing this key. + * @param n the modulus. + * @param e the public exponent. + */ + public GnuRSAPublicKey(int preferredFormat, BigInteger n, BigInteger e) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID + : preferredFormat, + n, e); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * A class method that takes the output of the encodePublicKey() + * method of an RSA keypair codec object (an instance implementing + * {@link IKeyPairCodec} for RSA keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an instance + * of this object. + * @throws IllegalArgumentException if the byte sequence does not represent a + * valid encoding of an instance of this object. + */ + public static GnuRSAPublicKey valueOf(final byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_RSA_PUBLIC_KEY[0]) + try + { + return (GnuRSAPublicKey) new RSAKeyPairRawCodec().decodePublicKey(k); + } + catch (IllegalArgumentException ignored) + { + } + + // try X.509 codec + return (GnuRSAPublicKey) new RSAKeyPairX509Codec().decodePublicKey(k); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns the encoded form of this public key according to the designated + * format.

+ * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + * @see RSAKeyPairRawCodec + */ + public byte[] getEncoded(final int format) + { + final byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new RSAKeyPairRawCodec().encodePublicKey(this); + break; + case IKeyPairCodec.X509_FORMAT: + result = new RSAKeyPairX509Codec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + *

Returns true if the designated object is an instance of + * this class and has the same RSA parameter values as this one.

+ * + * @param obj the other non-null RSA key to compare to. + * @return true if the designated object is of the same type and + * value as this one. + */ + public boolean equals(final Object obj) + { + if (obj == null) + { + return false; + } + if (!(obj instanceof RSAPublicKey)) + { + return false; + } + final RSAPublicKey that = (RSAPublicKey) obj; + return super.equals(that) + && getPublicExponent().equals(that.getPublicExponent()); + } +} diff --git a/gnu/java/security/key/rsa/RSAKeyPairGenerator.java b/gnu/java/security/key/rsa/RSAKeyPairGenerator.java new file mode 100644 index 000000000..9c7338f66 --- /dev/null +++ b/gnu/java/security/key/rsa/RSAKeyPairGenerator.java @@ -0,0 +1,264 @@ +/* RSAKeyPairGenerator.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Prime2; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.RSAKeyGenParameterSpec; +import java.util.Map; + +/** + *

A key-pair generator for asymetric keys to use in conjunction with the RSA + * scheme.

+ * + *

Reference:

+ *
    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B. Primitive + * specification and supporting documentation. Jakob Jonsson and Burt Kaliski. + *
  2. + *
  3. Handbook of Applied + * Cryptography, Alfred J. Menezes, Paul C. van Oorschot and Scott A. + * Vanstone. Section 11.3 RSA and related signature schemes.
  4. + *
+ */ +public class RSAKeyPairGenerator implements IKeyPairGenerator +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The BigInteger constant 1. */ + private static final BigInteger ONE = BigInteger.ONE; + + /** The BigInteger constant 2. */ + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** Property name of the length (Integer) of the modulus of an RSA key. */ + public static final String MODULUS_LENGTH = "gnu.crypto.rsa.L"; + + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.rsa.prng"; + + /** + * Property name of an optional {@link RSAKeyGenParameterSpec} instance to + * use for this generator's n, and e values. The + * default is to generate n and use a fixed value for + * e (Fermat's F4 number). + */ + public static final String RSA_PARAMETERS = "gnu.crypto.rsa.params"; + + /** + * Property name of the preferred encoding format to use when externalizing + * generated instance of key-pairs from this generator. The property is taken + * to be an {@link Integer} that encapsulates an encoding format identifier. + */ + public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.rsa.encoding"; + + /** Default value for the modulus length. */ + private static final int DEFAULT_MODULUS_LENGTH = 1024; + + /** Default encoding format to use when none was specified. */ + private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID; + + /** The desired bit length of the modulus. */ + private int L; + + /** + * This implementation uses, by default, Fermat's F4 number as the public + * exponent. + */ + private BigInteger e = BigInteger.valueOf(65537L); + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + /** Our default source of randomness. */ + private PRNG prng = null; + + /** Preferred encoding format of generated keys. */ + private int preferredFormat; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // gnu.crypto.key.IKeyPairGenerator interface implementation --------------- + + public String name() + { + return Registry.RSA_KPG; + } + + /** + *

Configures this instance.

+ * + * @param attributes the map of name/value pairs to use. + * @exception IllegalArgumentException if the designated MODULUS_LENGTH + * value is less than 1024. + */ + public void setup(Map attributes) + { + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + + // are we given a set of RSA params or we shall use our own? + RSAKeyGenParameterSpec params = (RSAKeyGenParameterSpec) attributes.get(RSA_PARAMETERS); + + // find out the modulus length + if (params != null) + { + L = params.getKeysize(); + e = params.getPublicExponent(); + } + else + { + Integer l = (Integer) attributes.get(MODULUS_LENGTH); + L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue()); + } + + if (L < 1024) + { + throw new IllegalArgumentException(MODULUS_LENGTH); + } + + // what is the preferred encoding format + Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT); + preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT + : formatID.intValue(); + } + + /** + *

The algorithm used here is described in nessie-pss-B.pdf + * document which is part of the RSA-PSS submission to NESSIE.

+ * + * @return an RSA keypair. + */ + public KeyPair generate() + { + BigInteger p, q, n, d; + + // 1. Generate a prime p in the interval [2**(M-1), 2**M - 1], where + // M = CEILING(L/2), and such that GCD(p, e) = 1 + int M = (L + 1) / 2; + BigInteger lower = TWO.pow(M - 1); + BigInteger upper = TWO.pow(M).subtract(ONE); + byte[] kb = new byte[(M + 7) / 8]; // enough bytes to frame M bits + step1: while (true) + { + nextRandomBytes(kb); + p = new BigInteger(1, kb).setBit(0); + if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0 + && Prime2.isProbablePrime(p) && p.gcd(e).equals(ONE)) + { + break step1; + } + } + + // 2. Generate a prime q such that the product of p and q is an L-bit + // number, and such that GCD(q, e) = 1 + step2: while (true) + { + nextRandomBytes(kb); + q = new BigInteger(1, kb).setBit(0); + n = p.multiply(q); + if (n.bitLength() == L && Prime2.isProbablePrime(q) + && q.gcd(e).equals(ONE)) + { + break step2; + } + + // TODO: test for p != q + } + + // TODO: ensure p < q + + // 3. Put n = pq. The public key is (n, e). + // 4. Compute the parameters necessary for the private key K (see + // Section 2.2). + BigInteger phi = p.subtract(ONE).multiply(q.subtract(ONE)); + d = e.modInverse(phi); + + // 5. Output the public key and the private key. + PublicKey pubK = new GnuRSAPublicKey(preferredFormat, n, e); + PrivateKey secK = new GnuRSAPrivateKey(preferredFormat, p, q, e, d); + + return new KeyPair(pubK, secK); + } + + // helper methods ---------------------------------------------------------- + + /** + *

Fills the designated byte array with random data.

+ * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java b/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java new file mode 100644 index 000000000..a7f65b610 --- /dev/null +++ b/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java @@ -0,0 +1,284 @@ +/* RSAKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; + +/** + * An implementation of an {@link IKeyPairCodec} that knows how to encode / + * decode PKCS#8 ASN.1 external representation of RSA private keys. + */ +public class RSAKeyPairPKCS8Codec + implements IKeyPairCodec +{ + private static final OID RSA_ALG_OID = new OID(Registry.RSA_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return PKCS8_FORMAT; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePublicKey(PublicKey key) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * Returns the PKCS#8 ASN.1 PrivateKeyInfo representation of an RSA + * private key. The ASN.1 specification is as follows: + * + *
+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   * 
+ * + *

The privateKey field, which is an OCTET STRING, contains the + * DER-encoded form of the RSA private key defined as:

+ * + *
+   *   RSAPrivateKey ::= SEQUENCE {
+   *     version                 INTEGER, -- MUST be 0
+   *     modulus                 INTEGER, -- n
+   *     publicExponent          INTEGER, -- e
+   *     privateExponent         INTEGER, -- d
+   *     prime1                  INTEGER, -- p
+   *     prime2                  INTEGER, -- q
+   *     exponent1               INTEGER, -- d mod (p-1)
+   *     exponent2               INTEGER, -- d mod (q-1)
+   *     coefficient             INTEGER, -- (inverse of q) mod p
+   *   }
+   * 
+ * + * @return the DER encoded form of the ASN.1 representation of the + * PrivateKeyInfo field for an RSA {@link PrivateKey}.. + * @throw InvalidParameterException if an error occurs during the marshalling + * process. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof GnuRSAPrivateKey)) + throw new InvalidParameterException("Wrong key type"); + + GnuRSAPrivateKey pk = (GnuRSAPrivateKey) key; + BigInteger n = pk.getN(); + BigInteger e = pk.getE(); + BigInteger d = pk.getPrivateExponent(); + BigInteger p = pk.getPrimeP(); + BigInteger q = pk.getPrimeQ(); + BigInteger dP = pk.getPrimeExponentP(); + BigInteger dQ = pk.getPrimeExponentQ(); + BigInteger qInv = pk.getCrtCoefficient(); + + DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, RSA_ALG_OID); + + ArrayList algorithmID = new ArrayList(1); + algorithmID.add(derOID); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + DERValue derRSAVersion = new DERValue(DER.INTEGER, BigInteger.ZERO); + DERValue derN = new DERValue(DER.INTEGER, n); + DERValue derE = new DERValue(DER.INTEGER, e); + DERValue derD = new DERValue(DER.INTEGER, d); + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derQ = new DERValue(DER.INTEGER, q); + DERValue derDP = new DERValue(DER.INTEGER, dP); + DERValue derDQ = new DERValue(DER.INTEGER, dQ); + DERValue derQInv = new DERValue(DER.INTEGER, qInv); + + ArrayList rsaPrivateKey = new ArrayList(); + rsaPrivateKey.add(derRSAVersion); + rsaPrivateKey.add(derN); + rsaPrivateKey.add(derE); + rsaPrivateKey.add(derD); + rsaPrivateKey.add(derP); + rsaPrivateKey.add(derQ); + rsaPrivateKey.add(derDP); + rsaPrivateKey.add(derDQ); + rsaPrivateKey.add(derQInv); + DERValue derRSAPrivateKey = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + rsaPrivateKey); + byte[] pkBytes = derRSAPrivateKey.getEncoded(); + DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, pkBytes); + + ArrayList pki = new ArrayList(3); + pki.add(derVersion); + pki.add(derAlgorithmID); + pki.add(derPrivateKey); + DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derPKI); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PublicKey decodePublicKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * @param input the byte array to unmarshall into a valid RSA + * {@link PrivateKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuRSAPrivateKey} decoded from the + * PrivateKeyInfo material fed as input. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger version, n, e, d, p, q, dP, dQ, qInv; + DERReader der = new DERReader(input); + try + { + DERValue derPKI = der.read(); + DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field"); + + DERValue derVersion = der.read(); + DerUtil.checkIsBigInteger(derVersion, "Wrong Version field"); + version = (BigInteger) derVersion.getValue(); + if (version.compareTo(BigInteger.ZERO) != 0) + throw new InvalidParameterException("Unexpected Version: " + version); + + DERValue derAlgoritmID = der.read(); + DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(RSA_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue val = der.read(); + byte[] pkBytes = (byte[]) val.getValue(); + + der = new DERReader(pkBytes); + DERValue derRSAPrivateKey = der.read(); + DerUtil.checkIsConstructed(derRSAPrivateKey, "Wrong RSAPrivateKey field"); + + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong RSAPrivateKey Version field"); + version = (BigInteger) val.getValue(); + if (version.compareTo(BigInteger.ZERO) != 0) + throw new InvalidParameterException("Unexpected RSAPrivateKey Version: " + + version); + + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong modulus field"); + n = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong publicExponent field"); + e = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong privateExponent field"); + d = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong prime1 field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong prime2 field"); + q = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong exponent1 field"); + dP = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong exponent2 field"); + dQ = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong coefficient field"); + qInv = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, n, e, d, p, q, + dP, dQ, qInv); + } +} diff --git a/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java b/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java new file mode 100644 index 000000000..1cca7c324 --- /dev/null +++ b/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java @@ -0,0 +1,332 @@ +/* RSAKeyPairRawCodec.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + *

An object that implements the {@link IKeyPairCodec} interface for the + * Raw format to use with RSA keypairs.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class RSAKeyPairRawCodec implements IKeyPairCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.key.IKeyPairCodec interface implementation ------------------- + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + *

Returns the encoded form of the designated RSA public key according to + * the Raw format supported by this library.

+ * + *

The Raw format for an RSA public key, in this implementation, is + * a byte sequence consisting of the following:

+ * + *
    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_RSA_PUBLIC_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the RSA parameter + * n (the modulus) in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter n,
  8. + *
  9. 4-byte count of following bytes representing the RSA parameter + * e (the public exponent) in internet order,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter e.
  12. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @exception IllegalArgumentException if the designated key is not an RSA + * one. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (!(key instanceof GnuRSAPublicKey)) + { + throw new IllegalArgumentException("key"); + } + + GnuRSAPublicKey rsaKey = (GnuRSAPublicKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[0]); + baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[1]); + baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[2]); + baos.write(Registry.MAGIC_RAW_RSA_PUBLIC_KEY[3]); + + // version + baos.write(0x01); + + // n + byte[] buffer = rsaKey.getModulus().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // e + buffer = rsaKey.getPublicExponent().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + public PublicKey decodePublicKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[0] + || k[1] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[1] + || k[2] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[2] + || k[3] != Registry.MAGIC_RAW_RSA_PUBLIC_KEY[3]) + { + throw new IllegalArgumentException("magic"); + } + + // version + if (k[4] != 0x01) + { + throw new IllegalArgumentException("version"); + } + int i = 5; + + int l; + byte[] buffer; + + // n + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger n = new BigInteger(1, buffer); + + // e + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger e = new BigInteger(1, buffer); + + return new GnuRSAPublicKey(n, e); + } + + /** + *

Returns the encoded form of the designated RSA private key according to + * the Raw format supported by this library.

+ * + *

The Raw format for an RSA private key, in this implementation, + * is a byte sequence consisting of the following:

+ * + *
    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_RSA_PRIVATE_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the RSA parameter + * p (the first prime factor of the modulus) in internet + * order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter p,
  8. + *
  9. 4-byte count of following bytes representing the RSA parameter + * q (the second prime factor of the modulus) in internet + * order,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter q,
  12. + *
  13. 4-byte count of following bytes representing the RSA parameter + * e (the public exponent) in internet order,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter e,
  16. + *
  17. 4-byte count of following bytes representing the RSA parameter + * d (the private exponent) in internet order,
  18. + *
  19. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the RSA parameter d,
  20. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (!(key instanceof GnuRSAPrivateKey)) + { + throw new IllegalArgumentException("key"); + } + + GnuRSAPrivateKey rsaKey = (GnuRSAPrivateKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[0]); + baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[1]); + baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[2]); + baos.write(Registry.MAGIC_RAW_RSA_PRIVATE_KEY[3]); + + // version + baos.write(0x01); + + // p + byte[] buffer = rsaKey.getPrimeP().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // q + buffer = rsaKey.getPrimeQ().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // e + buffer = rsaKey.getPublicExponent().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // d + buffer = rsaKey.getPrivateExponent().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + public PrivateKey decodePrivateKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[0] + || k[1] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[1] + || k[2] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[2] + || k[3] != Registry.MAGIC_RAW_RSA_PRIVATE_KEY[3]) + { + throw new IllegalArgumentException("magic"); + } + + // version + if (k[4] != 0x01) + { + throw new IllegalArgumentException("version"); + } + int i = 5; + + int l; + byte[] buffer; + + // p + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + + // q + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + + // e + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger e = new BigInteger(1, buffer); + + // d + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger d = new BigInteger(1, buffer); + + return new GnuRSAPrivateKey(p, q, e, d); + } +} diff --git a/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java b/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java new file mode 100644 index 000000000..f0a454992 --- /dev/null +++ b/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java @@ -0,0 +1,232 @@ +/* RSAKeyPairX509Codec.java -- X.509 Encoding/Decoding handler + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +/** + * An implementation of an {@link IKeyPairCodec} that knows how to encode / + * decode X.509 ASN.1 external representation of RSA public keys. + */ +public class RSAKeyPairX509Codec + implements IKeyPairCodec +{ + private static final OID RSA_ALG_OID = new OID(Registry.RSA_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return X509_FORMAT; + } + + /** + * Returns the X.509 ASN.1 SubjectPublicKeyInfo representation of an + * RSA public key. The ASN.1 specification, as defined in RFC-3280, and + * RFC-2459, is as follows: + * + *
+   *   SubjectPublicKeyInfo ::= SEQUENCE {
+   *     algorithm         AlgorithmIdentifier,
+   *     subjectPublicKey  BIT STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   * 
+ * + *

The subjectPublicKey field, which is a BIT STRING, contains the + * DER-encoded form of the RSA public key defined as:

+ * + *
+   *   RSAPublicKey ::= SEQUENCE {
+   *     modulus         INTEGER, -- n
+   *     publicExponent  INTEGER  -- e
+   *   }
+   * 
+ * + * @param key the {@link PublicKey} instance to encode. MUST be an instance of + * {@link GnuRSAPublicKey}. + * @return the ASN.1 representation of the SubjectPublicKeyInfo in an + * X.509 certificate. + * @throw InvalidParameterException if key is not an instance + * of {@link GnuRSAPublicKey} or if an exception occurs during the + * marshalling process. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof GnuRSAPublicKey)) + throw new InvalidParameterException("key"); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, RSA_ALG_OID); + + GnuRSAPublicKey rsaKey = (GnuRSAPublicKey) key; + BigInteger n = rsaKey.getN(); + BigInteger e = rsaKey.getE(); + + DERValue derN = new DERValue(DER.INTEGER, n); + DERValue derE = new DERValue(DER.INTEGER, e); + + ArrayList algorithmID = new ArrayList(1); + algorithmID.add(derOID); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + ArrayList publicKey = new ArrayList(2); + publicKey.add(derN); + publicKey.add(derE); + DERValue derPublicKey = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + publicKey); + byte[] spkBytes = derPublicKey.getEncoded(); + DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(spkBytes)); + + ArrayList spki = new ArrayList(2); + spki.add(derAlgorithmID); + spki.add(derSPK); + DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derSPKI); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + throw new InvalidParameterException("Wrong format for private keys"); + } + + /** + * @param input the byte array to unmarshall into a valid RSA + * {@link PublicKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuRSAPublicKey} decoded from the + * SubjectPublicKeyInfo material in an X.509 certificate. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PublicKey decodePublicKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger n, e; + DERReader der = new DERReader(input); + try + { + DERValue derSPKI = der.read(); + DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); + + DERValue derAlgorithmID = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + if (! (derOID.getValue() instanceof OID)) + throw new InvalidParameterException("Wrong Algorithm field"); + + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(RSA_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue val = der.read(); + if (! (val.getValue() instanceof BitString)) + throw new InvalidParameterException("Wrong SubjectPublicKey field"); + + byte[] spkBytes = ((BitString) val.getValue()).toByteArray(); + + der = new DERReader(spkBytes); + val = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong subjectPublicKey field"); + + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong modulus field"); + n = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong publicExponent field"); + e = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e); + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for private keys"); + } +} diff --git a/gnu/java/security/prng/BasePRNG.java b/gnu/java/security/prng/BasePRNG.java new file mode 100644 index 000000000..fe815d700 --- /dev/null +++ b/gnu/java/security/prng/BasePRNG.java @@ -0,0 +1,199 @@ +/* BasePRNG.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +import java.util.Map; + +/** + *

An abstract class to facilitate implementing PRNG algorithms.

+ */ +public abstract class BasePRNG implements IRandom +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The canonical name prefix of the PRNG algorithm. */ + protected String name; + + /** Indicate if this instance has already been initialised or not. */ + protected boolean initialised; + + /** A temporary buffer to serve random bytes. */ + protected byte[] buffer; + + /** The index into buffer of where the next byte will come from. */ + protected int ndx; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial constructor for use by concrete subclasses.

+ * + * @param name the canonical name of this instance. + */ + protected BasePRNG(String name) + { + super(); + + this.name = name; + initialised = false; + buffer = new byte[0]; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IRandom interface implementation ---------------------------------------- + + public String name() + { + return name; + } + + public void init(Map attributes) + { + this.setup(attributes); + + ndx = 0; + initialised = true; + } + + public byte nextByte() throws IllegalStateException, LimitReachedException + { + if (!initialised) + { + throw new IllegalStateException(); + } + return nextByteInternal(); + } + + public void nextBytes(byte[] out) throws IllegalStateException, + LimitReachedException + { + nextBytes(out, 0, out.length); + } + + public void nextBytes(byte[] out, int offset, int length) + throws IllegalStateException, LimitReachedException + { + if (!initialised) + throw new IllegalStateException("not initialized"); + + if (length == 0) + return; + + if (offset < 0 || length < 0 || offset + length > out.length) + throw new ArrayIndexOutOfBoundsException("offset=" + offset + " length=" + + length + " limit=" + + out.length); + + if (ndx >= buffer.length) + { + fillBlock(); + ndx = 0; + } + int count = 0; + while (count < length) + { + int amount = Math.min(buffer.length - ndx, length - count); + System.arraycopy(buffer, ndx, out, offset + count, amount); + count += amount; + ndx += amount; + if (ndx >= buffer.length) + { + fillBlock(); + ndx = 0; + } + } + } + + public void addRandomByte(byte b) + { + throw new UnsupportedOperationException("random state is non-modifiable"); + } + + public void addRandomBytes(byte[] buffer) + { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes(byte[] buffer, int offset, int length) + { + throw new UnsupportedOperationException("random state is non-modifiable"); + } + + // Instance methods + // ------------------------------------------------------------------------- + + public boolean isInitialised() + { + return initialised; + } + + private byte nextByteInternal() throws LimitReachedException + { + if (ndx >= buffer.length) + { + this.fillBlock(); + ndx = 0; + } + + return buffer[ndx++]; + } + + // abstract methods to implement by subclasses ----------------------------- + + public Object clone() throws CloneNotSupportedException + { + BasePRNG result = (BasePRNG) super.clone(); + if (this.buffer != null) + result.buffer = (byte[]) this.buffer.clone(); + + return result; + } + + public abstract void setup(Map attributes); + + public abstract void fillBlock() throws LimitReachedException; +} diff --git a/gnu/java/security/prng/EntropySource.java b/gnu/java/security/prng/EntropySource.java new file mode 100644 index 000000000..260c668f8 --- /dev/null +++ b/gnu/java/security/prng/EntropySource.java @@ -0,0 +1,62 @@ +/* EntropySource.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +/** + * A generic interface for adding random bytes to an entropy pool. + */ +public interface EntropySource +{ + + /** + * Returns the estimated quality of this source. This value should be + * between 0 and 100 (the running quality is computed as a percentage, + * 100 percent being perfect-quality). + * + * @return The quality. + */ + double quality(); + + /** + * Returns a new buffer with the next random bytes to add. + * + * @return The next random bytes. + */ + byte[] nextBytes(); +} \ No newline at end of file diff --git a/gnu/java/security/prng/IRandom.java b/gnu/java/security/prng/IRandom.java new file mode 100644 index 000000000..2c89e7ad5 --- /dev/null +++ b/gnu/java/security/prng/IRandom.java @@ -0,0 +1,180 @@ +/* IRandom.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +import java.util.Map; + +/** + *

The basic visible methods of any pseudo-random number generator.

+ * + *

The [HAC] defines a PRNG (as implemented in this library) as follows:

+ * + *
    + *
  • "5.6 Definition: A pseudorandom bit generator (PRBG) is said to pass + * the next-bit test if there is no polynomial-time algorithm which, + * on input of the first L bits of an output sequence S, + * can predict the (L+1)st bit of S with a + * probability significantly grater than 1/2."
  • + * + *
  • "5.8 Definition: A PRBG that passes the next-bit test + * (possibly under some plausible but unproved mathematical assumption such + * as the intractability of factoring integers) is called a + * cryptographically secure pseudorandom bit generator (CSPRBG)."
  • + *
+ * + *

IMPLEMENTATION NOTE: Although all the concrete classes in this + * package implement the {@link Cloneable} interface, it is important to note + * here that such an operation, for those algorithms that use an underlting + * symmetric key block cipher, DOES NOT clone any session key material + * that may have been used in initialising the source PRNG (the instance to be + * cloned). Instead a clone of an already initialised PRNG, that uses and + * underlying symmetric key block cipher, is another instance with a clone of + * the same cipher that operates with the same block size but without any + * knowledge of neither key material nor key size.

+ * + *

References:

+ * + *
    + *
  1. [HAC]: Handbook of + * Applied Cryptography.
    + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997
    + * Menezes, A., van Oorschot, P. and S. Vanstone.
  2. + *
+ */ +public interface IRandom extends Cloneable +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + *

Returns the canonical name of this instance.

+ * + * @return the canonical name of this instance. */ + String name(); + + /** + *

Initialises the pseudo-random number generator scheme with the + * appropriate attributes.

+ * + * @param attributes a set of name-value pairs that describe the desired + * future instance behaviour. + * @exception IllegalArgumentException if at least one of the defined name/ + * value pairs contains invalid data. + */ + void init(Map attributes); + + /** + *

Returns the next 8 bits of random data generated from this instance.

+ * + * @return the next 8 bits of random data generated from this instance. + * @exception IllegalStateException if the instance is not yet initialised. + * @exception LimitReachedException if this instance has reached its + * theoretical limit for generating non-repetitive pseudo-random data. + */ + byte nextByte() throws IllegalStateException, LimitReachedException; + + /** + *

Fills the designated byte array, starting from byte at index + * offset, for a maximum of length bytes with the + * output of this generator instance. + * + * @param out the placeholder to contain the generated random bytes. + * @param offset the starting index in out to consider. This method + * does nothing if this parameter is not within 0 and + * out.length. + * @param length the maximum number of required random bytes. This method + * does nothing if this parameter is less than 1. + * @exception IllegalStateException if the instance is not yet initialised. + * @exception LimitReachedException if this instance has reached its + * theoretical limit for generating non-repetitive pseudo-random data. + */ + void nextBytes(byte[] out, int offset, int length) + throws IllegalStateException, LimitReachedException; + + /** + *

Supplement, or possibly replace, the random state of this PRNG with + * a random byte.

+ * + *

Implementations are not required to implement this method in any + * meaningful way; this may be a no-operation, and implementations may + * throw an {@link UnsupportedOperationException}.

+ * + * @param b The byte to add. + */ + void addRandomByte(byte b); + + /** + *

Supplement, or possibly replace, the random state of this PRNG with + * a sequence of new random bytes.

+ * + *

Implementations are not required to implement this method in any + * meaningful way; this may be a no-operation, and implementations may + * throw an {@link UnsupportedOperationException}.

+ * + * @param in The buffer of new random bytes to add. + */ + void addRandomBytes(byte[] in); + + /** + *

Supplement, or possibly replace, the random state of this PRNG with + * a sequence of new random bytes.

+ * + *

Implementations are not required to implement this method in any + * meaningful way; this may be a no-operation, and implementations may + * throw an {@link UnsupportedOperationException}.

+ * + * @param in The buffer of new random bytes to add. + * @param offset The offset from whence to begin reading random bytes. + * @param length The number of random bytes to add. + * @exception IndexOutOfBoundsException If offset, length, + * or offset+length is out of bounds. + */ + void addRandomBytes(byte[] in, int offset, int length); + + /** + *

Returns a clone copy of this instance.

+ * + * @return a clone copy of this instance. + */ + Object clone() throws CloneNotSupportedException; +} \ No newline at end of file diff --git a/gnu/java/security/prng/LimitReachedException.java b/gnu/java/security/prng/LimitReachedException.java new file mode 100644 index 000000000..2fd8bfa7f --- /dev/null +++ b/gnu/java/security/prng/LimitReachedException.java @@ -0,0 +1,69 @@ +/* LimitReachedException.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +/** + * A checked exception that indicates that a pseudo random number generated has + * reached its theoretical limit in generating random bytes. + */ +public class LimitReachedException extends Exception +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public LimitReachedException() + { + super(); + } + + public LimitReachedException(String msg) + { + super(msg); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instant methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/java/security/prng/MDGenerator.java b/gnu/java/security/prng/MDGenerator.java new file mode 100644 index 000000000..255647d1c --- /dev/null +++ b/gnu/java/security/prng/MDGenerator.java @@ -0,0 +1,135 @@ +/* MDGenerator.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; + +import java.util.Map; + +/** + *

A simple pseudo-random number generator that relies on a hash algorithm, + * that (a) starts its operation by hashing a seed, and then (b) + * continuously re-hashing its output. If no hash algorithm name is specified + * in the {@link Map} of attributes used to initialise the instance then the + * SHA-160 algorithm is used as the underlying hash function. Also, if no + * seed is given, an empty octet sequence is used.

+ */ +public class MDGenerator extends BasePRNG implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Property name of underlying hash algorithm for this generator. */ + public static final String MD_NAME = "gnu.crypto.prng.md.hash.name"; + + /** Property name of seed material. */ + public static final String SEEED = "gnu.crypto.prng.md.seed"; + + /** The underlying hash instance. */ + private IMessageDigest md; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public MDGenerator() + { + super(Registry.MD_PRNG); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BaseRandom ------------------------ + + public void setup(Map attributes) + { + // find out which hash to use + String underlyingMD = (String) attributes.get(MD_NAME); + if (underlyingMD == null) + { + if (md == null) + { // happy birthday + // ensure we have a reliable implementation of this hash + md = HashFactory.getInstance(Registry.SHA160_HASH); + } + else + { // a clone. reset it for reuse + md.reset(); + } + } + else + { // ensure we have a reliable implementation of this hash + md = HashFactory.getInstance(underlyingMD); + } + + // get the seeed + byte[] seed = (byte[]) attributes.get(SEEED); + if (seed == null) + { + seed = new byte[0]; + } + + md.update(seed, 0, seed.length); + } + + public void fillBlock() throws LimitReachedException + { + IMessageDigest mdc = (IMessageDigest) md.clone(); + buffer = mdc.digest(); + md.update(buffer, 0, buffer.length); + } + + // Cloneable interface implementation --------------------------------------- + + public Object clone() throws CloneNotSupportedException + { + MDGenerator result = (MDGenerator) super.clone(); + if (this.md != null) + result.md = (IMessageDigest) this.md.clone(); + + return result; + } +} diff --git a/gnu/java/security/prng/PRNGFactory.java b/gnu/java/security/prng/PRNGFactory.java new file mode 100644 index 000000000..8b5141456 --- /dev/null +++ b/gnu/java/security/prng/PRNGFactory.java @@ -0,0 +1,109 @@ +/* PRNGFactory.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + *

A Factory to instantiate pseudo random number generators.

+ */ +public class PRNGFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + protected PRNGFactory() + { + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a padding algorithm given its name.

+ * + * @param prng the case-insensitive name of the PRNG. + * @return an instance of the pseudo-random number generator. + * @exception InternalError if the implementation does not pass its self- + * test. + */ + public static final IRandom getInstance(String prng) + { + if (prng == null) + { + return null; + } + + prng = prng.trim(); + IRandom result = null; + if (prng.equalsIgnoreCase(MD_PRNG)) + { + result = new MDGenerator(); + } + + return result; + } + + /** + *

Returns a {@link Set} of names of padding algorithms supported by this + * Factory.

+ * + * @return a {@link Set} of pseudo-random number generator algorithm names + * (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(MD_PRNG); + return Collections.unmodifiableSet(hs); + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/java/security/prng/RandomEvent.java b/gnu/java/security/prng/RandomEvent.java new file mode 100644 index 000000000..c07062125 --- /dev/null +++ b/gnu/java/security/prng/RandomEvent.java @@ -0,0 +1,82 @@ +/* RandomEvent.java -- an event with random data. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +import java.util.EventObject; + +/** + * An interface for entropy accumulators that will be notified of random + * events. + */ +public class RandomEvent extends EventObject +{ + + private final byte sourceNumber; + + private final byte poolNumber; + + private final byte[] data; + + public RandomEvent(Object source, byte sourceNumber, byte poolNumber, + byte[] data) + { + super(source); + this.sourceNumber = sourceNumber; + this.poolNumber = poolNumber; + if (data.length == 0 || data.length > 32) + throw new IllegalArgumentException( + "random events take between 1 and 32 bytes of data"); + this.data = (byte[]) data.clone(); + } + + public byte getSourceNumber() + { + return sourceNumber; + } + + public byte getPoolNumber() + { + return poolNumber; + } + + public byte[] getData() + { + return data; + } +} \ No newline at end of file diff --git a/gnu/java/security/prng/RandomEventListener.java b/gnu/java/security/prng/RandomEventListener.java new file mode 100644 index 000000000..1dc14619f --- /dev/null +++ b/gnu/java/security/prng/RandomEventListener.java @@ -0,0 +1,50 @@ +/* RandomEventListener.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +import java.util.EventListener; + +/** + * An interface for entropy accumulators that will be notified of random + * events. + */ +public interface RandomEventListener extends EventListener +{ + void addRandomEvent(RandomEvent event); +} \ No newline at end of file diff --git a/gnu/java/security/provider/EncodedKeyFactory.java b/gnu/java/security/provider/EncodedKeyFactory.java index 2bf0fff80..4092df817 100644 --- a/gnu/java/security/provider/EncodedKeyFactory.java +++ b/gnu/java/security/provider/EncodedKeyFactory.java @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.java.security.provider; import gnu.java.security.OID; +import gnu.java.security.Registry; import gnu.java.security.der.BitString; import gnu.java.security.der.DERReader; import gnu.java.security.der.DERValue; @@ -75,9 +76,9 @@ public class EncodedKeyFactory extends KeyFactorySpi // Constants. // ------------------------------------------------------------------------ - private static final OID ID_DSA = new OID("1.2.840.10040.4.1"); - private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1"); - private static final OID ID_DH = new OID("1.2.840.10046.2.1"); + private static final OID ID_DSA = new OID(Registry.DSA_OID_STRING); + private static final OID ID_RSA = new OID(Registry.RSA_OID_STRING); + private static final OID ID_DH = new OID(Registry.DH_OID_STRING); // Instance methods. // ------------------------------------------------------------------------ diff --git a/gnu/java/security/provider/Gnu.java b/gnu/java/security/provider/Gnu.java index e553bbcbd..849015214 100644 --- a/gnu/java/security/provider/Gnu.java +++ b/gnu/java/security/provider/Gnu.java @@ -97,11 +97,25 @@ public final class Gnu extends Provider put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA"); put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); + put("Signature.DSS/RAW", gnu.java.security.jce.sig.DSSRawSignatureSpi.class.getName()); + put("Signature.DSS/RAW KeySize", "1024"); + put("Signature.DSS/RAW ImplementedIn", "Software"); + put("Signature.RSA-PSS/RAW", gnu.java.security.jce.sig.RSAPSSRawSignatureSpi.class.getName()); + put("Signature.RSA-PSS/RAW KeySize", "1024"); + put("Signature.RSA-PSS/RAW ImplementedIn", "Software"); + // Key Pair Generator put("KeyPairGenerator.DSA", gnu.java.security.provider.DSAKeyPairGenerator.class.getName()); put("KeyPairGenerator.DiffieHellman", DiffieHellmanKeyPairGeneratorImpl.class.getName ()); + put("KeyPairGenerator.DSS", gnu.java.security.jce.sig.DSSKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.DSS KeySize", "1024"); + put("KeyPairGenerator.DSS ImplementedIn", "Software"); + put("KeyPairGenerator.RSA", gnu.java.security.jce.sig.RSAKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.RSA KeySize", "1024"); + put("KeyPairGenerator.RSA ImplementedIn", "Software"); + put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA"); put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA"); put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA"); @@ -128,13 +142,57 @@ public final class Gnu extends Provider put("Alg.Alias.KeyFactory.DH", "DiffieHellman"); // Message Digests - put("MessageDigest.SHA", gnu.java.security.provider.SHA.class.getName()); - put("MessageDigest.MD5", gnu.java.security.provider.MD5.class.getName()); +// put("MessageDigest.SHA", gnu.java.security.provider.SHA.class.getName()); +// put("MessageDigest.MD5", gnu.java.security.provider.MD5.class.getName()); // Format "Alias", "Actual Name" - put("Alg.Alias.MessageDigest.SHA1", "SHA"); - put("Alg.Alias.MessageDigest.SHA-1", "SHA"); - put("Alg.Alias.MessageDigest.SHA-160", "SHA"); +// put("Alg.Alias.MessageDigest.SHA1", "SHA"); +// put("Alg.Alias.MessageDigest.SHA-1", "SHA"); +// put("Alg.Alias.MessageDigest.SHA-160", "SHA"); + + put("MessageDigest.HAVAL", gnu.java.security.jce.hash.HavalSpi.class.getName()); + put("MessageDigest.HAVAL ImplementedIn", "Software"); + put("MessageDigest.MD2", gnu.java.security.jce.hash.MD2Spi.class.getName()); + put("MessageDigest.MD2 ImplementedIn", "Software"); + put("MessageDigest.MD4", gnu.java.security.jce.hash.MD4Spi.class.getName()); + put("MessageDigest.MD4 ImplementedIn", "Software"); + put("MessageDigest.MD5", gnu.java.security.jce.hash.MD5Spi.class.getName()); + put("MessageDigest.MD5 ImplementedIn", "Software"); + put("MessageDigest.RIPEMD128", gnu.java.security.jce.hash.RipeMD128Spi.class.getName()); + put("MessageDigest.RIPEMD128 ImplementedIn", "Software"); + put("MessageDigest.RIPEMD160", gnu.java.security.jce.hash.RipeMD160Spi.class.getName()); + put("MessageDigest.RIPEMD160 ImplementedIn", "Software"); + put("MessageDigest.SHA-160", gnu.java.security.jce.hash.Sha160Spi.class.getName()); + put("MessageDigest.SHA-160 ImplementedIn", "Software"); + put("MessageDigest.SHA-256", gnu.java.security.jce.hash.Sha256Spi.class.getName()); + put("MessageDigest.SHA-256 ImplementedIn", "Software"); + put("MessageDigest.SHA-384", gnu.java.security.jce.hash.Sha384Spi.class.getName()); + put("MessageDigest.SHA-384 ImplementedIn", "Software"); + put("MessageDigest.SHA-512", gnu.java.security.jce.hash.Sha512Spi.class.getName()); + put("MessageDigest.SHA-512 ImplementedIn", "Software"); + put("MessageDigest.TIGER", gnu.java.security.jce.hash.TigerSpi.class.getName()); + put("MessageDigest.TIGER ImplementedIn", "Software"); + put("MessageDigest.WHIRLPOOL", gnu.java.security.jce.hash.WhirlpoolSpi.class.getName()); + put("MessageDigest.WHIRLPOOL ImplementedIn", "Software"); + + put("Alg.Alias.MessageDigest.SHS", "SHA-160"); + put("Alg.Alias.MessageDigest.SHA", "SHA-160"); + put("Alg.Alias.MessageDigest.SHA1", "SHA-160"); + put("Alg.Alias.MessageDigest.SHA-1", "SHA-160"); + put("Alg.Alias.MessageDigest.SHA2-256", "SHA-256"); + put("Alg.Alias.MessageDigest.SHA2-384", "SHA-384"); + put("Alg.Alias.MessageDigest.SHA2-512", "SHA-512"); + put("Alg.Alias.MessageDigest.SHA256", "SHA-256"); + put("Alg.Alias.MessageDigest.SHA384", "SHA-384"); + put("Alg.Alias.MessageDigest.SHA512", "SHA-512"); + put("Alg.Alias.MessageDigest.RIPEMD-160", "RIPEMD160"); + put("Alg.Alias.MessageDigest.RIPEMD-128", "RIPEMD128"); + put("Alg.Alias.MessageDigest.OID.1.2.840.11359.2.2", "MD2"); + put("Alg.Alias.MessageDigest.1.2.840.11359.2.2", "MD2"); + put("Alg.Alias.MessageDigest.OID.1.2.840.11359.2.5", "MD5"); + put("Alg.Alias.MessageDigest.1.2.840.11359.2.5", "MD5"); + put("Alg.Alias.MessageDigest.OID.1.3.14.3.2.26", "SHA1"); + put("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA1"); // Algorithm Parameters put("AlgorithmParameters.DSA", @@ -153,6 +211,41 @@ public final class Gnu extends Provider put("SecureRandom.SHA1PRNG", gnu.java.security.provider.SHA1PRNG.class.getName()); + put("SecureRandom.MD2PRNG", gnu.java.security.jce.prng.MD2RandomSpi.class.getName()); + put("SecureRandom.MD2PRNG ImplementedIn", "Software"); + put("SecureRandom.MD4PRNG", gnu.java.security.jce.prng.MD4RandomSpi.class.getName()); + put("SecureRandom.MD4PRNG ImplementedIn", "Software"); + put("SecureRandom.MD5PRNG", gnu.java.security.jce.prng.MD5RandomSpi.class.getName()); + put("SecureRandom.MD5PRNG ImplementedIn", "Software"); + put("SecureRandom.RIPEMD128PRNG", gnu.java.security.jce.prng.RipeMD128RandomSpi.class.getName()); + put("SecureRandom.RIPEMD128PRNG ImplementedIn", "Software"); + put("SecureRandom.RIPEMD160PRNG", gnu.java.security.jce.prng.RipeMD160RandomSpi.class.getName()); + put("SecureRandom.RIPEMD160PRNG ImplementedIn", "Software"); + put("SecureRandom.SHA-160PRNG", gnu.java.security.jce.prng.Sha160RandomSpi.class.getName()); + put("SecureRandom.SHA-160PRNG ImplementedIn", "Software"); + put("SecureRandom.SHA-256PRNG", gnu.java.security.jce.prng.Sha256RandomSpi.class.getName()); + put("SecureRandom.SHA-256PRNG ImplementedIn", "Software"); + put("SecureRandom.SHA-384PRNG", gnu.java.security.jce.prng.Sha384RandomSpi.class.getName()); + put("SecureRandom.SHA-384PRNG ImplementedIn", "Software"); + put("SecureRandom.SHA-512PRNG", gnu.java.security.jce.prng.Sha512RandomSpi.class.getName()); + put("SecureRandom.SHA-512PRNG ImplementedIn", "Software"); + put("SecureRandom.TIGERPRNG", gnu.java.security.jce.prng.TigerRandomSpi.class.getName()); + put("SecureRandom.TIGERPRNG ImplementedIn", "Software"); + put("SecureRandom.HAVALPRNG", gnu.java.security.jce.prng.HavalRandomSpi.class.getName()); + put("SecureRandom.HAVALPRNG ImplementedIn", "Software"); + put("SecureRandom.WHIRLPOOLPRNG", gnu.java.security.jce.prng.WhirlpoolRandomSpi.class.getName()); + put("SecureRandom.WHIRLPOOLPRNG ImplementedIn", "Software"); + + put("Alg.Alias.SecureRandom.SHA-1PRNG", "SHA-160PRNG"); + put("Alg.Alias.SecureRandom.SHA1PRNG", "SHA-160PRNG"); + put("Alg.Alias.SecureRandom.SHAPRNG", "SHA-160PRNG"); + put("Alg.Alias.SecureRandom.SHA-256PRNG", "SHA-256PRNG"); + put("Alg.Alias.SecureRandom.SHA-2-1PRNG", "SHA-256PRNG"); + put("Alg.Alias.SecureRandom.SHA-384PRNG", "SHA-384PRNG"); + put("Alg.Alias.SecureRandom.SHA-2-2PRNG", "SHA-384PRNG"); + put("Alg.Alias.SecureRandom.SHA-512PRNG", "SHA-512PRNG"); + put("Alg.Alias.SecureRandom.SHA-2-3PRNG", "SHA-512PRNG"); + // CertificateFactory put("CertificateFactory.X509", X509CertificateFactory.class.getName()); @@ -166,14 +259,6 @@ public final class Gnu extends Provider // CertStore put("CertStore.Collection", CollectionCertStoreImpl.class.getName()); - // KeyAgreement - put("KeyAgreement.DiffieHellman", gnu.javax.crypto.DiffieHellmanImpl.class.getName()); - put("Alg.Alias.KeyAgreement.DH", "DiffieHellman"); - - // Cipher - put("Cipher.RSAES-PKCS1-v1_5", gnu.javax.crypto.RSACipherImpl.class.getName()); - put("Alg.Alias.Cipher.RSA", "RSAES-PKCS1-v1_5"); - return null; } }); diff --git a/gnu/java/security/provider/GnuDSAPrivateKey.java b/gnu/java/security/provider/GnuDSAPrivateKey.java index aac2faab2..e79e8d6b6 100644 --- a/gnu/java/security/provider/GnuDSAPrivateKey.java +++ b/gnu/java/security/provider/GnuDSAPrivateKey.java @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.java.security.provider; import gnu.java.security.OID; +import gnu.java.security.Registry; import gnu.java.security.der.DER; import gnu.java.security.der.DERValue; import gnu.java.security.der.DERWriter; @@ -110,7 +111,7 @@ public class GnuDSAPrivateKey implements DSAPrivateKey pki.add(new DERValue(DER.INTEGER, BigInteger.ZERO)); ArrayList algId = new ArrayList(2); algId.add(new DERValue(DER.OBJECT_IDENTIFIER, - new OID("1.2.840.10040.4.1"))); + new OID(Registry.DSA_OID_STRING))); ArrayList algParams = new ArrayList(3); algParams.add(new DERValue(DER.INTEGER, p)); algParams.add(new DERValue(DER.INTEGER, q)); diff --git a/gnu/java/security/provider/GnuDSAPublicKey.java b/gnu/java/security/provider/GnuDSAPublicKey.java index 41195fa99..73b9da1e0 100644 --- a/gnu/java/security/provider/GnuDSAPublicKey.java +++ b/gnu/java/security/provider/GnuDSAPublicKey.java @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.java.security.provider; import gnu.java.security.OID; +import gnu.java.security.Registry; import gnu.java.security.der.BitString; import gnu.java.security.der.DER; import gnu.java.security.der.DERValue; @@ -97,7 +98,7 @@ public class GnuDSAPublicKey implements DSAPublicKey ArrayList spki = new ArrayList(2); ArrayList alg = new ArrayList(2); alg.add(new DERValue(DER.OBJECT_IDENTIFIER, - new OID("1.2.840.113549.1.1.1"))); + new OID(Registry.DSA_OID_STRING))); ArrayList params = new ArrayList(3); params.add(new DERValue(DER.INTEGER, p)); params.add(new DERValue(DER.INTEGER, q)); diff --git a/gnu/java/security/provider/GnuRSAPrivateKey.java b/gnu/java/security/provider/GnuRSAPrivateKey.java index b09fc88bc..cda9f8eac 100644 --- a/gnu/java/security/provider/GnuRSAPrivateKey.java +++ b/gnu/java/security/provider/GnuRSAPrivateKey.java @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.java.security.provider; import gnu.java.security.OID; +import gnu.java.security.Registry; import gnu.java.security.der.DER; import gnu.java.security.der.DERValue; @@ -154,7 +155,7 @@ class GnuRSAPrivateKey implements RSAPrivateCrtKey pki.add(new DERValue(DER.INTEGER, BigInteger.ZERO)); ArrayList alg = new ArrayList(2); alg.add(new DERValue(DER.OBJECT_IDENTIFIER, - new OID("1.2.840.113549.1.1.1"))); + new OID(Registry.RSA_OID_STRING))); alg.add(new DERValue(DER.NULL, null)); pki.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, alg)); pki.add(new DERValue(DER.OCTET_STRING, pk.getEncoded())); diff --git a/gnu/java/security/provider/GnuRSAPublicKey.java b/gnu/java/security/provider/GnuRSAPublicKey.java index a35e761c0..3bdb6629b 100644 --- a/gnu/java/security/provider/GnuRSAPublicKey.java +++ b/gnu/java/security/provider/GnuRSAPublicKey.java @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.java.security.provider; import gnu.java.security.OID; +import gnu.java.security.Registry; import gnu.java.security.der.BitString; import gnu.java.security.der.DER; import gnu.java.security.der.DERValue; @@ -98,7 +99,7 @@ class GnuRSAPublicKey implements RSAPublicKey DERValue rsapk = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, key); ArrayList alg = new ArrayList(2); alg.add(new DERValue(DER.OBJECT_IDENTIFIER, - new OID("1.2.840.113549.1.1.1"))); + new OID(Registry.RSA_OID_STRING))); alg.add(new DERValue(DER.NULL, null)); ArrayList spki = new ArrayList(2); spki.add(new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, alg)); diff --git a/gnu/java/security/sig/BaseSignature.java b/gnu/java/security/sig/BaseSignature.java new file mode 100644 index 000000000..dd964d481 --- /dev/null +++ b/gnu/java/security/sig/BaseSignature.java @@ -0,0 +1,261 @@ +/* BaseSignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Map; +import java.util.Random; + +/** + *

A base abstract class to facilitate implementations of concrete + * Signatures.

+ */ +public abstract class BaseSignature implements ISignature +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The canonical name of this signature scheme. */ + protected String schemeName; + + /** The underlying message digest instance for this signature scheme. */ + protected IMessageDigest md; + + /** The public key to use when verifying signatures. */ + protected PublicKey publicKey; + + /** The private key to use when generating signatures (signing). */ + protected PrivateKey privateKey; + + /** The optional {@link Random} instance to use. */ + private Random rnd; + + /** The optional {@link IRandom} instance to use. */ + private IRandom irnd; + + /** Our default source of randomness. */ + private PRNG prng = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial constructor. + * + * @param schemeName the name of this signature scheme. + * @param md the underlying instance of the message digest algorithm. + * @throws IllegalArgumentException if the designated hash instance is + * null. + */ + protected BaseSignature(String schemeName, IMessageDigest md) + { + super(); + + this.schemeName = schemeName; + if (md == null) + throw new IllegalArgumentException("Message digest MUST NOT be null"); + + this.md = md; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.sig.ISignature interface implementation ---------------------- + + public String name() + { + return schemeName + "-" + md.name(); + } + + public void setupVerify(Map attributes) throws IllegalArgumentException + { + setup(attributes); + + // do we have a public key? + PublicKey key = (PublicKey) attributes.get(VERIFIER_KEY); + if (key != null) + { + setupForVerification(key); + } + } + + public void setupSign(Map attributes) throws IllegalArgumentException + { + setup(attributes); + + // do we have a private key? + PrivateKey key = (PrivateKey) attributes.get(SIGNER_KEY); + if (key != null) + { + setupForSigning(key); + } + } + + public void update(byte b) + { + if (md == null) + { + throw new IllegalStateException(); + } + md.update(b); + } + + public void update(byte[] b, int off, int len) + { + if (md == null) + { + throw new IllegalStateException(); + } + md.update(b, off, len); + } + + public Object sign() + { + if (md == null || privateKey == null) + { + throw new IllegalStateException(); + } + + return generateSignature(); + } + + public boolean verify(Object sig) + { + if (md == null || publicKey == null) + { + throw new IllegalStateException(); + } + + return verifySignature(sig); + } + + // abstract methods to be implemented by concrete subclasses --------------- + + public abstract Object clone(); + + protected abstract void setupForVerification(PublicKey key) + throws IllegalArgumentException; + + protected abstract void setupForSigning(PrivateKey key) + throws IllegalArgumentException; + + protected abstract Object generateSignature() throws IllegalStateException; + + protected abstract boolean verifySignature(Object signature) + throws IllegalStateException; + + // Other instance methods -------------------------------------------------- + + /** Initialises the internal fields of this instance. */ + protected void init() + { + md.reset(); + rnd = null; + irnd = null; + publicKey = null; + privateKey = null; + } + + /** + *

Fills the designated byte array with random data.

+ * + * @param buffer the byte array to fill with random data. + */ + protected void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else if (irnd != null) + { + try + { + irnd.nextBytes(buffer, 0, buffer.length); + } + catch (IllegalStateException x) + { + throw new RuntimeException("nextRandomBytes(): " + + String.valueOf(x)); + } + catch (LimitReachedException x) + { + throw new RuntimeException("nextRandomBytes(): " + + String.valueOf(x)); + } + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private void setup(Map attributes) + { + init(); + + // do we have a Random or SecureRandom, or should we use our own? + Object obj = attributes.get(SOURCE_OF_RANDOMNESS); + if (obj instanceof Random) + { + rnd = (Random) obj; + } + else if (obj instanceof IRandom) + { + irnd = (IRandom) obj; + } + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/gnu/java/security/sig/ISignature.java b/gnu/java/security/sig/ISignature.java new file mode 100644 index 000000000..118b7701a --- /dev/null +++ b/gnu/java/security/sig/ISignature.java @@ -0,0 +1,169 @@ +/* ISignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig; + +import java.util.Map; + +/** + *

The visible methods of every signature-with-appendix scheme.

+ * + *

The Handbook of Applied Cryptography (HAC), by A. Menezes & al. states: + * "Digital signature schemes which require the message as input to the + * verification algorithm are called digital signature schemes with + * appendix. ... They rely on cryptographic hash functions rather than + * customised redundancy functions, and are less prone to existential forgery + * attacks."

+ * + *

References:

+ *
    + *
  1. Handbook of Applied + * Cryptography, Alfred J. Menezes, Paul C. van Oorschot and Scott A. + * Vanstone. Section 11.2.2 Digital signature schemes with appendix.
  2. + *
+ * + * @version $Revision: 1.1.4.1 $ + */ +public interface ISignature extends Cloneable +{ + + // Constants + // ------------------------------------------------------------------------- + + /** Property name of the verifier's public key. */ + public static final String VERIFIER_KEY = "gnu.crypto.sig.public.key"; + + /** Property name of the signer's private key. */ + public static final String SIGNER_KEY = "gnu.crypto.sig.private.key"; + + /** + * Property name of an optional {@link java.security.SecureRandom}, + * {@link java.util.Random}, or {@link gnu.crypto.prng.IRandom} instance to + * use. The default is to use a classloader singleton from + * {@link gnu.crypto.util.PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.sig.prng"; + + // Methods + // ------------------------------------------------------------------------- + + /** + *

Returns the canonical name of this signature scheme.

+ * + * @return the canonical name of this instance. + */ + String name(); + + /** + *

Initialises this instance for signature verification.

+ * + * @param attributes the attributes to use for setting up this instance. + * @throws IllegalArgumentException if the designated public key is not + * appropriate for this signature scheme. + * @see #SOURCE_OF_RANDOMNESS + * @see #VERIFIER_KEY + */ + void setupVerify(Map attributes) throws IllegalArgumentException; + + /** + *

Initialises this instance for signature generation.

+ * + * @param attributes the attributes to use for setting up this instance. + * @throws IllegalArgumentException if the designated private key is not + * appropriate for this signature scheme. + * @see #SOURCE_OF_RANDOMNESS + * @see #SIGNER_KEY + */ + void setupSign(Map attributes) throws IllegalArgumentException; + + /** + *

Digests one byte of a message for signing or verification purposes.

+ * + * @param b the message byte to digest. + * @throws IllegalStateException if this instance was not setup for + * signature generation/verification. + */ + void update(byte b) throws IllegalStateException; + + /** + *

Digests a sequence of bytes from a message for signing or verification + * purposes.

+ * + * @param buffer the byte sequence to consider. + * @param offset the byte poisition in buffer of the first byte + * to consider. + * @param length the number of bytes in buffer starting from the + * byte at index offset to digest. + * @throws IllegalStateException if this instance was not setup for + * signature generation/verification. + */ + void update(byte[] buffer, int offset, int length) + throws IllegalStateException; + + /** + *

Terminates a signature generation phase by digesting and processing the + * context of the underlying message digest algorithm instance.

+ * + * @return a {@link Object} representing the native output of the signature + * scheme implementation. + * @throws IllegalStateException if this instance was not setup for + * signature generation. + */ + Object sign() throws IllegalStateException; + + /** + *

Terminates a signature verification phase by digesting and processing + * the context of the underlying message digest algorithm instance.

+ * + * @param signature a native signature object previously generated by an + * invocation of the sign() method. + * @return true iff the outpout of the verification phase + * confirms that the designated signature object has been generated using the + * corresponding public key of the recepient. + * @throws IllegalStateException if this instance was not setup for + * signature verification. + */ + boolean verify(Object signature) throws IllegalStateException; + + /** + *

Returns a clone copy of this instance.

+ * + * @return a clone copy of this instance. + */ + Object clone(); +} diff --git a/gnu/java/security/sig/ISignatureCodec.java b/gnu/java/security/sig/ISignatureCodec.java new file mode 100644 index 000000000..86d190944 --- /dev/null +++ b/gnu/java/security/sig/ISignatureCodec.java @@ -0,0 +1,68 @@ +/* ISignatureCodec.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig; + +import gnu.java.security.Registry; + +/** + *

The visible methods of an object that knows how to encode and decode + * cryptographic signatures. Codecs are useful for (a) externalising signature + * output data for storage and on-the-wire transmission, as well as (b) re- + * creating their internal Java representation from external sources.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public interface ISignatureCodec +{ + + // Constants + // ------------------------------------------------------------------------- + + /** Constant identifying the Raw encoding format. */ + int RAW_FORMAT = Registry.RAW_ENCODING_ID; + + // Method(s) + // ------------------------------------------------------------------------- + + int getFormatID(); + + byte[] encodeSignature(Object signature); + + Object decodeSignature(byte[] input); +} diff --git a/gnu/java/security/sig/SignatureCodecFactory.java b/gnu/java/security/sig/SignatureCodecFactory.java new file mode 100644 index 000000000..c5b2ccd4b --- /dev/null +++ b/gnu/java/security/sig/SignatureCodecFactory.java @@ -0,0 +1,226 @@ +/* SignatureCodecFactory.java -- Factory to instantiate Signature codecs + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.sig.dss.DSSSignatureRawCodec; +import gnu.java.security.sig.dss.DSSSignatureX509Codec; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureRawCodec; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; +import gnu.java.security.sig.rsa.RSAPSSSignatureRawCodec; +import gnu.java.security.util.FormatUtil; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A Factory class to instantiate Signature codecs. + */ +public class SignatureCodecFactory +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private SignatureCodecFactory() + { + super(); + } + + /** + * Returns the appropriate codec given a composed signature algorithm and an + * encoding format. A composed name is formed by the concatenation of the + * canonical signature algorithm name, the forward slash character + * / and the canonical name of the encoding format. + *

+ * When the encoding format name is missing, the Raw encoding format is + * assumed. When this is the case the trailing forward slash is discarded from + * the name. + * + * @param name the case-insensitive, possibly composed, signature codec name. + * @return an instance of the signaturecodec, or null if none + * found. + */ + public static ISignatureCodec getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + if (name.length() == 0) + return null; + + if (name.startsWith("/")) + return null; + + if (name.endsWith("/")) + return getInstance(name.substring(0, name.length() - 1), + Registry.RAW_ENCODING_ID); + + int i = name.indexOf("/"); + if (i == - 1) + return getInstance(name, Registry.RAW_ENCODING_ID); + + String sigName = name.substring(0, i); + String formatName = name.substring(i + 1); + return getInstance(sigName, formatName); + } + + /** + * Returns an instance of a signature codec given the canonical name of the + * signature algorithm, and that of the encoding format. + * + * @param name the case-insensitive signature algorithm name. + * @param format the name of the format to use when encodigng/decoding + * signatures generated by the named algorithm. + * @return an instance of the signature codec, or null if none + * found. + */ + public static ISignatureCodec getInstance(String name, String format) + { + int formatID = FormatUtil.getFormatID(format); + if (formatID == 0) + return null; + + return getInstance(name, formatID); + } + + /** + * Returns an instance of a signature codec given the canonical name of the + * signature algorithm, and the identifier of the format to use when + * encoding/decoding signatures generated by that algorithm. + * + * @param name the case-insensitive signature algorithm name. + * @param formatID the identifier of the format to use when encoding / + * decoding signatures generated by the designated algorithm. + * @return an instance of the signature codec, or null if none + * found. + */ + public static ISignatureCodec getInstance(String name, int formatID) + { + if (name == null) + return null; + + name = name.trim(); + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + return getRawCodec(name); + case Registry.X509_ENCODING_ID: + return getX509Codec(name); + } + + return null; + } + + /** + * Returns a {@link Set} of supported signature codec names. + * + * @return a {@link Set} of the names of supported signature codec (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(Registry.DSS_SIG + "/" + Registry.RAW_ENCODING_SHORT_NAME); + hs.add(Registry.DSS_SIG + "/" + Registry.X509_ENCODING_SORT_NAME); + Set hashNames = HashFactory.getNames(); + for (Iterator it = hashNames.iterator(); it.hasNext();) + { + String mdName = (String) it.next(); + String name = Registry.RSA_PKCS1_V1_5_SIG + "-" + mdName; + hs.add(name + "/" + Registry.RAW_ENCODING_SHORT_NAME); + hs.add(name + "/" + Registry.X509_ENCODING_SORT_NAME); + name = Registry.RSA_PSS_SIG + "-" + mdName; + hs.add(name + "/" + Registry.RAW_ENCODING_SHORT_NAME); + } + + names = Collections.unmodifiableSet(hs); + } + + return names; + } + + /** + * @param name the trimmed name of a signature algorithm. + * @return a Raw format codec for the designated signature algorithm, or + * null if none exists. + */ + private static ISignatureCodec getRawCodec(String name) + { + ISignatureCodec result = null; + if (name.equalsIgnoreCase(Registry.DSA_SIG) + || name.equalsIgnoreCase(Registry.DSS_SIG)) + result = new DSSSignatureRawCodec(); + else + { + name = name.toLowerCase(); + if (name.startsWith(Registry.RSA_PKCS1_V1_5_SIG)) + result = new RSAPKCS1V1_5SignatureRawCodec(); + else if (name.startsWith(Registry.RSA_PSS_SIG)) + result = new RSAPSSSignatureRawCodec(); + } + + return result; + } + + /** + * @param name the trimmed name of a signature algorithm. + * @return a X.509 format codec for the designated signature algorithm, or + * null if none exists. + */ + private static ISignatureCodec getX509Codec(String name) + { + ISignatureCodec result = null; + if (name.equalsIgnoreCase(Registry.DSA_SIG) + || name.equalsIgnoreCase(Registry.DSS_SIG)) + result = new DSSSignatureX509Codec(); + else + { + name = name.toLowerCase(); + if (name.startsWith(Registry.RSA_PKCS1_V1_5_SIG)) + result = new RSAPKCS1V1_5SignatureX509Codec(); + } + + return result; + } +} diff --git a/gnu/java/security/sig/SignatureFactory.java b/gnu/java/security/sig/SignatureFactory.java new file mode 100644 index 000000000..d5bd728ad --- /dev/null +++ b/gnu/java/security/sig/SignatureFactory.java @@ -0,0 +1,113 @@ +/* SignatureFactory.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.dss.DSSSignature; +import gnu.java.security.sig.rsa.RSASignatureFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory to instantiate signature-with-appendix handlers. + */ +public class SignatureFactory +{ + private static Set names; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private SignatureFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * Returns an instance of a signature-with-appendix scheme given its name. + * + * @param ssa the case-insensitive signature-with-appendix scheme name. + * @return an instance of the scheme, or null if none found. + */ + public static final ISignature getInstance(String ssa) + { + if (ssa == null) + { + return null; + } + + ssa = ssa.trim(); + ssa = ssa.toLowerCase(); + ISignature result = null; + if (ssa.equalsIgnoreCase(Registry.DSA_SIG) || ssa.equals(Registry.DSS_SIG)) + { + result = new DSSSignature(); + } + else if (ssa.startsWith(Registry.RSA_SIG_PREFIX)) + result = RSASignatureFactory.getInstance(ssa); + + return result; + } + + /** + * Returns a {@link Set} of signature-with-appendix scheme names supported + * by this Factory. + * + * @return a {@link Set} of signature-with-appendix scheme names (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(Registry.DSS_SIG); + hs.addAll(RSASignatureFactory.getNames()); + + names = Collections.unmodifiableSet(hs); + } + + return names; + } +} diff --git a/gnu/java/security/sig/dss/DSSSignature.java b/gnu/java/security/sig/dss/DSSSignature.java new file mode 100644 index 000000000..dd4087316 --- /dev/null +++ b/gnu/java/security/sig/dss/DSSSignature.java @@ -0,0 +1,347 @@ +/* DSSSignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.dss; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.hash.Sha160; +import gnu.java.security.prng.IRandom; +import gnu.java.security.sig.BaseSignature; +import gnu.java.security.sig.ISignature; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +/** + *

The DSS (Digital Signature Standard) algorithm makes use of the following + * parameters:

+ * + *
    + *
  1. p: A prime modulus, where 2L-1 < p < 2L + * for 512 <= L <= 1024 and L a + * multiple of 64.
  2. + *
  3. q: A prime divisor of p - 1, where 2159 + * < q < 2160.
  4. + *
  5. g: Where g = h(p-1)/q mod p, where + * h is any integer with 1 < h < p - 1 such + * that h (p-1)/q mod p > 1 (g has order + * q mod p).
  6. + *
  7. x: A randomly or pseudorandomly generated integer with 0 < x + * < q.
  8. + *
  9. y: y = gx mod p.
  10. + *
  11. k: A randomly or pseudorandomly generated integer with 0 < k + * < q.
  12. + *
+ * + *

The integers p, q, and g can be + * public and can be common to a group of users. A user's private and public + * keys are x and y, respectively. They are normally + * fixed for a period of time. Parameters x and k are + * used for signature generation only, and must be kept secret. Parameter + * k must be regenerated for each signature.

+ * + *

The signature of a message M is the pair of numbers r + * and s computed according to the equations below:

+ * + *
    + *
  • r = (gk mod p) mod q and
  • + *
  • s = (k-1(SHA(M) + xr)) mod q.
  • + *
+ * + *

In the above, k-1 is the multiplicative inverse of + * k, mod q; i.e., (k-1 k) mod q = 1 + * and 0 < k-1 < q. The value of SHA(M) + * is a 160-bit string output by the Secure Hash Algorithm specified in FIPS 180. + * For use in computing s, this string must be converted to an + * integer.

+ * + *

As an option, one may wish to check if r == 0 or s == 0 + * . If either r == 0 or s == 0, a new value + * of k should be generated and the signature should be + * recalculated (it is extremely unlikely that r == 0 or s == + * 0 if signatures are generated properly).

+ * + *

The signature is transmitted along with the message to the verifier.

+ * + *

References:

+ *
    + *
  1. Digital + * Signature Standard (DSS), Federal Information Processing Standards + * Publication 186. National Institute of Standards and Technology.
  2. + *
+ * + * @version $Revision: 1.1.4.1 $ + */ +public class DSSSignature extends BaseSignature +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public DSSSignature() + { + super(Registry.DSS_SIG, new Sha160()); + } + + /** Private constructor for cloning purposes. */ + private DSSSignature(DSSSignature that) + { + this(); + + this.publicKey = that.publicKey; + this.privateKey = that.privateKey; + this.md = (IMessageDigest) that.md.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.SIGNER_KEY, k); + sig.setupSign(attributes); + + return sig.computeRS(h); + } + + public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h, + Random rnd) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.SIGNER_KEY, k); + if (rnd != null) + { + attributes.put(ISignature.SOURCE_OF_RANDOMNESS, rnd); + } + sig.setupSign(attributes); + + return sig.computeRS(h); + } + + public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h, + IRandom irnd) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.SIGNER_KEY, k); + if (irnd != null) + { + attributes.put(ISignature.SOURCE_OF_RANDOMNESS, irnd); + } + sig.setupSign(attributes); + + return sig.computeRS(h); + } + + public static final boolean verify(final DSAPublicKey k, final byte[] h, + final BigInteger[] rs) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.VERIFIER_KEY, k); + sig.setupVerify(attributes); + + return sig.checkRS(rs, h); + } + + // Implementation of abstract methods in superclass + // ------------------------------------------------------------------------- + + public Object clone() + { + return new DSSSignature(this); + } + + protected void setupForVerification(PublicKey k) + throws IllegalArgumentException + { + if (!(k instanceof DSAPublicKey)) + { + throw new IllegalArgumentException(); + } + this.publicKey = k; + } + + protected void setupForSigning(PrivateKey k) throws IllegalArgumentException + { + if (!(k instanceof DSAPrivateKey)) + { + throw new IllegalArgumentException(); + } + this.privateKey = k; + } + + protected Object generateSignature() throws IllegalStateException + { + // BigInteger p = ((DSAPrivateKey) privateKey).getParams().getP(); + // BigInteger q = ((DSAPrivateKey) privateKey).getParams().getQ(); + // BigInteger g = ((DSAPrivateKey) privateKey).getParams().getG(); + // BigInteger x = ((DSAPrivateKey) privateKey).getX(); + // BigInteger m = new BigInteger(1, md.digest()); + // BigInteger k, r, s; + // + // byte[] kb = new byte[20]; // we'll use 159 bits only + // while (true) { + // this.nextRandomBytes(kb); + // k = new BigInteger(1, kb); + // k.clearBit(159); + // r = g.modPow(k, p).mod(q); + // if (r.equals(BigInteger.ZERO)) { + // continue; + // } + // s = m.add(x.multiply(r)).multiply(k.modInverse(q)).mod(q); + // if (s.equals(BigInteger.ZERO)) { + // continue; + // } + // break; + // } + final BigInteger[] rs = computeRS(md.digest()); + + // return encodeSignature(r, s); + return encodeSignature(rs[0], rs[1]); + } + + protected boolean verifySignature(Object sig) throws IllegalStateException + { + final BigInteger[] rs = decodeSignature(sig); + // BigInteger r = rs[0]; + // BigInteger s = rs[1]; + // + // BigInteger g = ((DSAPublicKey) publicKey).getParams().getG(); + // BigInteger p = ((DSAPublicKey) publicKey).getParams().getP(); + // BigInteger q = ((DSAPublicKey) publicKey).getParams().getQ(); + // BigInteger y = ((DSAPublicKey) publicKey).getY(); + // BigInteger w = s.modInverse(q); + // + // byte bytes[] = md.digest(); + // BigInteger u1 = w.multiply(new BigInteger(1, bytes)).mod(q); + // BigInteger u2 = r.multiply(w).mod(q); + // + // BigInteger v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q); + // return v.equals(r); + return checkRS(rs, md.digest()); + } + + // Other instance methods + // ------------------------------------------------------------------------- + + /** + * Returns the output of a signature generation phase.

+ * + * @return an object encapsulating the DSS signature pair r and + * s. + */ + private Object encodeSignature(BigInteger r, BigInteger s) + { + return new BigInteger[] { r, s }; + } + + /** + * Returns the output of a previously generated signature object as a pair + * of {@link java.math.BigInteger}.

+ * + * @return the DSS signature pair r and s. + */ + private BigInteger[] decodeSignature(Object signature) + { + return (BigInteger[]) signature; + } + + private BigInteger[] computeRS(final byte[] digestBytes) + { + final BigInteger p = ((DSAPrivateKey) privateKey).getParams().getP(); + final BigInteger q = ((DSAPrivateKey) privateKey).getParams().getQ(); + final BigInteger g = ((DSAPrivateKey) privateKey).getParams().getG(); + final BigInteger x = ((DSAPrivateKey) privateKey).getX(); + final BigInteger m = new BigInteger(1, digestBytes); + BigInteger k, r, s; + + final byte[] kb = new byte[20]; // we'll use 159 bits only + while (true) + { + this.nextRandomBytes(kb); + k = new BigInteger(1, kb); + k.clearBit(159); + r = g.modPow(k, p).mod(q); + if (r.equals(BigInteger.ZERO)) + { + continue; + } + s = m.add(x.multiply(r)).multiply(k.modInverse(q)).mod(q); + if (s.equals(BigInteger.ZERO)) + { + continue; + } + break; + } + + return new BigInteger[] { r, s }; + } + + private boolean checkRS(final BigInteger[] rs, final byte[] digestBytes) + { + final BigInteger r = rs[0]; + final BigInteger s = rs[1]; + + final BigInteger g = ((DSAPublicKey) publicKey).getParams().getG(); + final BigInteger p = ((DSAPublicKey) publicKey).getParams().getP(); + final BigInteger q = ((DSAPublicKey) publicKey).getParams().getQ(); + final BigInteger y = ((DSAPublicKey) publicKey).getY(); + final BigInteger w = s.modInverse(q); + + final BigInteger u1 = w.multiply(new BigInteger(1, digestBytes)).mod(q); + final BigInteger u2 = r.multiply(w).mod(q); + + final BigInteger v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q); + return v.equals(r); + } +} diff --git a/gnu/java/security/sig/dss/DSSSignatureRawCodec.java b/gnu/java/security/sig/dss/DSSSignatureRawCodec.java new file mode 100644 index 000000000..fa25c9201 --- /dev/null +++ b/gnu/java/security/sig/dss/DSSSignatureRawCodec.java @@ -0,0 +1,191 @@ +/* DSSSignatureRawCodec.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.dss; + +import gnu.java.security.Registry; +import gnu.java.security.sig.ISignatureCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; + +/** + *

An object that implements the {@link ISignatureCodec} operations for the + * Raw format to use with DSS signatures.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class DSSSignatureRawCodec implements ISignatureCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.sig.ISignatureCodec interface implementation ----------------- + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + *

Returns the encoded form of the designated DSS (Digital Signature + * Standard) signature object according to the Raw format supported by + * this library.

+ * + *

The Raw format for a DSA signature, in this implementation, is a + * byte sequence consisting of the following:

+ * + *
    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DSS_SIGNATURE},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the DSS parameter + * r in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSS parameter r,
  8. + *
  9. 4-byte count of following bytes representing the DSS parameter + * s,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DSS parameter s.
  12. + *
+ * + * @param signature the signature to encode, consisting of the two DSS + * parameters r and s as a {@link java.math.BigInteger} + * array. + * @return the Raw format encoding of the designated signature. + * @exception IllegalArgumentException if the designated signature is not a + * DSS (Digital Signature Standard) one. + */ + public byte[] encodeSignature(Object signature) + { + BigInteger r, s; + try + { + BigInteger[] sig = (BigInteger[]) signature; + r = sig[0]; + s = sig[1]; + } + catch (Exception x) + { + throw new IllegalArgumentException("key"); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[0]); + baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[1]); + baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[2]); + baos.write(Registry.MAGIC_RAW_DSS_SIGNATURE[3]); + + // version + baos.write(0x01); + + // r + byte[] buffer = r.toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // s + buffer = s.toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + public Object decodeSignature(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DSS_SIGNATURE[0] + || k[1] != Registry.MAGIC_RAW_DSS_SIGNATURE[1] + || k[2] != Registry.MAGIC_RAW_DSS_SIGNATURE[2] + || k[3] != Registry.MAGIC_RAW_DSS_SIGNATURE[3]) + { + throw new IllegalArgumentException("magic"); + } + + // version + if (k[4] != 0x01) + { + throw new IllegalArgumentException("version"); + } + + int i = 5; + int l; + byte[] buffer; + + // r + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger r = new BigInteger(1, buffer); + + // s + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger s = new BigInteger(1, buffer); + + return new BigInteger[] { r, s }; + } +} diff --git a/gnu/java/security/sig/dss/DSSSignatureX509Codec.java b/gnu/java/security/sig/dss/DSSSignatureX509Codec.java new file mode 100644 index 000000000..81a11da42 --- /dev/null +++ b/gnu/java/security/sig/dss/DSSSignatureX509Codec.java @@ -0,0 +1,192 @@ +/* DSSSignatureX509Codec.java -- X.509 encoder/decoder for DSS signatures + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.dss; + +import gnu.java.security.Registry; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.sig.ISignatureCodec; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.util.ArrayList; + +/** + * An implementation of an {@link ISignatureCodec} that knows to encode and + * decode DSS signatures into the DER-encoded form of the ASN.1 structure + * defined in RFC-2459 as described in the next paragraphs. + *

+ * Digital signatures when transmitted in an X.509 certificates are encoded + * in DER (Distinguished Encoding Rules) as a BIT STRING; i.e. + * + *

+ * Certificate ::= SEQUENCE {
+ *   tbsCertificate       TBSCertificate,
+ *   signatureAlgorithm   AlgorithmIdentifier,
+ *   signature            BIT STRING
+ * }
+ * 
+ *

+ * The output of the encoder, and the input of the decoder, of this codec are + * then the bytes of such a BIT STRING. + *

+ * RFC-2459 states that, for the Digital Signature Standard (DSS), which + * generates two MPIs, commonly called r and s, as the + * result of digitally signing a message, these two numbers will be transferred + * as the following ASN.1 structure: + * + *

+ *   Dss-Sig-Value ::= SEQUENCE {
+ *     r  INTEGER,
+ *     s  INTEGER
+ *   }
+ * 
+ */ +public class DSSSignatureX509Codec + implements ISignatureCodec +{ + // implicit 0-arguments constructor + + public int getFormatID() + { + return Registry.X509_ENCODING_ID; + } + + /** + * Encodes a DSS Signature output as a signature BIT STRING as defined + * in the documentation of this class. + * + * @param signature the output of the DSS signature algorithm; i.e. the value + * returned by the invocation of + * {@link gnu.java.security.sig.ISignature#sign()} method. In the + * case of a DSS signature this is an array of two MPIs called + * r and s. + * @return the DER-encoded output of a DSS signature as defined in rfc-2459. + * @throws InvalidParameterException if an exception occurs during the + * marshalling process. + */ + public byte[] encodeSignature(Object signature) + { + BigInteger[] rs = (BigInteger[]) signature; + + DERValue derR = new DERValue(DER.INTEGER, rs[0]); + DERValue derS = new DERValue(DER.INTEGER, rs[1]); + + ArrayList dssSigValue = new ArrayList(2); + dssSigValue.add(derR); + dssSigValue.add(derS); + DERValue derDssSigValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + dssSigValue); + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derDssSigValue); + result = baos.toByteArray(); + + // put it in a BIT STRING + DERValue derSignature = new DERValue(DER.BIT_STRING, + new BitString(result)); + baos.reset(); + DERWriter.write(baos, derSignature); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return result; + } + + /** + * Decodes a signature BIT STRING as defined in the documentation of + * this class. + * + * @param input the byte array to unmarshall into a valid DSS signature + * instance; i.e. an array of two MPIs. MUST NOT be null. + * @return an array of two MPIs, r and s in this + * order, decoded from the designated input. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public Object decodeSignature(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger r, s; + DERReader der = new DERReader(input); + try + { + DERValue derSignature = der.read(); + if (! (derSignature.getValue() instanceof BitString)) + throw new InvalidParameterException("Wrong signature field"); + + byte[] sBytes = ((BitString) derSignature.getValue()).toByteArray(); + der = new DERReader(sBytes); + + DERValue derDssSigValue = der.read(); + DerUtil.checkIsConstructed(derDssSigValue, "Wrong Dss-Sig-Value field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong R field"); + r = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong S field"); + s = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return new BigInteger[] { r, s }; + } +} diff --git a/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java b/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java new file mode 100644 index 000000000..efe580d51 --- /dev/null +++ b/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java @@ -0,0 +1,306 @@ +/* EME_PKCS1_V1_5.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; + +import java.io.ByteArrayOutputStream; +import java.security.interfaces.RSAKey; +import java.util.Random; + +/** + *

An implementation of the EME-PKCS1-V1.5 encoding and decoding methods.

+ * + *

EME-PKCS1-V1.5 is parameterised by the entity k which is the + * byte count of an RSA public shared modulus.

+ * + *

References:

+ *
    + *
  1. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class EME_PKCS1_V1_5 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private int k; + + private ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + /** Our default source of randomness. */ + private PRNG prng = PRNG.getInstance(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + private EME_PKCS1_V1_5(final int k) + { + super(); + + this.k = k; + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final EME_PKCS1_V1_5 getInstance(final int k) + { + if (k < 0) + { + throw new IllegalArgumentException("k must be a positive integer"); + } + return new EME_PKCS1_V1_5(k); + } + + public static final EME_PKCS1_V1_5 getInstance(final RSAKey key) + { + final int modBits = key.getModulus().bitLength(); + final int k = (modBits + 7) / 8; + return EME_PKCS1_V1_5.getInstance(k); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Generates an octet string PS of length k - mLen - + * 3 consisting of pseudo-randomly generated nonzero octets. The + * length of PS will be at least eight octets.

+ * + *

The method then concatenates PS, the message M, + * and other padding to form an encoded message EM of length + * k octets as:

+ * + *
+   *    EM = 0x00 || 0x02 || PS || 0x00 || M.
+   * 
+ * + *

This method uses a default PRNG to obtain the padding bytes.

+ * + * @param M the message to encode. + * @return the encoded message EM. + */ + public byte[] encode(final byte[] M) + { + // a. Generate an octet string PS of length k - mLen - 3 consisting + // of pseudo-randomly generated nonzero octets. The length of PS + // will be at least eight octets. + final byte[] PS = new byte[k - M.length - 3]; + + // FIXME. This should be configurable, somehow. + prng.nextBytes(PS); + int i = 0; + for (; i < PS.length; i++) + { + if (PS[i] == 0) + PS[i] = 1; + } + // b. Concatenate PS, the message M, and other padding to form an + // encoded message EM of length k octets as + // + // EM = 0x00 || 0x02 || PS || 0x00 || M. + return assembleEM(PS, M); + } + + /** + *

Similar to {@link #encode(byte[])} method, except that the source of + * randomness to use for obtaining the padding bytes (an instance of + * {@link IRandom}) is given as a parameter.

+ * + * @param M the message to encode. + * @param irnd the {@link IRandom} instance to use as a source of randomness. + * @return the encoded message EM. + */ + public byte[] encode(final byte[] M, final IRandom irnd) + { + final byte[] PS = new byte[k - M.length - 3]; + try + { + irnd.nextBytes(PS, 0, PS.length); + int i = 0; + outer: while (true) + { + for (; i < PS.length; i++) + { + if (PS[i] == 0x00) + { + System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1); + irnd.nextBytes(PS, PS.length - 1, 1); + continue outer; + } + } + break; + } + } + catch (IllegalStateException x) + { + throw new RuntimeException("encode(): " + String.valueOf(x)); + } + catch (LimitReachedException x) + { + throw new RuntimeException("encode(): " + String.valueOf(x)); + } + + return assembleEM(PS, M); + } + + /** + *

Similar to the {@link #encode(byte[], IRandom)} method, except that + * the source of randmoness is an instance of {@link Random}. + * + * @param M the message to encode. + * @param rnd the {@link Random} instance to use as a source of randomness. + * @return the encoded message EM. + */ + public byte[] encode(final byte[] M, final Random rnd) + { + final byte[] PS = new byte[k - M.length - 3]; + rnd.nextBytes(PS); + int i = 0; + outer: while (true) + { + for (; i < PS.length; i++) + { + if (PS[i] == 0x00) + { + System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1); + PS[PS.length - 1] = (byte) rnd.nextInt(); + continue outer; + } + } + break; + } + + return assembleEM(PS, M); + } + + /** + *

Separate the encoded message EM into an octet string + * PS consisting of nonzero octets and a message M + * as:

+ * + *
+   *    EM = 0x00 || 0x02 || PS || 0x00 || M.
+   * 
+ * + *

If the first octet of EM does not have hexadecimal value + * 0x00, if the second octet of EM does not have + * hexadecimal value 0x02, if there is no octet with hexadecimal + * value 0x00 to separate PS from M, + * or if the length of PS is less than 8 octets, + * output "decryption error" and stop.

+ + * @param EM the designated encoded message. + * @return the decoded message M framed in the designated + * EM value. + * @throws IllegalArgumentException if the length of the designated entity + * EM is different than k (the length in bytes of + * the public shared modulus), or if any of the conditions described above + * is detected. + */ + public byte[] decode(final byte[] EM) + { + // Separate the encoded message EM into an + // octet string PS consisting of nonzero octets and a message M as + // + // EM = 0x00 || 0x02 || PS || 0x00 || M. + // + // If the first octet of EM does not have hexadecimal value 0x00, if + // the second octet of EM does not have hexadecimal value 0x02, if + // there is no octet with hexadecimal value 0x00 to separate PS from + // M, or if the length of PS is less than 8 octets, output + // "decryption error" and stop. (See the note below.) + final int emLen = EM.length; + if (emLen != k) + { + throw new IllegalArgumentException("decryption error"); + } + if (EM[0] != 0x00) + { + throw new IllegalArgumentException("decryption error"); + } + if (EM[1] != 0x02) + { + throw new IllegalArgumentException("decryption error"); + } + int i = 2; + for (; i < emLen; i++) + { + if (EM[i] == 0x00) + { + break; + } + } + if (i >= emLen || i < 11) + { + throw new IllegalArgumentException("decryption error"); + } + i++; + final byte[] result = new byte[emLen - i]; + System.arraycopy(EM, i, result, 0, result.length); + return result; + } + + // helper methods ---------------------------------------------------------- + + private byte[] assembleEM(final byte[] PS, final byte[] M) + { + // b. Concatenate PS, the message M, and other padding to form an + // encoded message EM of length k octets as + // + // EM = 0x00 || 0x02 || PS || 0x00 || M. + baos.reset(); + baos.write(0x00); + baos.write(0x02); + baos.write(PS, 0, PS.length); + baos.write(0x00); + baos.write(M, 0, M.length); + final byte[] result = baos.toByteArray(); + baos.reset(); + + return result; + } +} diff --git a/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java b/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java new file mode 100644 index 000000000..27ab5d493 --- /dev/null +++ b/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java @@ -0,0 +1,299 @@ +/* EMSA_PKCS1_V1_5.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; + +import java.io.ByteArrayOutputStream; + +/** + *

An implementation of the EMSA-PKCS1-V1.5 encoding scheme.

+ * + *

EMSA-PKCS1-V1.5 is parameterised by the choice of hash function Hash and + * hLen which denotes the length in octets of the hash function output.

+ * + *

References:

+ *
    + *
  1. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ * + * @version $Revision: 1.2.2.1 $ + */ +public class EMSA_PKCS1_V1_5 implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /* Notes. + 1. For the six hash functions mentioned in Appendix B.1, the DER encoding + T of the DigestInfo value is equal to the following: + + MD2: (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 02 05 00 04 10 || H + MD5: (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 05 05 00 04 10 || H + SHA-1: (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H + SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H + SHA-384: (0x)30 41 30 0d 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30 || H + SHA-512: (0x)30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 || H + */ + private static final byte[] MD2_PREFIX = { (byte) 0x30, (byte) 0x20, + (byte) 0x30, (byte) 0x0c, + (byte) 0x06, (byte) 0x08, + (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, + (byte) 0x02, (byte) 0x02, + (byte) 0x05, (byte) 0x00, + (byte) 0x04, (byte) 0x10 }; + + private static final byte[] MD5_PREFIX = { (byte) 0x30, (byte) 0x20, + (byte) 0x30, (byte) 0x0c, + (byte) 0x06, (byte) 0x08, + (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, + (byte) 0x02, (byte) 0x05, + (byte) 0x05, (byte) 0x00, + (byte) 0x04, (byte) 0x10 }; + + private static final byte[] SHA160_PREFIX = { (byte) 0x30, (byte) 0x21, + (byte) 0x30, (byte) 0x09, + (byte) 0x06, (byte) 0x05, + (byte) 0x2b, (byte) 0x0e, + (byte) 0x03, (byte) 0x02, + (byte) 0x1a, (byte) 0x05, + (byte) 0x00, (byte) 0x04, + (byte) 0x14 }; + + private static final byte[] SHA256_PREFIX = { (byte) 0x30, (byte) 0x31, + (byte) 0x30, (byte) 0x0d, + (byte) 0x06, (byte) 0x09, + (byte) 0x60, (byte) 0x86, + (byte) 0x48, (byte) 0x01, + (byte) 0x65, (byte) 0x03, + (byte) 0x04, (byte) 0x02, + (byte) 0x01, (byte) 0x05, + (byte) 0x00, (byte) 0x04, + (byte) 0x20 }; + + private static final byte[] SHA384_PREFIX = { (byte) 0x30, (byte) 0x41, + (byte) 0x30, (byte) 0x0d, + (byte) 0x06, (byte) 0x09, + (byte) 0x60, (byte) 0x86, + (byte) 0x48, (byte) 0x01, + (byte) 0x65, (byte) 0x03, + (byte) 0x04, (byte) 0x02, + (byte) 0x02, (byte) 0x05, + (byte) 0x00, (byte) 0x04, + (byte) 0x30 }; + + private static final byte[] SHA512_PREFIX = { (byte) 0x30, (byte) 0x51, + (byte) 0x30, (byte) 0x0d, + (byte) 0x06, (byte) 0x09, + (byte) 0x60, (byte) 0x86, + (byte) 0x48, (byte) 0x01, + (byte) 0x65, (byte) 0x03, + (byte) 0x04, (byte) 0x02, + (byte) 0x03, (byte) 0x05, + (byte) 0x00, (byte) 0x04, + (byte) 0x40 }; + + /** The underlying hash function to use with this instance. */ + private IMessageDigest hash; + + /** The output size of the hash function in octets. */ + private int hLen; // TODO: field not used!!! investigate + + /** The DER part of DigestInfo not containing the hash value itself. */ + private byte[] prefix; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial private constructor to enforce use through Factory method.

+ * + * @param hash the message digest instance to use with this scheme instance. + */ + private EMSA_PKCS1_V1_5(final IMessageDigest hash) + { + super(); + + this.hash = hash; + hLen = hash.hashSize(); + final String name = hash.name(); + if (name.equals(Registry.MD2_HASH)) + { + prefix = MD2_PREFIX; + } + else if (name.equals(Registry.MD5_HASH)) + { + prefix = MD5_PREFIX; + } + else if (name.equals(Registry.SHA160_HASH)) + { + prefix = SHA160_PREFIX; + } + else if (name.equals(Registry.SHA256_HASH)) + { + prefix = SHA256_PREFIX; + } + else if (name.equals(Registry.SHA384_HASH)) + { + prefix = SHA384_PREFIX; + } + else if (name.equals(Registry.SHA512_HASH)) + { + prefix = SHA512_PREFIX; + } + else + { + throw new UnsupportedOperationException(); // should not happen + } + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of this object given a designated name of a hash + * function.

+ * + * @param mdName the canonical name of a hash function. + * @return an instance of this object configured for use with the designated + * options. + * @throws UnsupportedOperationException if the hash function is not + * implemented or does not have an ID listed in RFC-3447. + */ + public static final EMSA_PKCS1_V1_5 getInstance(final String mdName) + { + final IMessageDigest hash = HashFactory.getInstance(mdName); + final String name = hash.name(); + if (!(name.equals(Registry.MD2_HASH) || name.equals(Registry.MD5_HASH) + || name.equals(Registry.SHA160_HASH) + || name.equals(Registry.SHA256_HASH) + || name.equals(Registry.SHA384_HASH) || name.equals(Registry.SHA512_HASH))) + { + throw new UnsupportedOperationException("hash with no OID: " + name); + } + return new EMSA_PKCS1_V1_5(hash); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // Cloneable interface implementation -------------------------------------- + + public Object clone() + { + return getInstance(hash.name()); + } + + // own methods ------------------------------------------------------------- + + /** + *

Frames the hash of a message, along with an ID of the hash function in + * a DER sequence according to the specifications of EMSA-PKCS1-V1.5 as + * described in RFC-3447 (see class documentation).

+ * + * @param mHash the byte sequence resulting from applying the message digest + * algorithm Hash to the message M. + * @param emLen intended length in octets of the encoded message, at least + * tLen + 11, where tLen is the octet length of the + * DER encoding T of a certain value computed during the + * encoding operation. + * @return encoded message, an octet string of length emLen. + * @throws IllegalArgumentException if the message is too long, or if the + * intended encoded message length is too short. + */ + public byte[] encode(final byte[] mHash, final int emLen) + { + // 1. Apply the hash function to the message M to produce a hash value + // H: H = Hash(M). + // If the hash function outputs "message too long," output "message + // too long" and stop. + // 2. Encode the algorithm ID for the hash function and the hash value + // into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with + // the Distinguished Encoding Rules (DER), where the type DigestInfo + // has the syntax + // DigestInfo ::= SEQUENCE { + // digestAlgorithm AlgorithmIdentifier, + // digest OCTET STRING + // } + // The first field identifies the hash function and the second contains + // the hash value. Let T be the DER encoding of the DigestInfo value + // (see the notes below) and let tLen be the length in octets of T. + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write(prefix, 0, prefix.length); + baos.write(mHash, 0, mHash.length); + final byte[] T = baos.toByteArray(); + final int tLen = T.length; + // 3. If emLen < tLen + 11, output "intended encoded message length too + // short" and stop. + if (emLen < tLen + 11) + { + throw new IllegalArgumentException("emLen too short"); + } + // 4. Generate an octet string PS consisting of emLen - tLen - 3 octets + // with hexadecimal value 0xff. The length of PS will be at least 8 + // octets. + final byte[] PS = new byte[emLen - tLen - 3]; + for (int i = 0; i < PS.length; i++) + { + PS[i] = (byte) 0xFF; + } + // 5. Concatenate PS, the DER encoding T, and other padding to form the + // encoded message EM as: EM = 0x00 || 0x01 || PS || 0x00 || T. + baos.reset(); + baos.write(0x00); + baos.write(0x01); + baos.write(PS, 0, PS.length); + baos.write(0x00); + baos.write(T, 0, tLen); + final byte[] result = baos.toByteArray(); + baos.reset(); + // 6. Output EM. + return result; + } +} diff --git a/gnu/java/security/sig/rsa/EMSA_PSS.java b/gnu/java/security/sig/rsa/EMSA_PSS.java new file mode 100644 index 000000000..845b6ab56 --- /dev/null +++ b/gnu/java/security/sig/rsa/EMSA_PSS.java @@ -0,0 +1,432 @@ +/* EMSA_PSS.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import java.io.PrintWriter; +import java.util.Arrays; + +/** + *

An implementation of the EMSA-PSS encoding/decoding scheme.

+ * + *

EMSA-PSS coincides with EMSA4 in IEEE P1363a D5 except that EMSA-PSS acts + * on octet strings and not on bit strings. In particular, the bit lengths of + * the hash and the salt must be multiples of 8 in EMSA-PSS. Moreover, EMSA4 + * outputs an integer of a desired bit length rather than an octet string.

+ * + *

EMSA-PSS is parameterized by the choice of hash function Hash and mask + * generation function MGF. In this submission, MGF is based on a Hash + * definition that coincides with the corresponding definitions in IEEE Std + * 1363-2000, PKCS #1 v2.0, and the draft ANSI X9.44. In PKCS #1 v2.0 and the + * draft ANSI X9.44, the recommended hash function is SHA-1, while IEEE Std + * 1363-2000 recommends SHA-1 and RIPEMD-160.

+ * + *

References:

+ *
    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ * + * @version $Revision: 1.1.4.1 $ + */ +public class EMSA_PSS implements Cloneable +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "emsa-pss"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 5; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The underlying hash function to use with this instance. */ + private IMessageDigest hash; + + /** The output size of the hash function in octets. */ + private int hLen; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial private constructor to enforce use through Factory method.

+ * + * @param hash the message digest instance to use with this scheme instance. + */ + private EMSA_PSS(IMessageDigest hash) + { + super(); + + this.hash = hash; + hLen = hash.hashSize(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of this object given a designated name of a hash + * function.

+ * + * @param mdName the canonical name of a hash function. + * @return an instance of this object configured for use with the designated + * options. + */ + public static EMSA_PSS getInstance(String mdName) + { + IMessageDigest hash = HashFactory.getInstance(mdName); + return new EMSA_PSS(hash); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // Cloneable interface implementation -------------------------------------- + + public Object clone() + { + return getInstance(hash.name()); + } + + // own methods ------------------------------------------------------------- + + /** + *

The encoding operation EMSA-PSS-Encode computes the hash of a message + * M using a hash function and maps the result to an encoded + * message EM of a specified length using a mask generation + * function.

+ * + * @param mHash the byte sequence resulting from applying the message digest + * algorithm Hash to the message M. + * @param emBits the maximal bit length of the integer OS2IP(EM), at least + * 8.hLen + 8.sLen + 9. + * @param salt the salt to use when encoding the output. + * @return the encoded message EM, an octet string of length + * emLen = CEILING(emBits / 8). + * @exception IllegalArgumentException if an exception occurs. + * + */ + public byte[] encode(byte[] mHash, int emBits, byte[] salt) + { + int sLen = salt.length; + + // 1. If the length of M is greater than the input limitation for the hash + // function (2**61 - 1 octets for SHA-1) then output "message too long" + // and stop. + // 2. Let mHash = Hash(M), an octet string of length hLen. + if (hLen != mHash.length) + { + throw new IllegalArgumentException("wrong hash"); + } + // 3. If emBits < 8.hLen + 8.sLen + 9, output 'encoding error' and stop. + if (emBits < (8 * hLen + 8 * sLen + 9)) + { + throw new IllegalArgumentException("encoding error"); + } + int emLen = (emBits + 7) / 8; + // 4. Generate a random octet string salt of length sLen; if sLen = 0, + // then salt is the empty string. + // ...passed as argument to accomodate JCE + // 5. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt; + // M0 is an octet string of length 8 + hLen + sLen with eight initial zero + // octets. + // 6. Let H = Hash(M0), an octet string of length hLen. + byte[] H; + int i; + synchronized (hash) + { + for (i = 0; i < 8; i++) + { + hash.update((byte) 0x00); + } + hash.update(mHash, 0, hLen); + hash.update(salt, 0, sLen); + H = hash.digest(); + } + // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 + // zero octets. The length of PS may be 0. + // 8. Let DB = PS || 01 || salt. + byte[] DB = new byte[emLen - sLen - hLen - 2 + 1 + sLen]; + DB[emLen - sLen - hLen - 2] = 0x01; + System.arraycopy(salt, 0, DB, emLen - sLen - hLen - 1, sLen); + // 9. Let dbMask = MGF(H, emLen - hLen - 1). + byte[] dbMask = MGF(H, emLen - hLen - 1); + if (DEBUG && debuglevel > 8) + { + debug("dbMask (encode): " + Util.toString(dbMask)); + debug("DB (encode): " + Util.toString(DB)); + } + // 10. Let maskedDB = DB XOR dbMask. + for (i = 0; i < DB.length; i++) + { + DB[i] = (byte) (DB[i] ^ dbMask[i]); + } + // 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in + // maskedDB to zero. + DB[0] &= (0xFF >>> (8 * emLen - emBits)); + // 12. Let EM = maskedDB || H || bc, where bc is the single octet with + // hexadecimal value 0xBC. + byte[] result = new byte[emLen]; + System.arraycopy(DB, 0, result, 0, emLen - hLen - 1); + System.arraycopy(H, 0, result, emLen - hLen - 1, hLen); + result[emLen - 1] = (byte) 0xBC; + // 13. Output EM. + return result; + } + + /** + *

The decoding operation EMSA-PSS-Decode recovers the message hash from + * an encoded message EM and compares it to the hash of + * M.

+ * + * @param mHash the byte sequence resulting from applying the message digest + * algorithm Hash to the message M. + * @param EM the encoded message, an octet string of length + * emLen = CEILING(emBits/8). + * @param emBits the maximal bit length of the integer OS2IP(EM), at least + * 8.hLen + 8.sLen + 9. + * @param sLen the length, in octets, of the expected salt. + * @return true if the result of the verification was + * consistent with the expected reseult; and false if the + * result was inconsistent. + * @exception IllegalArgumentException if an exception occurs. + */ + public boolean decode(byte[] mHash, byte[] EM, int emBits, int sLen) + { + if (DEBUG && debuglevel > 8) + { + debug("mHash: " + Util.toString(mHash)); + debug("EM: " + Util.toString(EM)); + debug("emBits: " + String.valueOf(emBits)); + debug("sLen: " + String.valueOf(sLen)); + } + if (sLen < 0) + { + throw new IllegalArgumentException("sLen"); + } + + // 1. If the length of M is greater than the input limitation for the hash + // function (2**61 ? 1 octets for SHA-1) then output 'inconsistent' and + // stop. + // 2. Let mHash = Hash(M), an octet string of length hLen. + if (hLen != mHash.length) + { + if (DEBUG && debuglevel > 8) + { + debug("hLen != mHash.length; hLen: " + String.valueOf(hLen)); + } + throw new IllegalArgumentException("wrong hash"); + } + // 3. If emBits < 8.hLen + 8.sLen + 9, output 'decoding error' and stop. + if (emBits < (8 * hLen + 8 * sLen + 9)) + { + if (DEBUG && debuglevel > 8) + { + debug("emBits < (8hLen + 8sLen + 9); sLen: " + String.valueOf(sLen)); + } + throw new IllegalArgumentException("decoding error"); + } + int emLen = (emBits + 7) / 8; + // 4. If the rightmost octet of EM does not have hexadecimal value bc, + // output 'inconsistent' and stop. + if ((EM[EM.length - 1] & 0xFF) != 0xBC) + { + if (DEBUG && debuglevel > 8) + { + debug("EM does not end with 0xBC"); + } + return false; + } + // 5. Let maskedDB be the leftmost emLen ? hLen ? 1 octets of EM, and let + // H be the next hLen octets. + // 6. If the leftmost 8.emLen ? emBits bits of the leftmost octet in + // maskedDB are not all equal to zero, output 'inconsistent' and stop. + if ((EM[0] & (0xFF << (8 - (8 * emLen - emBits)))) != 0) + { + if (DEBUG && debuglevel > 8) + { + debug("Leftmost 8emLen - emBits bits of EM are not 0s"); + } + return false; + } + byte[] DB = new byte[emLen - hLen - 1]; + byte[] H = new byte[hLen]; + System.arraycopy(EM, 0, DB, 0, emLen - hLen - 1); + System.arraycopy(EM, emLen - hLen - 1, H, 0, hLen); + // 7. Let dbMask = MGF(H, emLen ? hLen ? 1). + byte[] dbMask = MGF(H, emLen - hLen - 1); + // 8. Let DB = maskedDB XOR dbMask. + int i; + for (i = 0; i < DB.length; i++) + { + DB[i] = (byte) (DB[i] ^ dbMask[i]); + } + // 9. Set the leftmost 8.emLen ? emBits bits of DB to zero. + DB[0] &= (0xFF >>> (8 * emLen - emBits)); + if (DEBUG && debuglevel > 8) + { + debug("dbMask (decode): " + Util.toString(dbMask)); + debug("DB (decode): " + Util.toString(DB)); + } + // 10. If the emLen -hLen -sLen -2 leftmost octets of DB are not zero or + // if the octet at position emLen -hLen -sLen -1 is not equal to 0x01, + // output 'inconsistent' and stop. + // IMPORTANT (rsn): this is an error in the specs, the index of the 0x01 + // byte should be emLen -hLen -sLen -2 and not -1! authors have been + // advised + for (i = 0; i < (emLen - hLen - sLen - 2); i++) + { + if (DB[i] != 0) + { + if (DEBUG && debuglevel > 8) + { + debug("DB[" + String.valueOf(i) + "] != 0x00"); + } + return false; + } + } + if (DB[i] != 0x01) + { // i == emLen -hLen -sLen -2 + if (DEBUG && debuglevel > 8) + { + debug("DB's byte at position (emLen -hLen -sLen -2); i.e. " + + String.valueOf(i) + " is not 0x01"); + } + return false; + } + // 11. Let salt be the last sLen octets of DB. + byte[] salt = new byte[sLen]; + System.arraycopy(DB, DB.length - sLen, salt, 0, sLen); + // 12. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt; + // M0 is an octet string of length 8 + hLen + sLen with eight initial + // zero octets. + // 13. Let H0 = Hash(M0), an octet string of length hLen. + byte[] H0; + synchronized (hash) + { + for (i = 0; i < 8; i++) + { + hash.update((byte) 0x00); + } + hash.update(mHash, 0, hLen); + hash.update(salt, 0, sLen); + H0 = hash.digest(); + } + // 14. If H = H0, output 'consistent.' Otherwise, output 'inconsistent.' + return Arrays.equals(H, H0); + } + + // helper methods ---------------------------------------------------------- + + /** + *

A mask generation function takes an octet string of variable length + * and a desired output length as input, and outputs an octet string of the + * desired length. There may be restrictions on the length of the input and + * output octet strings, but such bounds are generally very large. Mask + * generation functions are deterministic; the octet string output is + * completely determined by the input octet string. The output of a mask + * generation function should be pseudorandom, that is, it should be + * infeasible to predict, given one part of the output but not the input, + * another part of the output. The provable security of RSA-PSS relies on + * the random nature of the output of the mask generation function, which in + * turn relies on the random nature of the underlying hash function.

+ * + * @param Z a seed. + * @param l the desired output length in octets. + * @return the mask. + * @exception IllegalArgumentException if the desired output length is too + * long. + */ + private byte[] MGF(byte[] Z, int l) + { + // 1. If l > (2**32).hLen, output 'mask too long' and stop. + if (l < 1 || (l & 0xFFFFFFFFL) > ((hLen & 0xFFFFFFFFL) << 32L)) + { + throw new IllegalArgumentException("mask too long"); + } + // 2. Let T be the empty octet string. + byte[] result = new byte[l]; + // 3. For i = 0 to CEILING(l/hLen) ? 1, do + int limit = ((l + hLen - 1) / hLen) - 1; + IMessageDigest hashZ = null; + hashZ = (IMessageDigest) hash.clone(); + hashZ.digest(); + hashZ.update(Z, 0, Z.length); + IMessageDigest hashZC = null; + byte[] t; + int sofar = 0; + int length; + for (int i = 0; i < limit; i++) + { + // 3.1 Convert i to an octet string C of length 4 with the primitive + // I2OSP: C = I2OSP(i, 4). + // 3.2 Concatenate the hash of the seed Z and C to the octet string T: + // T = T || Hash(Z || C) + hashZC = (IMessageDigest) hashZ.clone(); + hashZC.update((byte) (i >>> 24)); + hashZC.update((byte) (i >>> 16)); + hashZC.update((byte) (i >>> 8)); + hashZC.update((byte) i); + t = hashZC.digest(); + length = l - sofar; + length = (length > hLen ? hLen : length); + System.arraycopy(t, 0, result, sofar, length); + sofar += length; + } + // 4. Output the leading l octets of T as the octet string mask. + return result; + } +} diff --git a/gnu/java/security/sig/rsa/RSA.java b/gnu/java/security/sig/rsa/RSA.java new file mode 100644 index 000000000..7d1707e19 --- /dev/null +++ b/gnu/java/security/sig/rsa/RSA.java @@ -0,0 +1,356 @@ +/* RSA.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Properties; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + *

Utility methods related to the RSA algorithm.

+ * + *

References:

+ *
    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + * + *
  3. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  4. + * + *
  5. + * Remote timing attacks are practical
    + * D. Boneh and D. Brumley.
  6. + *
+ */ +public class RSA +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final BigInteger ZERO = BigInteger.ZERO; + + private static final BigInteger ONE = BigInteger.ONE; + + /** Our default source of randomness. */ + private static final PRNG prng = PRNG.getInstance(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial private constructor to enforce Singleton pattern. */ + private RSA() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Signature and verification methods -------------------------------------- + + /** + *

An implementation of the RSASP method: Assuming that the + * designated RSA private key is a valid one, this method computes a + * signature representative for a designated message + * representative signed by the holder of the designated RSA private + * key.

+ * + * @param K the RSA private key. + * @param m the message representative: an integer between + * 0 and n - 1, where n is the RSA + * modulus. + * @return the signature representative, an integer between + * 0 and n - 1, where n is the RSA + * modulus. + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if m (the message + * representative) is out of range. + */ + public static final BigInteger sign(final PrivateKey K, final BigInteger m) + { + try + { + return RSADP((RSAPrivateKey) K, m); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException( + "message representative out of range"); + } + } + + /** + *

An implementation of the RSAVP method: Assuming that the + * designated RSA public key is a valid one, this method computes a + * message representative for the designated signature + * representative generated by an RSA private key, for a message + * intended for the holder of the designated RSA public key.

+ * + * @param K the RSA public key. + * @param s the signature representative, an integer between + * 0 and n - 1, where n is the RSA + * modulus. + * @return a message representative: an integer between 0 + * and n - 1, where n is the RSA modulus. + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if s (the signature + * representative) is out of range. + */ + public static final BigInteger verify(final PublicKey K, final BigInteger s) + { + try + { + return RSAEP((RSAPublicKey) K, s); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException( + "signature representative out of range"); + } + } + + // Encryption and decryption methods --------------------------------------- + + /** + *

An implementation of the RSAEP algorithm.

+ * + * @param K the recipient's RSA public key. + * @param m the message representative as an MPI. + * @return the resulting MPI --an MPI between 0 and + * n - 1 (n being the public shared modulus)-- that + * will eventually be padded with an appropriate framing/padding scheme. + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if m, the message + * representative is not between 0 and n - 1 + * (n being the public shared modulus). + */ + public static final BigInteger encrypt(final PublicKey K, final BigInteger m) + { + try + { + return RSAEP((RSAPublicKey) K, m); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException( + "message representative out of range"); + } + } + + /** + *

An implementation of the RSADP algorithm.

+ * + * @param K the recipient's RSA private key. + * @param c the ciphertext representative as an MPI. + * @return the message representative, an MPI between 0 and + * n - 1 (n being the shared public modulus). + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if c, the ciphertext + * representative is not between 0 and n - 1 + * (n being the shared public modulus). + */ + public static final BigInteger decrypt(final PrivateKey K, final BigInteger c) + { + try + { + return RSADP((RSAPrivateKey) K, c); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException( + "ciphertext representative out of range"); + } + } + + // Conversion methods ------------------------------------------------------ + + /** + *

Converts a multi-precision integer (MPI) s into an + * octet sequence of length k.

+ * + * @param s the multi-precision integer to convert. + * @param k the length of the output. + * @return the result of the transform. + * @exception IllegalArgumentException if the length in octets of meaningful + * bytes of s is greater than k. + */ + public static final byte[] I2OSP(final BigInteger s, final int k) + { + byte[] result = s.toByteArray(); + if (result.length < k) + { + final byte[] newResult = new byte[k]; + System.arraycopy(result, 0, newResult, k - result.length, result.length); + result = newResult; + } + else if (result.length > k) + { // leftmost extra bytes should all be 0 + final int limit = result.length - k; + for (int i = 0; i < limit; i++) + { + if (result[i] != 0x00) + { + throw new IllegalArgumentException("integer too large"); + } + } + final byte[] newResult = new byte[k]; + System.arraycopy(result, limit, newResult, 0, k); + result = newResult; + } + return result; + } + + // helper methods ---------------------------------------------------------- + + private static final BigInteger RSAEP(final RSAPublicKey K, final BigInteger m) + { + // 1. If the representative m is not between 0 and n - 1, output + // "representative out of range" and stop. + final BigInteger n = K.getModulus(); + if (m.compareTo(ZERO) < 0 || m.compareTo(n.subtract(ONE)) > 0) + { + throw new IllegalArgumentException(); + } + // 2. Let c = m^e mod n. + final BigInteger e = K.getPublicExponent(); + final BigInteger result = m.modPow(e, n); + // 3. Output c. + return result; + } + + private static final BigInteger RSADP(final RSAPrivateKey K, BigInteger c) + { + // 1. If the representative c is not between 0 and n - 1, output + // "representative out of range" and stop. + final BigInteger n = K.getModulus(); + if (c.compareTo(ZERO) < 0 || c.compareTo(n.subtract(ONE)) > 0) + { + throw new IllegalArgumentException(); + } + + // 2. The representative m is computed as follows. + BigInteger result; + if (!(K instanceof RSAPrivateCrtKey)) + { + // a. If the first form (n, d) of K is used, let m = c^d mod n. + final BigInteger d = K.getPrivateExponent(); + result = c.modPow(d, n); + } + else + { + // from [3] p.13 --see class docs: + // The RSA blinding operation calculates x = (r^e) * g mod n before + // decryption, where r is random, e is the RSA encryption exponent, and + // g is the ciphertext to be decrypted. x is then decrypted as normal, + // followed by division by r, i.e. (x^e) / r mod n. Since r is random, + // x is random and timing the decryption should not reveal information + // about the key. Note that r should be a new random number for every + // decryption. + final boolean rsaBlinding = Properties.doRSABlinding(); + BigInteger r = null; + BigInteger e = null; + if (rsaBlinding) + { // pre-decryption + r = newR(n); + e = ((RSAPrivateCrtKey) K).getPublicExponent(); + final BigInteger x = r.modPow(e, n).multiply(c).mod(n); + c = x; + } + + // b. If the second form (p, q, dP, dQ, qInv) and (r_i, d_i, t_i) + // of K is used, proceed as follows: + final BigInteger p = ((RSAPrivateCrtKey) K).getPrimeP(); + final BigInteger q = ((RSAPrivateCrtKey) K).getPrimeQ(); + final BigInteger dP = ((RSAPrivateCrtKey) K).getPrimeExponentP(); + final BigInteger dQ = ((RSAPrivateCrtKey) K).getPrimeExponentQ(); + final BigInteger qInv = ((RSAPrivateCrtKey) K).getCrtCoefficient(); + + // i. Let m_1 = c^dP mod p and m_2 = c^dQ mod q. + final BigInteger m_1 = c.modPow(dP, p); + final BigInteger m_2 = c.modPow(dQ, q); + // ii. If u > 2, let m_i = c^(d_i) mod r_i, i = 3, ..., u. + // iii. Let h = (m_1 - m_2) * qInv mod p. + final BigInteger h = m_1.subtract(m_2).multiply(qInv).mod(p); + // iv. Let m = m_2 + q * h. + result = m_2.add(q.multiply(h)); + + if (rsaBlinding) + { // post-decryption + result = result.multiply(r.modInverse(n)).mod(n); + } + } + + // 3. Output m + return result; + } + + /** + *

Returns a random MPI with a random bit-length of the form 8b, + * where b is in the range [32..64].

+ * + * @return a random MPI whose length in bytes is between 32 and 64 inclusive. + */ + private static final BigInteger newR(final BigInteger N) + { + final int upper = (N.bitLength() + 7) / 8; + final int lower = upper / 2; + final byte[] bl = new byte[1]; + int b; + do + { + prng.nextBytes(bl); + b = bl[0] & 0xFF; + } + while (b < lower || b > upper); + final byte[] buffer = new byte[b]; // 256-bit MPI + prng.nextBytes(buffer); + return new BigInteger(1, buffer); + } +} diff --git a/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java b/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java new file mode 100644 index 000000000..38cdf2934 --- /dev/null +++ b/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java @@ -0,0 +1,247 @@ +/* RSAPKCS1V1_5Signature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.BaseSignature; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Arrays; + +/** + *

The RSA-PKCS1-V1.5 signature scheme is a digital signature scheme with + * appendix (SSA) combining the RSA algorithm with the EMSA-PKCS1-v1_5 encoding + * method.

+ * + *

References:

+ *
    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + * + *
  3. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  4. + *
+ * + * @version $Revision: 1.2.2.1 $ + */ +public class RSAPKCS1V1_5Signature extends BaseSignature +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The underlying EMSA-PKCS1-v1.5 instance for this object. */ + private EMSA_PKCS1_V1_5 pkcs1; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Default 0-arguments constructor. Uses SHA-1 as the default hash. + */ + public RSAPKCS1V1_5Signature() + { + this(Registry.SHA160_HASH); + } + + /** + *

Constructs an instance of this object using the designated message + * digest algorithm as its underlying hash function.

+ * + * @param mdName the canonical name of the underlying hash function. + */ + public RSAPKCS1V1_5Signature(final String mdName) + { + this(HashFactory.getInstance(mdName)); + } + + public RSAPKCS1V1_5Signature(IMessageDigest md) + { + super(Registry.RSA_PKCS1_V1_5_SIG, md); + + pkcs1 = EMSA_PKCS1_V1_5.getInstance(md.name()); + } + + /** Private constructor for cloning purposes. */ + private RSAPKCS1V1_5Signature(final RSAPKCS1V1_5Signature that) + { + this(that.md.name()); + + this.publicKey = that.publicKey; + this.privateKey = that.privateKey; + this.md = (IMessageDigest) that.md.clone(); + this.pkcs1 = (EMSA_PKCS1_V1_5) that.pkcs1.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in superclass ------------------------ + + public Object clone() + { + return new RSAPKCS1V1_5Signature(this); + } + + protected void setupForVerification(final PublicKey k) + throws IllegalArgumentException + { + if (!(k instanceof RSAPublicKey)) + { + throw new IllegalArgumentException(); + } + publicKey = k; + } + + protected void setupForSigning(final PrivateKey k) + throws IllegalArgumentException + { + if (!(k instanceof RSAPrivateKey)) + { + throw new IllegalArgumentException(); + } + privateKey = k; + } + + protected Object generateSignature() throws IllegalStateException + { + // 1. EMSA-PKCS1-v1_5 encoding: Apply the EMSA-PKCS1-v1_5 encoding + // operation (Section 9.2) to the message M to produce an encoded + // message EM of length k octets: + // + // EM = EMSA-PKCS1-V1_5-ENCODE (M, k). + // + // If the encoding operation outputs "message too long," output + // "message too long" and stop. If the encoding operation outputs + // "intended encoded message length too short," output "RSA modulus + // too short" and stop. + final int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength(); + final int k = (modBits + 7) / 8; + final byte[] EM = pkcs1.encode(md.digest(), k); + + // 2. RSA signature: + // a. Convert the encoded message EM to an integer message epresentative + // m (see Section 4.2): m = OS2IP (EM). + final BigInteger m = new BigInteger(1, EM); + // b. Apply the RSASP1 signature primitive (Section 5.2.1) to the RSA + // private key K and the message representative m to produce an + // integer signature representative s: s = RSASP1 (K, m). + final BigInteger s = RSA.sign(privateKey, m); + // c. Convert the signature representative s to a signature S of length + // k octets (see Section 4.1): S = I2OSP (s, k). + // 3. Output the signature S. + return RSA.I2OSP(s, k); + } + + protected boolean verifySignature(final Object sig) + throws IllegalStateException + { + if (publicKey == null) + { + throw new IllegalStateException(); + } + final byte[] S = (byte[]) sig; + // 1. Length checking: If the length of the signature S is not k octets, + // output "invalid signature" and stop. + final int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength(); + final int k = (modBits + 7) / 8; + if (S.length != k) + { + return false; + } + // 2. RSA verification: + // a. Convert the signature S to an integer signature representative + // s (see Section 4.2): s = OS2IP (S). + final BigInteger s = new BigInteger(1, S); + // b. Apply the RSAVP1 verification primitive (Section 5.2.2) to the + // RSA public key (n, e) and the signature representative s to + // produce an integer message representative m: + // m = RSAVP1 ((n, e), s). + // If RSAVP1 outputs "signature representative out of range," + // output "invalid signature" and stop. + final BigInteger m; + try + { + m = RSA.verify(publicKey, s); + } + catch (IllegalArgumentException x) + { + return false; + } + // c. Convert the message representative m to an encoded message EM + // of length k octets (see Section 4.1): EM = I2OSP (m, k). + // If I2OSP outputs "integer too large," output "invalid signature" + // and stop. + final byte[] EM; + try + { + EM = RSA.I2OSP(m, k); + } + catch (IllegalArgumentException x) + { + return false; + } + // 3. EMSA-PKCS1-v1_5 encoding: Apply the EMSA-PKCS1-v1_5 encoding + // operation (Section 9.2) to the message M to produce a second + // encoded message EM' of length k octets: + // EM' = EMSA-PKCS1-V1_5-ENCODE (M, k). + // If the encoding operation outputs "message too long," output + // "message too long" and stop. If the encoding operation outputs + // "intended encoded message length too short," output "RSA modulus + // too short" and stop. + final byte[] EMp = pkcs1.encode(md.digest(), k); + // 4. Compare the encoded message EM and the second encoded message EM'. + // If they are the same, output "valid signature"; otherwise, output + // "invalid signature." + return Arrays.equals(EM, EMp); + } +} diff --git a/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java b/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java new file mode 100644 index 000000000..68c1edaa6 --- /dev/null +++ b/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java @@ -0,0 +1,153 @@ +/* RSAPKCS1V1_5SignatureRawCodec.java -- Raw RSA PKCS1 v1.5 signature codeec + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import java.io.ByteArrayOutputStream; + +import gnu.java.security.Registry; +import gnu.java.security.sig.ISignatureCodec; + +/** + * An object that implements the {@link ISignatureCodec} operations for the + * Raw format to use with RSA-PKCS#1 v1.5 signatures. + */ +public class RSAPKCS1V1_5SignatureRawCodec + implements ISignatureCodec +{ + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated RSA-PKCS#1 (v1.5) signature + * object according to the Raw format supported by this library. + *

+ * The Raw format for such a signature, in this implementation, is a + * byte sequence consisting of the following: + *

+ *

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE}, + *
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the RSA-PKCS#1 (v1.5) + * signature bytes in internet order,
  6. + *
  7. the RSA-PKCS#1 (v1.5) signature bytes in internet order.
  8. + *
+ * + * @param signature the signature to encode, consisting of the output of the + * sign() method of a {@link RSAPKCS1V1_5Signature} + * instance --a byte array. + * @return the Raw format encoding of the designated signature. + * @exception IllegalArgumentException if the designated signature is not an + * RSA-PKCS#1 (v1.5) one. + */ + public byte[] encodeSignature(Object signature) + { + byte[] buffer; + try + { + buffer = (byte[]) signature; + } + catch (Exception x) + { + throw new IllegalArgumentException("Signature/codec mismatch"); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[0]); + baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[1]); + baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[2]); + baos.write(Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[3]); + + // version + baos.write(0x01); + + // signature bytes + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write( length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + /** + * Returns the decoded object from a designated input assumed to have been + * generated by the {@link #encodeSignature(Object)} method. + * + * @param input the input bytes of a previously Raw-encoded RSA PKCS1 (v1.5) + * signature. + * @return the signature object. + * @throws IllegalArgumentException if the designated input does not start + * with the right magic characters, or if the version + * is not supported. + */ + public Object decodeSignature(byte[] input) + { + // magic + if (input[0] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[0] + || input[1] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[1] + || input[2] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[2] + || input[3] != Registry.MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE[3]) + throw new IllegalArgumentException("Signature/codec mismatch"); + + // version + if (input[4] != 0x01) + throw new IllegalArgumentException("Wrong or unsupported format version"); + + int i = 5; + int l; + + // signature bytes + l = input[i++] << 24 + | (input[i++] & 0xFF) << 16 + | (input[i++] & 0xFF) << 8 + | (input[i++] & 0xFF); + byte[] result = new byte[l]; + System.arraycopy(input, i, result, 0, l); + + return result; + } +} diff --git a/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java b/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java new file mode 100644 index 000000000..90797e2d5 --- /dev/null +++ b/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java @@ -0,0 +1,157 @@ +/* RSAPSSSignatureX509Codec.java -- X.509 encoder/decoder for RSA signatures + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.sig.ISignatureCodec; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.InvalidParameterException; + +/** + * An implementation of an {@link ISignatureCodec} that knows to encode and + * decode RSA PKCS1 (v1.5) signatures into the DER-encoded form of the ASN.1 + * structure defined in RFC-2459, and RFC-2313 as described in the next + * paragraphs. + *

+ * Digital signatures when transmitted in an X.509 certificates are encoded + * in DER (Distinguished Encoding Rules) as a BIT STRING; i.e. + * + *

+ * Certificate ::= SEQUENCE {
+ *   tbsCertificate       TBSCertificate,
+ *   signatureAlgorithm   AlgorithmIdentifier,
+ *   signature            BIT STRING
+ * }
+ * 
+ *

+ * The output of the encoder, and the input of the decoder, of this codec are + * then the bytes of such a BIT STRING. + *

+ * Our implementation of the RSA PKCS1 signature algorithm outputs a byte array + * as the result of generating a digital signature, in accordance with RFC-2313. + * As a consequence, the encoder and decoder of this codec, simply marshall and + * unmarshall such a byte array into the DER-encoded BIT STRING expected (or + * supplied) by an X.509 certificate. + */ +public class RSAPKCS1V1_5SignatureX509Codec + implements ISignatureCodec +{ + // default 0-arguments constructor + + public int getFormatID() + { + return Registry.X509_ENCODING_ID; + } + + /** + * Encodes an RSA Signature output as a signature BIT STRING as defined + * in the documentation of this class. + * + * @param signature the output of the RSA PKCS1 (v1.5) signature algorithm; + * i.e. the value returned by the invocation of + * {@link gnu.java.security.sig.ISignature#sign()} method. In the + * case of the RSA PKCS1 (v1.5) signature this is an array of bytes. + * @return the DER-encoded output of an RSA signature as defined in rfc-2459. + * @throws InvalidParameterException if an exception occurs during the + * marshalling process. + */ + public byte[] encodeSignature(Object signature) + { + byte[] sBytes = (byte[]) signature; + DERValue derSignature = new DERValue(DER.BIT_STRING, + new BitString(sBytes)); + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derSignature); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return result; + } + + /** + * Decodes a signature BIT STRING as defined in the documentation of + * this class. + * + * @param input the byte array to unmarshall into a valid RSA PKCS1 (v1.5) + * signature instance; i.e. an array of two MPIs. MUST NOT be null. + * @return an array of bytes decoded from the designated input. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public Object decodeSignature(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + byte[] result; + DERReader der = new DERReader(input); + try + { + DERValue derSignature = der.read(); + if (! (derSignature.getValue() instanceof BitString)) + throw new InvalidParameterException("Wrong signature field"); + + result = ((BitString) derSignature.getValue()).toByteArray(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return result; + } +} diff --git a/gnu/java/security/sig/rsa/RSAPSSSignature.java b/gnu/java/security/sig/rsa/RSAPSSSignature.java new file mode 100644 index 000000000..cbf66c958 --- /dev/null +++ b/gnu/java/security/sig/rsa/RSAPSSSignature.java @@ -0,0 +1,348 @@ +/* RSAPSSSignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.BaseSignature; +import gnu.java.security.util.Util; + +import java.io.PrintWriter; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + *

The RSA-PSS signature scheme is a public-key encryption scheme combining + * the RSA algorithm with the Probabilistic Signature Scheme (PSS) encoding + * method.

+ * + *

The inventors of RSA are Ronald L. Rivest, Adi Shamir, and Leonard Adleman, + * while the inventors of the PSS encoding method are Mihir Bellare and Phillip + * Rogaway. During efforts to adopt RSA-PSS into the P1363a standards effort, + * certain adaptations to the original version of RSA-PSS were made by Mihir + * Bellare and Phillip Rogaway and also by Burt Kaliski (the editor of IEEE + * P1363a) to facilitate implementation and integration into existing protocols.

+ * + *

References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ * + * @version $Revision: 1.2.2.1 $ + */ +public class RSAPSSSignature extends BaseSignature +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "rsa-pss"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 1; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The underlying EMSA-PSS instance for this object. */ + private EMSA_PSS pss; + + /** The desired length in octets of the EMSA-PSS salt. */ + private int sLen; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Default 0-arguments constructor. Uses SHA-1 as the default hash and a + * 0-octet salt. + */ + public RSAPSSSignature() + { + this(Registry.SHA160_HASH, 0); + } + + /** + *

Constructs an instance of this object using the designated message + * digest algorithm as its underlying hash function, and having 0-octet + * salt.

+ * + * @param mdName the canonical name of the underlying hash function. + */ + public RSAPSSSignature(String mdName) + { + this(mdName, 0); + } + + /** + *

Constructs an instance of this object using the designated message + * digest algorithm as its underlying hash function.

+ * + * @param mdName the canonical name of the underlying hash function. + * @param sLen the desired length in octets of the salt to use for encoding / + * decoding signatures. + */ + public RSAPSSSignature(String mdName, int sLen) + { + this(HashFactory.getInstance(mdName), sLen); + } + + public RSAPSSSignature(IMessageDigest md, int sLen) + { + super(Registry.RSA_PSS_SIG, md); + + pss = EMSA_PSS.getInstance(md.name()); + this.sLen = sLen; + } + + /** Private constructor for cloning purposes. */ + private RSAPSSSignature(RSAPSSSignature that) + { + this(that.md.name(), that.sLen); + + this.publicKey = that.publicKey; + this.privateKey = that.privateKey; + this.md = (IMessageDigest) that.md.clone(); + this.pss = (EMSA_PSS) that.pss.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in superclass ------------------------ + + public Object clone() + { + return new RSAPSSSignature(this); + } + + protected void setupForVerification(PublicKey k) + throws IllegalArgumentException + { + if (!(k instanceof RSAPublicKey)) + { + throw new IllegalArgumentException(); + } + publicKey = (RSAPublicKey) k; + } + + protected void setupForSigning(PrivateKey k) throws IllegalArgumentException + { + if (!(k instanceof RSAPrivateKey)) + { + throw new IllegalArgumentException(); + } + privateKey = (RSAPrivateKey) k; + } + + protected Object generateSignature() throws IllegalStateException + { + // 1. Apply the EMSA-PSS encoding operation to the message M to produce an + // encoded message EM of length CEILING((modBits ? 1)/8) octets such + // that the bit length of the integer OS2IP(EM) is at most modBits ? 1: + // EM = EMSA-PSS-Encode(M,modBits ? 1). + // Note that the octet length of EM will be one less than k if + // modBits ? 1 is divisible by 8. If the encoding operation outputs + // 'message too long' or 'encoding error,' then output 'message too + // long' or 'encoding error' and stop. + int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength(); + byte[] salt = new byte[sLen]; + this.nextRandomBytes(salt); + byte[] EM = pss.encode(md.digest(), modBits - 1, salt); + if (DEBUG && debuglevel > 8) + { + debug("EM (sign): " + Util.toString(EM)); + } + // 2. Convert the encoded message EM to an integer message representative + // m (see Section 1.2.2): m = OS2IP(EM). + BigInteger m = new BigInteger(1, EM); + // 3. Apply the RSASP signature primitive to the public key K and the + // message representative m to produce an integer signature + // representative s: s = RSASP(K,m). + BigInteger s = RSA.sign(privateKey, m); + // 4. Convert the signature representative s to a signature S of length k + // octets (see Section 1.2.1): S = I2OSP(s, k). + // 5. Output the signature S. + int k = (modBits + 7) / 8; + // return encodeSignature(s, k); + return RSA.I2OSP(s, k); + } + + protected boolean verifySignature(Object sig) throws IllegalStateException + { + if (publicKey == null) + { + throw new IllegalStateException(); + } + // byte[] S = decodeSignature(sig); + byte[] S = (byte[]) sig; + // 1. If the length of the signature S is not k octets, output 'signature + // invalid' and stop. + int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength(); + int k = (modBits + 7) / 8; + if (S.length != k) + { + return false; + } + // 2. Convert the signature S to an integer signature representative s: + // s = OS2IP(S). + BigInteger s = new BigInteger(1, S); + // 3. Apply the RSAVP verification primitive to the public key (n, e) and + // the signature representative s to produce an integer message + // representative m: m = RSAVP((n, e), s). + // If RSAVP outputs 'signature representative out of range,' then + // output 'signature invalid' and stop. + BigInteger m = null; + try + { + m = RSA.verify(publicKey, s); + } + catch (IllegalArgumentException x) + { + return false; + } + // 4. Convert the message representative m to an encoded message EM of + // length emLen = CEILING((modBits - 1)/8) octets, where modBits is + // equal to the bit length of the modulus: EM = I2OSP(m, emLen). + // Note that emLen will be one less than k if modBits - 1 is divisible + // by 8. If I2OSP outputs 'integer too large,' then output 'signature + // invalid' and stop. + int emBits = modBits - 1; + int emLen = (emBits + 7) / 8; + byte[] EM = m.toByteArray(); + if (DEBUG && debuglevel > 8) + { + debug("EM (verify): " + Util.toString(EM)); + } + if (EM.length > emLen) + { + return false; + } + else if (EM.length < emLen) + { + byte[] newEM = new byte[emLen]; + System.arraycopy(EM, 0, newEM, emLen - EM.length, EM.length); + EM = newEM; + } + // 5. Apply the EMSA-PSS decoding operation to the message M and the + // encoded message EM: Result = EMSA-PSS-Decode(M, EM, emBits). If + // Result = 'consistent,' output 'signature verified.' Otherwise, + // output 'signature invalid.' + byte[] mHash = md.digest(); + boolean result = false; + try + { + result = pss.decode(mHash, EM, emBits, sLen); + } + catch (IllegalArgumentException x) + { + result = false; + } + return result; + } + + // Other instance methods -------------------------------------------------- + + /** + * Converts the signature representative s to a signature + * S of length k octets; i.e. + * S = I2OSP(s, k), where k = CEILING(modBits/8). + * + * @param s the signature representative. + * @param k the length of the output. + * @return the signature as an octet sequence. + * @exception IllegalArgumentException if the length in octets of meaningful + * bytes of s is greater than k, implying that + * s is not less than the RSA modulus. + */ + // private Object encodeSignature(BigInteger s, int k) { + // if (DEBUG && debuglevel > 8) { + // debug("s.bitLength(): "+String.valueOf(s.bitLength())); + // debug("k: "+String.valueOf(k)); + // } + // byte[] result = s.toByteArray(); + // if (DEBUG && debuglevel > 8) { + // debug("s: "+Util.toString(result)); + // debug("s (bytes): "+String.valueOf(result.length)); + // } + // if (result.length < k) { + // byte[] newResult = new byte[k]; + // System.arraycopy(result, 0, newResult, k-result.length, result.length); + // result = newResult; + // } else if (result.length > k) { // leftmost extra bytes should all be 0 + // int limit = result.length - k; + // for (int i = 0; i < limit; i++) { + // if (result[i] != 0x00) { + // throw new IllegalArgumentException("integer too large"); + // } + // } + // byte[] newResult = new byte[k]; + // System.arraycopy(result, limit, newResult, 0, k); + // result = newResult; + // } + // return result; + // } + /** + * Returns the output of a previously generated signature object as an octet + * sequence.

+ * + * @return the octet sequence S. + */ + // private byte[] decodeSignature(Object signature) { + // return (byte[]) signature; + // } +} diff --git a/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java b/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java new file mode 100644 index 000000000..16e70c69e --- /dev/null +++ b/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java @@ -0,0 +1,159 @@ +/* RSAPSSSignatureRawCodec.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.sig.ISignatureCodec; + +import java.io.ByteArrayOutputStream; + +/** + *

An object that implements the {@link gnu.crypto.sig.ISignatureCodec} + * operations for the Raw format to use with RSA-PSS signatures.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class RSAPSSSignatureRawCodec implements ISignatureCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // gnu.crypto.keys.IKeyPairCodec interface implementation + // ------------------------------------------------------------------------- + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + *

Returns the encoded form of the designated RSA-PSS signature object + * according to the Raw format supported by this library.

+ * + *

The Raw format for an RSA-PSS signature, in this implementation, + * is a byte sequence consisting of the following:

+ * + *
    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_RSA_PSS_SIGNATURE},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the RSA-PSS signature + * bytes in internet order,
  6. + *
  7. the RSA-PSS signature bytes in internet order.
  8. + *
+ * + * @param signature the signature to encode, consisting of the output of the + * sign() method of a {@link RSAPSSSignature} instance --a byte + * array. + * @return the Raw format encoding of the designated signature. + * @exception IllegalArgumentException if the designated signature is not an + * RSA-PSS one. + */ + public byte[] encodeSignature(Object signature) + { + byte[] buffer; + try + { + buffer = (byte[]) signature; + } + catch (Exception x) + { + throw new IllegalArgumentException("key"); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[0]); + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[1]); + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[2]); + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[3]); + + // version + baos.write(0x01); + + // signature bytes + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + public Object decodeSignature(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[0] + || k[1] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[1] + || k[2] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[2] + || k[3] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[3]) + { + throw new IllegalArgumentException("magic"); + } + + // version + if (k[4] != 0x01) + { + throw new IllegalArgumentException("version"); + } + + int i = 5; + int l; + + // signature bytes + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + byte[] result = new byte[l]; + System.arraycopy(k, i, result, 0, l); + + return result; + } +} diff --git a/gnu/java/security/sig/rsa/RSASignatureFactory.java b/gnu/java/security/sig/rsa/RSASignatureFactory.java new file mode 100644 index 000000000..b8e12caf7 --- /dev/null +++ b/gnu/java/security/sig/rsa/RSASignatureFactory.java @@ -0,0 +1,176 @@ +/* RSASignatureFactory.java -- A Factory class to instantiate RSA Signatures + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.ISignature; + +/** + * A Factory class to instantiate RSA Signature classes. + */ +public class RSASignatureFactory +{ + private static Set names; + + /** + * Private constructor to enforce usage through Factory (class) methods. + */ + private RSASignatureFactory() + { + super(); + } + + /** + * Returns a new instance of an RSA Signature given its name. The name of an + * RSA Signature always starts with rsa-, followed by either + * pss or pkcs1_v1.5. An optional message digest + * name, to be used with the RSA signature may be specified by appending the + * hyphen chanaracter - followed by the canonical message digest + * algorithm name. When no message digest algorithm name is given, SHA-160 is + * used. + * + * @param name the composite RSA signature name. + * @return a new instance of an RSA Signature algorithm implementation. + * Returns null if the given name does not correspond to any + * supported RSA Signature encoding and message digest combination. + */ + public static final ISignature getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + if (name.length() == 0) + return null; + + name = name.toLowerCase(); + if (! name.startsWith(Registry.RSA_SIG_PREFIX)) + return null; + + name = name.substring(Registry.RSA_SIG_PREFIX.length()).trim(); + if (name.startsWith(Registry.RSA_PSS_ENCODING)) + return getPSSSignature(name); + else if (name.startsWith(Registry.RSA_PKCS1_V1_5_ENCODING)) + return getPKCS1Signature(name); + else + return null; + } + + /** + * Returns a {@link Set} of names of RSA signatures supported by this + * Factory. + * + * @return a {@link Set} of RSA Signature algorithm names (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + Set hashNames = HashFactory.getNames(); + HashSet hs = new HashSet(); + for (Iterator it = hashNames.iterator(); it.hasNext();) + { + String mdName = (String) it.next(); + hs.add(Registry.RSA_PSS_SIG + "-" + mdName); + } + + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD2_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD5_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA160_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA256_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA384_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA512_HASH); + + names = Collections.unmodifiableSet(hs); + } + + return names; + } + + private static final ISignature getPSSSignature(String name) + { + name = name.substring(Registry.RSA_PSS_ENCODING.length()).trim(); + // remove the hyphen if found at the beginning + if (name.startsWith("-")) + name = name.substring(1).trim(); + + IMessageDigest md; + if (name.length() == 0) + md = HashFactory.getInstance(Registry.SHA160_HASH); + else + { + // check if there is such a hash + md = HashFactory.getInstance(name); + if (md == null) + return null; + } + + ISignature result = new RSAPSSSignature(md, 0); + return result; + } + + private static final ISignature getPKCS1Signature(String name) + { + name = name.substring(Registry.RSA_PKCS1_V1_5_ENCODING.length()).trim(); + // remove the hyphen if found at the beginning + if (name.startsWith("-")) + name = name.substring(1).trim(); + + IMessageDigest md; + if (name.length() == 0) + md = HashFactory.getInstance(Registry.SHA160_HASH); + else + { + // check if there is such a hash + md = HashFactory.getInstance(name); + if (md == null) + return null; + } + + ISignature result = new RSAPKCS1V1_5Signature(md); + return result; + } +} diff --git a/gnu/java/security/util/Base64.java b/gnu/java/security/util/Base64.java new file mode 100644 index 000000000..f9998c38f --- /dev/null +++ b/gnu/java/security/util/Base64.java @@ -0,0 +1,396 @@ +/* Base64.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; + +/** + * Most of this implementation is from Robert Harder's public domain Base64 + * code (version 1.4.1 available from <http://iharder.net/xmlizable>). + */ +public class Base64 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "Base64"; + + private static final boolean DEBUG = true; + + private static final int debuglevel = 9; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Maximum line length (76) of Base64 output. */ + private static final int MAX_LINE_LENGTH = 76; + + /** The new line character (\n) as one byte. */ + private static final byte NEW_LINE = (byte) '\n'; + + /** The equals sign (=) as a byte. */ + private static final byte EQUALS_SIGN = (byte) '='; + + private static final byte WHITE_SPACE_ENC = -5; // white space in encoding + + private static final byte EQUALS_SIGN_ENC = -1; // equals sign in encoding + + /** The 64 valid Base64 values. */ + private static final byte[] ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', + (byte) 'D', (byte) 'E', (byte) 'F', + (byte) 'G', (byte) 'H', (byte) 'I', + (byte) 'J', (byte) 'K', (byte) 'L', + (byte) 'M', (byte) 'N', (byte) 'O', + (byte) 'P', (byte) 'Q', (byte) 'R', + (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', + (byte) 'Y', (byte) 'Z', (byte) 'a', + (byte) 'b', (byte) 'c', (byte) 'd', + (byte) 'e', (byte) 'f', (byte) 'g', + (byte) 'h', (byte) 'i', (byte) 'j', + (byte) 'k', (byte) 'l', (byte) 'm', + (byte) 'n', (byte) 'o', (byte) 'p', + (byte) 'q', (byte) 'r', (byte) 's', + (byte) 't', (byte) 'u', (byte) 'v', + (byte) 'w', (byte) 'x', (byte) 'y', + (byte) 'z', (byte) '0', (byte) '1', + (byte) '2', (byte) '3', (byte) '4', + (byte) '5', (byte) '6', (byte) '7', + (byte) '8', (byte) '9', (byte) '+', + (byte) '/' }; + + /** + * Translates a Base64 value to either its 6-bit reconstruction value or a + * negative number indicating some other meaning. + */ + private static final byte[] DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9, -9, -9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9 // Decimal 123 - 126 + }; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial private ctor to enfore Singleton pattern. */ + private Base64() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * Encodes a byte array into Base64 notation. Equivalent to calling + * encode(source, 0, source.length). + * + * @param src the data to convert. + */ + public static final String encode(final byte[] src) + { + return encode(src, 0, src.length, true); + } + + /** + * Encodes a byte array into Base64 notation. + * + * @param src the data to convert. + * @param off offset in array where conversion should begin. + * @param len length of data to convert. + * @param breakLines break lines at 80 characters or less. + */ + public static final String encode(final byte[] src, final int off, + final int len, final boolean breakLines) + { + final int len43 = len * 4 / 3; + final byte[] outBuff = new byte[len43 // Main 4:3 + + ((len % 3) > 0 ? 4 : 0) // Account for padding + + (breakLines ? (len43 / MAX_LINE_LENGTH) + : 0)]; // New lines + int d = 0; + int e = 0; + final int len2 = len - 2; + int lineLength = 0; + for (; d < len2; d += 3, e += 4) + { + encode3to4(src, d + off, 3, outBuff, e); + lineLength += 4; + if (breakLines && lineLength == MAX_LINE_LENGTH) + { + outBuff[e + 4] = NEW_LINE; + e++; + lineLength = 0; + } + } + + if (d < len) + { // padding needed + encode3to4(src, d + off, len - d, outBuff, e); + e += 4; + } + + return new String(outBuff, 0, e); + } + + /** + * Decodes data from Base64 notation. + * + * @param s the string to decode. + * @return the decoded data. + */ + public static final byte[] decode(final String s) + throws UnsupportedEncodingException + { + final byte[] bytes; + bytes = s.getBytes("US-ASCII"); + return decode(bytes, 0, bytes.length); + } + + /** + * Decodes Base64 content in byte array format and returns the decoded byte + * array. + * + * @param src the Base64 encoded data. + * @param off the offset of where to begin decoding. + * @param len the length of characters to decode. + * @return the decoded data. + * @throws IllegalArgumentException if src contains an illegal + * Base-64 character. + */ + public static byte[] decode(final byte[] src, final int off, final int len) + { + final int len34 = len * 3 / 4; + final byte[] outBuff = new byte[len34]; // Upper limit on size of output + int outBuffPosn = 0; + final byte[] b4 = new byte[4]; + int b4Posn = 0; + int i; + byte sbiCrop, sbiDecode; + for (i = off; i < off + len; i++) + { + sbiCrop = (byte) (src[i] & 0x7F); // Only the low seven bits + sbiDecode = DECODABET[sbiCrop]; + if (sbiDecode >= WHITE_SPACE_ENC) + { // White space, Equals sign or better + if (sbiDecode >= EQUALS_SIGN_ENC) + { + b4[b4Posn++] = sbiCrop; + if (b4Posn > 3) + { + outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn); + b4Posn = 0; + // If that was the equals sign, break out of 'for' loop + if (sbiCrop == EQUALS_SIGN) + break; + } // end if: quartet built + } // end if: equals sign or better + } + else + { + throw new IllegalArgumentException("Illegal BASE-64 character at #" + + i + ": " + src[i] + + "(decimal)"); + } + } + + final byte[] result = new byte[outBuffPosn]; + System.arraycopy(outBuff, 0, result, 0, outBuffPosn); + return result; + } + + /** + *

Encodes up to three bytes of the array src and writes + * the resulting four Base64 bytes to dest. The source and + * destination arrays can be manipulated anywhere along their length by + * specifying sOffset and dOffset.

+ * + *

This method does not check to make sure the arrays are large enough to + * accomodate sOffset + 3 for the src array or + * dOffset + 4 for the dest array. The actual + * number of significant bytes in the input array is given by + * numBytes.

+ * + * @param src the array to convert. + * @param sOffset the index where conversion begins. + * @param numBytes the number of significant bytes in your array. + * @param dest the array to hold the conversion. + * @param dOffset the index where output will be put. + * @return the destination array. + */ + private static final byte[] encode3to4(final byte[] src, final int sOffset, + final int numBytes, final byte[] dest, + final int dOffset) + { + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index ALPHABET + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3F 0x3F 0x3F Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + final int inBuff = (numBytes > 0 ? ((src[sOffset] << 24) >>> 8) : 0) + | (numBytes > 1 ? ((src[sOffset + 1] << 24) >>> 16) : 0) + | (numBytes > 2 ? ((src[sOffset + 2] << 24) >>> 24) : 0); + switch (numBytes) + { + case 3: + dest[dOffset] = ALPHABET[(inBuff >>> 18)]; + dest[dOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3F]; + dest[dOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3F]; + dest[dOffset + 3] = ALPHABET[(inBuff) & 0x3F]; + break; + case 2: + dest[dOffset] = ALPHABET[(inBuff >>> 18)]; + dest[dOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3F]; + dest[dOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3F]; + dest[dOffset + 3] = EQUALS_SIGN; + break; + case 1: + dest[dOffset] = ALPHABET[(inBuff >>> 18)]; + dest[dOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3F]; + dest[dOffset + 2] = EQUALS_SIGN; + dest[dOffset + 3] = EQUALS_SIGN; + break; + } + return dest; + } + + /** + *

Decodes four bytes from array src and writes the + * resulting bytes (up to three of them) to dest.

+ * + *

The source and destination arrays can be manipulated anywhere along + * their length by specifying sOffset and dOffset. + *

+ * + *

This method does not check to make sure your arrays are large enough + * to accomodate sOffset + 4 for the src array or + * dOffset + 3 for the dest array. This method + * returns the actual number of bytes that were converted from the Base64 + * encoding.

+ * + * @param src the array to convert. + * @param sOffset the index where conversion begins. + * @param dest the array to hold the conversion. + * @param dOffset the index where output will be put. + * @return the number of decoded bytes converted. + */ + private static final int decode4to3(final byte[] src, final int sOffset, + final byte[] dest, final int dOffset) + { + if (src[sOffset + 2] == EQUALS_SIGN) + { // Example: Dk== + final int outBuff = ((DECODABET[src[sOffset]] & 0xFF) << 18) + | ((DECODABET[src[sOffset + 1]] & 0xFF) << 12); + dest[dOffset] = (byte) (outBuff >>> 16); + return 1; + } + + if (src[sOffset + 3] == EQUALS_SIGN) + { // Example: DkL= + final int outBuff = ((DECODABET[src[sOffset]] & 0xFF) << 18) + | ((DECODABET[src[sOffset + 1]] & 0xFF) << 12) + | ((DECODABET[src[sOffset + 2]] & 0xFF) << 6); + dest[dOffset] = (byte) (outBuff >>> 16); + dest[dOffset + 1] = (byte) (outBuff >>> 8); + return 2; + } + + try + { // Example: DkLE + final int outBuff = ((DECODABET[src[sOffset]] & 0xFF) << 18) + | ((DECODABET[src[sOffset + 1]] & 0xFF) << 12) + | ((DECODABET[src[sOffset + 2]] & 0xFF) << 6) + | ((DECODABET[src[sOffset + 3]] & 0xFF)); + dest[dOffset] = (byte) (outBuff >> 16); + dest[dOffset + 1] = (byte) (outBuff >> 8); + dest[dOffset + 2] = (byte) outBuff; + return 3; + } + catch (Exception x) + { + if (DEBUG && debuglevel > 8) + { + debug("" + src[sOffset] + ": " + (DECODABET[src[sOffset]])); + debug("" + src[sOffset + 1] + ": " + (DECODABET[src[sOffset + 1]])); + debug("" + src[sOffset + 2] + ": " + (DECODABET[src[sOffset + 2]])); + debug("" + src[sOffset + 3] + ": " + (DECODABET[src[sOffset + 3]])); + } + return -1; + } + } +} diff --git a/gnu/java/security/util/DerUtil.java b/gnu/java/security/util/DerUtil.java new file mode 100644 index 000000000..26232ba98 --- /dev/null +++ b/gnu/java/security/util/DerUtil.java @@ -0,0 +1,64 @@ +/* DerUtil.java -- Utility methods for DER read/write operations + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import gnu.java.security.der.DEREncodingException; +import gnu.java.security.der.DERValue; + +import java.math.BigInteger; + +/** + * Utility methods for DER encoding handling. + */ +public abstract class DerUtil +{ + public static final void checkIsConstructed(DERValue v, String msg) + throws DEREncodingException + { + if (! v.isConstructed()) + throw new DEREncodingException(msg); + } + + public static final void checkIsBigInteger(DERValue v, String msg) + throws DEREncodingException + { + if (! (v.getValue() instanceof BigInteger)) + throw new DEREncodingException(msg); + } +} diff --git a/gnu/java/security/util/ExpirableObject.java b/gnu/java/security/util/ExpirableObject.java new file mode 100644 index 000000000..2d4452015 --- /dev/null +++ b/gnu/java/security/util/ExpirableObject.java @@ -0,0 +1,172 @@ +/* ExpirableObject.java -- an object that is automatically destroyed. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.util.Timer; +import java.util.TimerTask; + +import javax.security.auth.DestroyFailedException; +import javax.security.auth.Destroyable; + +/** + * The base class for objects with sensitive data that are automatically + * destroyed after a timeout elapses. On creation, an object that extends + * this class will automatically be added to a {@link Timer} object that, + * once a timeout elapses, will automatically call the {@link + * Destroyable#destroy()} method. + * + *

Concrete subclasses must implement the {@link doDestroy()} method + * instead of {@link Destroyable#destroy()}; the behavior of that method + * should match exactly the behavior desired of destroy(). + * + *

Note that if a {@link DestroyFailedException} occurs when the timeout + * expires, it will not be reported. + * + * @see Destroyable + */ +public abstract class ExpirableObject implements Destroyable +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + /** + * The default timeout, used in the default constructor. + */ + public static final long DEFAULT_TIMEOUT = 3600000L; + + /** + * The timer that expires instances. + */ + private static final Timer EXPIRER = new Timer(true); + + /** + * A reference to the task that will destroy this object when the timeout + * expires. + */ + private final Destroyer destroyer; + + // Constructors. + // ------------------------------------------------------------------------- + + /** + * Create a new expirable object that will expire after one hour. + */ + protected ExpirableObject() + { + this(DEFAULT_TIMEOUT); + } + + /** + * Create a new expirable object that will expire after the specified + * timeout. + * + * @param delay The delay before expiration. + * @throws IllegalArgumentException If delay is negative, or if + * delay + System.currentTimeMillis() is negative. + */ + protected ExpirableObject(final long delay) + { + destroyer = new Destroyer(this); + EXPIRER.schedule(destroyer, delay); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + /** + * Destroys this object. This method calls {@link doDestroy}, then, if + * no exception is thrown, cancels the task that would destroy this object + * when the timeout is reached. + * + * @throws DestroyFailedException If this operation fails. + */ + public final void destroy() throws DestroyFailedException + { + doDestroy(); + destroyer.cancel(); + } + + /** + * Subclasses must implement this method instead of the {@link + * Destroyable#destroy()} method. + * + * @throws DestroyFailedException If this operation fails. + */ + protected abstract void doDestroy() throws DestroyFailedException; + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * The task that destroys the target when the timeout elapses. + */ + private final class Destroyer extends TimerTask + { + + // Fields. + // ----------------------------------------------------------------------- + + private final ExpirableObject target; + + // Constructor. + // ----------------------------------------------------------------------- + + Destroyer(final ExpirableObject target) + { + super(); + this.target = target; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public void run() + { + try + { + if (!target.isDestroyed()) + target.doDestroy(); + } + catch (DestroyFailedException dfe) + { + } + } + } +} diff --git a/gnu/java/security/util/FormatUtil.java b/gnu/java/security/util/FormatUtil.java new file mode 100644 index 000000000..eed669cc3 --- /dev/null +++ b/gnu/java/security/util/FormatUtil.java @@ -0,0 +1,140 @@ +/* FormatUtil.java -- Encoding and decoding format utility methods + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import gnu.java.security.Registry; + +/** + * Encoding and decoding format utility methods. + */ +public class FormatUtil +{ + /** Trivial constructor to enforce Singleton pattern. */ + private FormatUtil() + { + super(); + } + + /** + * Returns the fully qualified name of the designated encoding ID. + * + * @param formatID the unique identifier of the encoding format. + * @return the fully qualified name of the designated format. Returns + * null if no such encoding format is known. + */ + public static final String getEncodingName(int formatID) + { + String result = null; + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + result = Registry.RAW_ENCODING; + break; + case Registry.X509_ENCODING_ID: + result = Registry.X509_ENCODING; + break; + case Registry.PKCS8_ENCODING_ID: + result = Registry.PKCS8_ENCODING; + break; + case Registry.ASN1_ENCODING_ID: + result = Registry.ASN1_ENCODING; + break; + } + + return result; + } + + /** + * Returns the short name of the designated encoding ID. This is used by the + * JCE Adapters. + * + * @param formatID the unique identifier of the encoding format. + * @return the short name of the designated format. Returns null + * if no such encoding format is known. + */ + public static final String getEncodingShortName(int formatID) + { + String result = null; + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + result = Registry.RAW_ENCODING_SHORT_NAME; + break; + case Registry.X509_ENCODING_ID: + result = Registry.X509_ENCODING_SORT_NAME; + break; + case Registry.PKCS8_ENCODING_ID: + result = Registry.PKCS8_ENCODING_SHORT_NAME; + break; + case Registry.ASN1_ENCODING_ID: + result = Registry.ASN1_ENCODING_SHORT_NAME; + break; + } + + return result; + } + + /** + * Returns the identifier of the encoding format given its short name. + * + * @param name the case-insensitive canonical short name of an encoding + * format. + * @return the identifier of the designated encoding format, or 0 + * if the name does not correspond to any known format. + */ + public static final int getFormatID(String name) + { + if (name == null) + return 0; + + name = name.trim(); + if (name.length() == 0) + return 0; + + int result = 0; + if (name.equalsIgnoreCase(Registry.RAW_ENCODING_SHORT_NAME)) + result = Registry.RAW_ENCODING_ID; + else if (name.equalsIgnoreCase(Registry.X509_ENCODING_SORT_NAME)) + result = Registry.X509_ENCODING_ID; + else if (name.equalsIgnoreCase(Registry.PKCS8_ENCODING_SHORT_NAME)) + result = Registry.PKCS8_ENCODING_ID; + + return result; + } +} diff --git a/gnu/java/security/util/PRNG.java b/gnu/java/security/util/PRNG.java new file mode 100644 index 000000000..138cc6bcb --- /dev/null +++ b/gnu/java/security/util/PRNG.java @@ -0,0 +1,156 @@ +/* PRNG.java -- A Utility methods for default source of randomness + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.util.HashMap; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.prng.MDGenerator; + +/** + * A useful hash-based (SHA) pseudo-random number generator used + * throughout this library. + * + * @see MDGenerator + */ +public class PRNG +{ + // Constans and fields + // -------------------------------------------------------------------------- + + /** The underlying {@link IRandom}. */ + private IRandom delegate; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** + * Private constructor to enforce using the Factory method. + * + * @param delegate + * the undelying {@link IRandom} object used. + */ + private PRNG(IRandom delegate) + { + super(); + + this.delegate = delegate; + } + + // Class methods + // -------------------------------------------------------------------------- + + public static final PRNG getInstance() + { + IRandom delegate = new MDGenerator(); + try + { + HashMap map = new HashMap(); + // initialise it with a seed + long t = System.currentTimeMillis(); + byte[] seed = new byte[] { + (byte) (t >>> 56), (byte) (t >>> 48), + (byte) (t >>> 40), (byte) (t >>> 32), + (byte) (t >>> 24), (byte) (t >>> 16), + (byte) (t >>> 8), (byte) t}; + map.put(MDGenerator.SEEED, seed); + delegate.init(map); // default is to use SHA-1 hash + } + catch (Exception x) + { + throw new ExceptionInInitializerError(x); + } + + return new PRNG(delegate); + } + + // Instance methods + // -------------------------------------------------------------------------- + + /** + * Completely fills the designated buffer with random data + * generated by the underlying delegate. + * + * @param buffer + * the place holder of random bytes generated by the underlying + * delegate. On output, the contents of buffer are + * replaced with pseudo-random data, iff the buffer + * size is not zero. + */ + public void nextBytes(byte[] buffer) + { + nextBytes(buffer, 0, buffer.length); + } + + /** + * Fills the designated buffer, starting from byte at position + * offset with, at most, length bytes of random + * data generated by the underlying delegate. + * + * @see IRandom#nextBytes + */ + public void nextBytes(byte[] buffer, int offset, int length) + { + try + { + delegate.nextBytes(buffer, offset, length); + } + catch (LimitReachedException x) // re-initialise with a seed + { + try + { + HashMap map = new HashMap(); + long t = System.currentTimeMillis(); + byte[] seed = new byte[] { + (byte)(t >>> 56), (byte)(t >>> 48), + (byte)(t >>> 40), (byte)(t >>> 32), + (byte)(t >>> 24), (byte)(t >>> 16), + (byte)(t >>> 8), (byte) t }; + map.put(MDGenerator.SEEED, seed); + delegate.init(map); // default is to use SHA-1 hash + delegate.nextBytes(buffer, offset, length); + } + catch (Exception y) + { + throw new ExceptionInInitializerError(y); + } + } + } +} diff --git a/gnu/java/security/util/Prime2.java b/gnu/java/security/util/Prime2.java new file mode 100644 index 000000000..6e46f5fca --- /dev/null +++ b/gnu/java/security/util/Prime2.java @@ -0,0 +1,417 @@ +/* Prime2.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; +import java.math.BigInteger; +import java.util.Map; +import java.util.WeakHashMap; + +/** + *

A collection of prime number related utilities used in this library.

+ */ +public class Prime2 +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "prime"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 5; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int DEFAULT_CERTAINTY = 20; // XXX is this a good value? + + private static final BigInteger ZERO = BigInteger.ZERO; + + private static final BigInteger ONE = BigInteger.ONE; + + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** + * The first SMALL_PRIME primes: Algorithm P, section 1.3.2, The Art of + * Computer Programming, Donald E. Knuth. + */ + private static final int SMALL_PRIME_COUNT = 1000; + + private static final BigInteger[] SMALL_PRIME = new BigInteger[SMALL_PRIME_COUNT]; + static + { + long time = -System.currentTimeMillis(); + SMALL_PRIME[0] = TWO; + int N = 3; + int J = 0; + int prime; + P2: while (true) + { + SMALL_PRIME[++J] = BigInteger.valueOf(N); + if (J >= 999) + { + break P2; + } + P4: while (true) + { + N += 2; + P6: for (int K = 1; true; K++) + { + prime = SMALL_PRIME[K].intValue(); + if ((N % prime) == 0) + { + continue P4; + } + else if ((N / prime) <= prime) + { + continue P2; + } + } + } + } + time += System.currentTimeMillis(); + if (DEBUG && debuglevel > 8) + { + StringBuffer sb; + for (int i = 0; i < (SMALL_PRIME_COUNT / 10); i++) + { + sb = new StringBuffer(); + for (int j = 0; j < 10; j++) + { + sb.append(String.valueOf(SMALL_PRIME[i * 10 + j])).append(" "); + } + debug(sb.toString()); + } + } + if (DEBUG && debuglevel > 4) + { + debug("Generating first " + String.valueOf(SMALL_PRIME_COUNT) + + " primes took: " + String.valueOf(time) + " ms."); + } + } + + private static final Map knownPrimes = new WeakHashMap(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private Prime2() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Trial division for the first 1000 small primes.

+ * + *

Returns true if at least one small prime, among the first + * 1000 ones, was found to divide the designated number. Retuens false + * otherwise.

+ * + * @param w the number to test. + * @return true if at least one small prime was found to divide + * the designated number. + */ + public static boolean hasSmallPrimeDivisor(BigInteger w) + { + BigInteger prime; + for (int i = 0; i < SMALL_PRIME_COUNT; i++) + { + prime = SMALL_PRIME[i]; + if (w.mod(prime).equals(ZERO)) + { + if (DEBUG && debuglevel > 4) + { + debug(prime.toString(16) + " | " + w.toString(16) + "..."); + } + return true; + } + } + if (DEBUG && debuglevel > 4) + { + debug(w.toString(16) + " has no small prime divisors..."); + } + return false; + } + + /** + *

Java port of Colin Plumb primality test (Euler Criterion) + * implementation for a base of 2 --from bnlib-1.1 release, function + * primeTest() in prime.c. this is his comments.

+ * + *

"Now, check that bn is prime. If it passes to the base 2, it's prime + * beyond all reasonable doubt, and everything else is just gravy, but it + * gives people warm fuzzies to do it.

+ * + *

This starts with verifying Euler's criterion for a base of 2. This is + * the fastest pseudoprimality test that I know of, saving a modular squaring + * over a Fermat test, as well as being stronger. 7/8 of the time, it's as + * strong as a strong pseudoprimality test, too. (The exception being when + * bn == 1 mod 8 and 2 is a quartic residue, i.e. + * bn is of the form a^2 + (8*b)^2.) The precise + * series of tricks used here is not documented anywhere, so here's an + * explanation. Euler's criterion states that if p is prime + * then a^((p-1)/2) is congruent to Jacobi(a,p), + * modulo p. Jacobi(a, p) is a function which is + * +1 if a is a square modulo p, and -1 + * if it is not. For a = 2, this is particularly simple. It's + * +1 if p == +/-1 (mod 8), and -1 if + * m == +/-3 (mod 8). If p == 3 (mod 4), then all + * a strong test does is compute 2^((p-1)/2). and see if it's + * +1 or -1. (Euler's criterion says which + * it should be.) If p == 5 (mod 8), then 2^((p-1)/2) + * is -1, so the initial step in a strong test, looking at + * 2^((p-1)/4), is wasted --you're not going to find a + * +/-1 before then if it is prime, and it shouldn't + * have either of those values if it isn't. So don't bother.

+ * + *

The remaining case is p == 1 (mod 8). In this case, we + * expect 2^((p-1)/2) == 1 (mod p), so we expect that the + * square root of this, 2^((p-1)/4), will be +/-1 (mod p) + * . Evaluating this saves us a modular squaring 1/4 of the time. If + * it's -1, a strong pseudoprimality test would call p + * prime as well. Only if the result is +1, indicating that + * 2 is not only a quadratic residue, but a quartic one as well, + * does a strong pseudoprimality test verify more things than this test does. + * Good enough.

+ * + *

We could back that down another step, looking at 2^((p-1)/8) + * if there was a cheap way to determine if 2 were expected to + * be a quartic residue or not. Dirichlet proved that 2 is a + * quadratic residue iff p is of the form a^2 + (8*b^2). + * All primes == 1 (mod 4) can be expressed as a^2 + + * (2*b)^2, but I see no cheap way to evaluate this condition."

+ * + * @param bn the number to test. + * @return true iff the designated number passes Euler criterion + * as implemented by Colin Plumb in his bnlib version 1.1. + */ + public static boolean passEulerCriterion(final BigInteger bn) + { + BigInteger bn_minus_one = bn.subtract(ONE); + BigInteger e = bn_minus_one; + // l is the 3 least-significant bits of e + int l = e.and(BigInteger.valueOf(7L)).intValue(); + int j = 1; // Where to start in prime array for strong prime tests + BigInteger a; + int k; + + if (l != 0) + { + e = e.shiftRight(1); + a = TWO.modPow(e, bn); + if (l == 6) // bn == 7 mod 8, expect +1 + { + if (a.bitLength() != 1) + { + debugBI("Fails Euler criterion #1", bn); + return false; // Not prime + } + k = 1; + } + else // bn == 3 or 5 mod 8, expect -1 == bn-1 + { + a = a.add(ONE); + if (a.compareTo(bn) != 0) + { + debugBI("Fails Euler criterion #2", bn); + return false; // Not prime + } + k = 1; + if ((l & 4) != 0) // bn == 5 mod 8, make odd for strong tests + { + e = e.shiftRight(1); + k = 2; + } + } + } + else // bn == 1 mod 8, expect 2^((bn-1)/4) == +/-1 mod bn + { + e = e.shiftRight(2); + a = TWO.modPow(e, bn); + if (a.bitLength() == 1) + j = 0; // Re-do strong prime test to base 2 + else + { + a = a.add(ONE); + if (a.compareTo(bn) != 0) + { + debugBI("Fails Euler criterion #3", bn); + return false; // Not prime + } + } + // bnMakeOdd(n) = d * 2^s. Replaces n with d and returns s. + k = e.getLowestSetBit(); + e = e.shiftRight(k); + k += 2; + } + // It's prime! Now go on to confirmation tests + + // Now, e = (bn-1)/2^k is odd. k >= 1, and has a given value with + // probability 2^-k, so its expected value is 2. j = 1 in the usual case + // when the previous test was as good as a strong prime test, but 1/8 of + // the time, j = 0 because the strong prime test to the base 2 needs to + // be re-done. + for (int i = j; i < 7; i++) // try only the first 7 primes + { + a = SMALL_PRIME[i]; + a = a.modPow(e, bn); + if (a.bitLength() == 1) + continue; // Passed this test + + l = k; + while (true) + { +// a = a.add(ONE); +// if (a.compareTo(w) == 0) { // Was result bn-1? + if (a.compareTo(bn_minus_one) == 0) // Was result bn-1? + break; // Prime + + if (--l == 0) // Reached end, not -1? luck? + { + debugBI("Fails Euler criterion #4", bn); + return false; // Failed, not prime + } + // This portion is executed, on average, once +// a = a.subtract(ONE); // Put a back where it was + a = a.modPow(TWO, bn); + if (a.bitLength() == 1) + { + debugBI("Fails Euler criterion #5", bn); + return false; // Failed, not prime + } + } + // It worked (to the base primes[i]) + } + debugBI("Passes Euler criterion", bn); + return true; + } + + public static boolean isProbablePrime(BigInteger w) + { + return isProbablePrime(w, DEFAULT_CERTAINTY); + } + + /** + * Wrapper around {@link BigInteger#isProbablePrime(int)} with few pre-checks. + * + * @param w the integer to test. + * @param certainty the certainty with which to compute the test. + */ + public static boolean isProbablePrime(BigInteger w, int certainty) + { + // Nonnumbers are not prime. + if (w == null) + return false; + + // eliminate trivial cases when w == 0 or 1 + if (w.equals(ZERO) || w.equals(ONE)) + return false; + + // Test if w is a known small prime. + for (int i = 0; i < SMALL_PRIME_COUNT; i++) + if (w.equals(SMALL_PRIME[i])) + { + if (DEBUG && debuglevel > 4) + debug(w.toString(16) + " is a small prime"); + return true; + } + + // Check if it's already a known prime + WeakReference obj = (WeakReference) knownPrimes.get(w); + if (obj != null && w.equals(obj.get())) + { + if (DEBUG && debuglevel > 4) + debug("found in known primes"); + return true; + } + + // trial division with first 1000 primes + if (hasSmallPrimeDivisor(w)) + { + if (DEBUG && debuglevel > 4) + debug(w.toString(16) + " has a small prime divisor. Rejected..."); + return false; + } + +// Euler's criterion. +// if (passEulerCriterion(w)) { +// if (DEBUG && debuglevel > 4) { +// debug(w.toString(16)+" passes Euler's criterion..."); +// } +// } else { +// if (DEBUG && debuglevel > 4) { +// debug(w.toString(16)+" fails Euler's criterion. Rejected..."); +// } +// return false; +// } +// +// if (DEBUG && debuglevel > 4) +// { +// debug(w.toString(16) + " is probable prime. Accepted..."); +// } + + boolean result = w.isProbablePrime(certainty); + if (result && certainty > 0) // store it in the known primes weak hash-map + knownPrimes.put(w, new WeakReference(w)); + + return result; + } + + // helper methods ----------------------------------------------------------- + + private static final void debugBI(String msg, BigInteger bn) + { + if (DEBUG && debuglevel > 4) + debug("*** " + msg + ": 0x" + bn.toString(16)); + } +} diff --git a/gnu/java/security/util/Sequence.java b/gnu/java/security/util/Sequence.java new file mode 100644 index 000000000..5edc7942e --- /dev/null +++ b/gnu/java/security/util/Sequence.java @@ -0,0 +1,149 @@ +/* Sequence.java -- a sequence of integers. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.util.AbstractList; +import java.util.LinkedList; + +/** + * A monotonic sequence of integers in the finite field 232. + */ +public final class Sequence extends AbstractList +{ + + // Field. + // ------------------------------------------------------------------------ + + private final Integer[] sequence; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Create a sequence of integers from 0 to end, with an increment + * of 1. If end is less than 0, then the sequence will wrap around + * through all positive integers then negative integers until the end + * value is reached. Naturally, this will result in an enormous object, + * so don't do this. + * + * @param end The ending value. + */ + public Sequence(int end) + { + this(0, end, 1); + } + + /** + * Create a sequence of integers from start to end, with an + * increment of 1. If end is less than start, then the sequence + * will wrap around until the end value is reached. Naturally, this will + * result in an enormous object, so don't do this. + * + * @param start The starting value. + * @param end The ending value. + */ + public Sequence(int start, int end) + { + this(start, end, 1); + } + + /** + * Create a sequence of integers from start to end, with an + * increment of span. If end is less than start, then + * the sequence will wrap around until the end value is reached. Naturally, + * this will result in an enormous object, so don't do this. + * + *

span can be negative, resulting in a decresing sequence. + * + *

If span is 0, then the sequence will contain {start, + * end} if start != end, or just the singleton + * start if start == end. + * + * @param start The starting value. + * @param end The ending value. + * @param span The increment value. + */ + public Sequence(int start, int end, int span) + { + if (span == 0) + { + if (start != end) + { + sequence = new Integer[] { new Integer(start), new Integer(end) }; + } + else + { + sequence = new Integer[] { new Integer(start) }; + } + } + else + { + LinkedList l = new LinkedList(); + for (int i = start; i != end; i += span) + { + l.add(new Integer(i)); + } + l.add(new Integer(end)); + sequence = (Integer[]) l.toArray(new Integer[l.size()]); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public Object get(int index) + { + if (index < 0 || index >= size()) + { + throw new IndexOutOfBoundsException("index=" + index + ", size=" + + size()); + } + return sequence[index]; + } + + public int size() + { + return sequence.length; + } + + public Object[] toArray() + { + return (Object[]) sequence.clone(); + } +} diff --git a/gnu/java/security/util/SimpleList.java b/gnu/java/security/util/SimpleList.java new file mode 100644 index 000000000..b2525c4b8 --- /dev/null +++ b/gnu/java/security/util/SimpleList.java @@ -0,0 +1,171 @@ +/* SimpleList.java -- simple way to make tuples. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.util.AbstractList; +import java.util.Collection; +import java.util.Iterator; + +/** + * A simple way to create immutable n-tuples. This class can be created with + * up to four elements specified via one of the constructors, or with a + * collection of arbitrary size. + */ +public final class SimpleList extends AbstractList +{ + + // Fields. + // ------------------------------------------------------------------------ + + private final Object[] elements; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a singleton list. + * + * @param e1 The first element. + */ + public SimpleList(final Object element) + { + elements = new Object[1]; + elements[0] = element; + } + + /** + * Create an ordered pair (2-tuple). + * + * @param e1 The first element. + * @param e2 The second element. + */ + public SimpleList(final Object e1, final Object e2) + { + elements = new Object[2]; + elements[0] = e1; + elements[1] = e2; + } + + /** + * Create a 3-tuple. + * + * @param e1 The first element. + * @param e2 The second element. + * @param e3 The third element. + */ + public SimpleList(final Object e1, final Object e2, final Object e3) + { + elements = new Object[3]; + elements[0] = e1; + elements[1] = e2; + elements[2] = e3; + } + + /** + * Create a 4-tuple. + * + * @param e1 The first element. + * @param e2 The second element. + * @param e3 The third element. + * @param e4 The fourth element. + */ + public SimpleList(final Object e1, final Object e2, final Object e3, + final Object e4) + { + elements = new Object[4]; + elements[0] = e1; + elements[1] = e2; + elements[2] = e3; + elements[3] = e4; + } + + /** + * Create the empty list. + */ + public SimpleList() + { + elements = null; + } + + /** + * Create an n-tuple of arbitrary size. Even if the supplied collection has + * no natural order, the created n-tuple will have the order that the + * elements are returned by the collection's iterator. + * + * @param c The collection. + */ + public SimpleList(Collection c) + { + elements = new Object[c.size()]; + int i = 0; + for (Iterator it = c.iterator(); it.hasNext() && i < elements.length;) + { + elements[i++] = it.next(); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public int size() + { + if (elements == null) + return 0; + return elements.length; + } + + public Object get(int index) + { + if (elements == null) + { + throw new IndexOutOfBoundsException("list is empty"); + } + if (index < 0 || index >= elements.length) + { + throw new IndexOutOfBoundsException("index=" + index + ", size=" + + size()); + } + return elements[index]; + } + + public String toString() + { + return SimpleList.class.getName() + "(" + size() + ") " + super.toString(); + } +} diff --git a/gnu/java/security/util/Util.java b/gnu/java/security/util/Util.java new file mode 100644 index 000000000..7eb308e2d --- /dev/null +++ b/gnu/java/security/util/Util.java @@ -0,0 +1,692 @@ +/* Util.java -- various utility routines. + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.math.BigInteger; + +/** + *

A collection of utility methods used throughout this project.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class Util +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Hex charset + private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray(); + + // Base-64 charset + private static final String BASE64_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"; + + private static final char[] BASE64_CHARSET = BASE64_CHARS.toCharArray(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private Util() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns a string of hexadecimal digits from a byte array. Each byte is + * converted to 2 hex symbols; zero(es) included.

+ * + *

This method calls the method with same name and three arguments as:

+ * + *
+   *    toString(ba, 0, ba.length);
+   * 
+ * + * @param ba the byte array to convert. + * @return a string of hexadecimal characters (two for each byte) + * representing the designated input byte array. + */ + public static String toString(byte[] ba) + { + return toString(ba, 0, ba.length); + } + + /** + *

Returns a string of hexadecimal digits from a byte array, starting at + * offset and consisting of length bytes. Each byte + * is converted to 2 hex symbols; zero(es) included.

+ * + * @param ba the byte array to convert. + * @param offset the index from which to start considering the bytes to + * convert. + * @param length the count of bytes, starting from the designated offset to + * convert. + * @return a string of hexadecimal characters (two for each byte) + * representing the designated input byte sub-array. + */ + public static final String toString(byte[] ba, int offset, int length) + { + char[] buf = new char[length * 2]; + for (int i = 0, j = 0, k; i < length;) + { + k = ba[offset + i++]; + buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; + buf[j++] = HEX_DIGITS[k & 0x0F]; + } + return new String(buf); + } + + /** + *

Returns a string of hexadecimal digits from a byte array. Each byte is + * converted to 2 hex symbols; zero(es) included. The argument is + * treated as a large little-endian integer and is returned as a + * large big-endian integer.

+ * + *

This method calls the method with same name and three arguments as:

+ * + *
+   *    toReversedString(ba, 0, ba.length);
+   * 
+ * + * @param ba the byte array to convert. + * @return a string of hexadecimal characters (two for each byte) + * representing the designated input byte array. + */ + public static String toReversedString(byte[] ba) + { + return toReversedString(ba, 0, ba.length); + } + + /** + *

Returns a string of hexadecimal digits from a byte array, starting at + * offset and consisting of length bytes. Each byte + * is converted to 2 hex symbols; zero(es) included.

+ * + *

The byte array is treated as a large little-endian integer, and + * is returned as a large big-endian integer.

+ * + * @param ba the byte array to convert. + * @param offset the index from which to start considering the bytes to + * convert. + * @param length the count of bytes, starting from the designated offset to + * convert. + * @return a string of hexadecimal characters (two for each byte) + * representing the designated input byte sub-array. + */ + public static final String toReversedString(byte[] ba, int offset, int length) + { + char[] buf = new char[length * 2]; + for (int i = offset + length - 1, j = 0, k; i >= offset;) + { + k = ba[offset + i--]; + buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; + buf[j++] = HEX_DIGITS[k & 0x0F]; + } + return new String(buf); + } + + /** + *

Returns a byte array from a string of hexadecimal digits.

+ * + * @param s a string of hexadecimal ASCII characters + * @return the decoded byte array from the input hexadecimal string. + */ + public static byte[] toBytesFromString(String s) + { + int limit = s.length(); + byte[] result = new byte[((limit + 1) / 2)]; + int i = 0, j = 0; + if ((limit % 2) == 1) + { + result[j++] = (byte) fromDigit(s.charAt(i++)); + } + while (i < limit) + { + result[j] = (byte) (fromDigit(s.charAt(i++)) << 4); + result[j++] |= (byte) fromDigit(s.charAt(i++)); + } + return result; + } + + /** + *

Returns a byte array from a string of hexadecimal digits, interpreting + * them as a large big-endian integer and returning it as a large + * little-endian integer.

+ * + * @param s a string of hexadecimal ASCII characters + * @return the decoded byte array from the input hexadecimal string. + */ + public static byte[] toReversedBytesFromString(String s) + { + int limit = s.length(); + byte[] result = new byte[((limit + 1) / 2)]; + int i = 0; + if ((limit % 2) == 1) + { + result[i++] = (byte) fromDigit(s.charAt(--limit)); + } + while (limit > 0) + { + result[i] = (byte) fromDigit(s.charAt(--limit)); + result[i++] |= (byte) (fromDigit(s.charAt(--limit)) << 4); + } + return result; + } + + /** + *

Returns a number from 0 to 15 corresponding + * to the designated hexadecimal digit.

+ * + * @param c a hexadecimal ASCII symbol. + */ + public static int fromDigit(char c) + { + if (c >= '0' && c <= '9') + { + return c - '0'; + } + else if (c >= 'A' && c <= 'F') + { + return c - 'A' + 10; + } + else if (c >= 'a' && c <= 'f') + { + return c - 'a' + 10; + } + else + throw new IllegalArgumentException("Invalid hexadecimal digit: " + c); + } + + /** + *

Returns a string of 8 hexadecimal digits (most significant digit first) + * corresponding to the unsigned integer n.

+ * + * @param n the unsigned integer to convert. + * @return a hexadecimal string 8-character long. + */ + public static String toString(int n) + { + char[] buf = new char[8]; + for (int i = 7; i >= 0; i--) + { + buf[i] = HEX_DIGITS[n & 0x0F]; + n >>>= 4; + } + return new String(buf); + } + + /** + *

Returns a string of hexadecimal digits from an integer array. Each int + * is converted to 4 hex symbols.

+ */ + public static String toString(int[] ia) + { + int length = ia.length; + char[] buf = new char[length * 8]; + for (int i = 0, j = 0, k; i < length; i++) + { + k = ia[i]; + buf[j++] = HEX_DIGITS[(k >>> 28) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 24) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 20) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 16) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 12) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 8) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; + buf[j++] = HEX_DIGITS[k & 0x0F]; + } + return new String(buf); + } + + /** + *

Returns a string of 16 hexadecimal digits (most significant digit first) + * corresponding to the unsigned long n.

+ * + * @param n the unsigned long to convert. + * @return a hexadecimal string 16-character long. + */ + public static String toString(long n) + { + char[] b = new char[16]; + for (int i = 15; i >= 0; i--) + { + b[i] = HEX_DIGITS[(int) (n & 0x0FL)]; + n >>>= 4; + } + return new String(b); + } + + /** + *

Similar to the toString() method except that the Unicode + * escape character is inserted before every pair of bytes. Useful to + * externalise byte arrays that will be constructed later from such strings; + * eg. s-box values.

+ * + * @throws ArrayIndexOutOfBoundsException if the length is odd. + */ + public static String toUnicodeString(byte[] ba) + { + return toUnicodeString(ba, 0, ba.length); + } + + /** + *

Similar to the toString() method except that the Unicode + * escape character is inserted before every pair of bytes. Useful to + * externalise byte arrays that will be constructed later from such strings; + * eg. s-box values.

+ * + * @throws ArrayIndexOutOfBoundsException if the length is odd. + */ + public static final String toUnicodeString(byte[] ba, int offset, int length) + { + StringBuffer sb = new StringBuffer(); + int i = 0; + int j = 0; + int k; + sb.append('\n').append("\""); + while (i < length) + { + sb.append("\\u"); + + k = ba[offset + i++]; + sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]); + sb.append(HEX_DIGITS[k & 0x0F]); + + k = ba[offset + i++]; + sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]); + sb.append(HEX_DIGITS[k & 0x0F]); + + if ((++j % 8) == 0) + { + sb.append("\"+").append('\n').append("\""); + } + } + sb.append("\"").append('\n'); + return sb.toString(); + } + + /** + *

Similar to the toString() method except that the Unicode + * escape character is inserted before every pair of bytes. Useful to + * externalise integer arrays that will be constructed later from such + * strings; eg. s-box values.

+ * + * @throws ArrayIndexOutOfBoundsException if the length is not a multiple of 4. + */ + public static String toUnicodeString(int[] ia) + { + StringBuffer sb = new StringBuffer(); + int i = 0; + int j = 0; + int k; + sb.append('\n').append("\""); + while (i < ia.length) + { + k = ia[i++]; + sb.append("\\u"); + sb.append(HEX_DIGITS[(k >>> 28) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 24) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 20) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 16) & 0x0F]); + sb.append("\\u"); + sb.append(HEX_DIGITS[(k >>> 12) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 8) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]); + sb.append(HEX_DIGITS[k & 0x0F]); + + if ((++j % 4) == 0) + { + sb.append("\"+").append('\n').append("\""); + } + } + sb.append("\"").append('\n'); + return sb.toString(); + } + + public static byte[] toBytesFromUnicode(String s) + { + int limit = s.length() * 2; + byte[] result = new byte[limit]; + char c; + for (int i = 0; i < limit; i++) + { + c = s.charAt(i >>> 1); + result[i] = (byte) (((i & 1) == 0) ? c >>> 8 : c); + } + return result; + } + + /** + *

Dumps a byte array as a string, in a format that is easy to read for + * debugging. The string m is prepended to the start of each + * line.

+ * + *

If offset and length are omitted, the whole + * array is used. If m is omitted, nothing is prepended to each + * line.

+ * + * @param data the byte array to be dumped. + * @param offset the offset within data to start from. + * @param length the number of bytes to dump. + * @param m a string to be prepended to each line. + * @return a string containing the result. + */ + public static String dumpString(byte[] data, int offset, int length, String m) + { + if (data == null) + { + return m + "null\n"; + } + StringBuffer sb = new StringBuffer(length * 3); + if (length > 32) + { + sb.append(m).append("Hexadecimal dump of ").append(length).append( + " bytes...\n"); + } + // each line will list 32 bytes in 4 groups of 8 each + int end = offset + length; + String s; + int l = Integer.toString(length).length(); + if (l < 4) + { + l = 4; + } + for (; offset < end; offset += 32) + { + if (length > 32) + { + s = " " + offset; + sb.append(m).append(s.substring(s.length() - l)).append(": "); + } + int i = 0; + for (; i < 32 && offset + i + 7 < end; i += 8) + { + sb.append(toString(data, offset + i, 8)).append(' '); + } + if (i < 32) + { + for (; i < 32 && offset + i < end; i++) + { + sb.append(byteToString(data[offset + i])); + } + } + sb.append('\n'); + } + return sb.toString(); + } + + public static String dumpString(byte[] data) + { + return (data == null) ? "null\n" : dumpString(data, 0, data.length, ""); + } + + public static String dumpString(byte[] data, String m) + { + return (data == null) ? "null\n" : dumpString(data, 0, data.length, m); + } + + public static String dumpString(byte[] data, int offset, int length) + { + return dumpString(data, offset, length, ""); + } + + /** + *

Returns a string of 2 hexadecimal digits (most significant digit first) + * corresponding to the lowest 8 bits of n.

+ * + * @param n the byte value to convert. + * @return a string of 2 hex characters representing the input. + */ + public static String byteToString(int n) + { + char[] buf = { HEX_DIGITS[(n >>> 4) & 0x0F], HEX_DIGITS[n & 0x0F] }; + return new String(buf); + } + + /** + *

Converts a designated byte array to a Base-64 representation, with the + * exceptions that (a) leading 0-byte(s) are ignored, and (b) the character + * '.' (dot) shall be used instead of "+' (plus).

+ * + *

Used by SASL password file manipulation primitives.

+ * + * @param buffer an arbitrary sequence of bytes to represent in Base-64. + * @return unpadded (without the '=' character(s)) Base-64 representation of + * the input. + */ + public static final String toBase64(byte[] buffer) + { + int len = buffer.length, pos = len % 3; + byte b0 = 0, b1 = 0, b2 = 0; + switch (pos) + { + case 1: + b2 = buffer[0]; + break; + case 2: + b1 = buffer[0]; + b2 = buffer[1]; + break; + } + StringBuffer sb = new StringBuffer(); + int c; + boolean notleading = false; + do + { + c = (b0 & 0xFC) >>> 2; + if (notleading || c != 0) + { + sb.append(BASE64_CHARSET[c]); + notleading = true; + } + c = ((b0 & 0x03) << 4) | ((b1 & 0xF0) >>> 4); + if (notleading || c != 0) + { + sb.append(BASE64_CHARSET[c]); + notleading = true; + } + c = ((b1 & 0x0F) << 2) | ((b2 & 0xC0) >>> 6); + if (notleading || c != 0) + { + sb.append(BASE64_CHARSET[c]); + notleading = true; + } + c = b2 & 0x3F; + if (notleading || c != 0) + { + sb.append(BASE64_CHARSET[c]); + notleading = true; + } + if (pos >= len) + { + break; + } + else + { + try + { + b0 = buffer[pos++]; + b1 = buffer[pos++]; + b2 = buffer[pos++]; + } + catch (ArrayIndexOutOfBoundsException x) + { + break; + } + } + } + while (true); + + if (notleading) + { + return sb.toString(); + } + return "0"; + } + + /** + *

The inverse function of the above.

+ * + *

Converts a string representing the encoding of some bytes in Base-64 + * to their original form.

+ * + * @param str the Base-64 encoded representation of some byte(s). + * @return the bytes represented by the str. + * @throws NumberFormatException if str is null, or + * str contains an illegal Base-64 character. + * @see #toBase64(byte[]) + */ + public static final byte[] fromBase64(String str) + { + int len = str.length(); + if (len == 0) + { + throw new NumberFormatException("Empty string"); + } + byte[] a = new byte[len + 1]; + int i, j; + for (i = 0; i < len; i++) + { + try + { + a[i] = (byte) BASE64_CHARS.indexOf(str.charAt(i)); + } + catch (ArrayIndexOutOfBoundsException x) + { + throw new NumberFormatException("Illegal character at #" + i); + } + } + i = len - 1; + j = len; + try + { + while (true) + { + a[j] = a[i]; + if (--i < 0) + { + break; + } + a[j] |= (a[i] & 0x03) << 6; + j--; + a[j] = (byte) ((a[i] & 0x3C) >>> 2); + if (--i < 0) + { + break; + } + a[j] |= (a[i] & 0x0F) << 4; + j--; + a[j] = (byte) ((a[i] & 0x30) >>> 4); + if (--i < 0) + { + break; + } + a[j] |= (a[i] << 2); + j--; + a[j] = 0; + if (--i < 0) + { + break; + } + } + } + catch (Exception ignored) + { + } + + try + { // ignore leading 0-bytes + while (a[j] == 0) + { + j++; + } + } + catch (Exception x) + { + return new byte[1]; // one 0-byte + } + byte[] result = new byte[len - j + 1]; + System.arraycopy(a, j, result, 0, len - j + 1); + return result; + } + + // BigInteger utilities ---------------------------------------------------- + + /** + *

Treats the input as the MSB representation of a number, and discards + * leading zero elements. For efficiency, the input is simply returned if no + * leading zeroes are found.

+ * + * @param n the {@link BigInteger} to trim. + * @return the byte array representation of the designated {@link BigInteger} + * with no leading 0-bytes. + */ + public static final byte[] trim(BigInteger n) + { + byte[] in = n.toByteArray(); + if (in.length == 0 || in[0] != 0) + { + return in; + } + int len = in.length; + int i = 1; + while (in[i] == 0 && i < len) + { + ++i; + } + byte[] result = new byte[len - i]; + System.arraycopy(in, i, result, 0, len - i); + return result; + } + + /** + *

Returns a hexadecimal dump of the trimmed bytes of a {@link BigInteger}. + *

+ * + * @param x the {@link BigInteger} to display. + * @return the string representation of the designated {@link BigInteger}. + */ + public static final String dump(BigInteger x) + { + return dumpString(trim(x)); + } +} diff --git a/gnu/java/security/x509/X509Certificate.java b/gnu/java/security/x509/X509Certificate.java index 14ac43a25..cf0161701 100644 --- a/gnu/java/security/x509/X509Certificate.java +++ b/gnu/java/security/x509/X509Certificate.java @@ -40,7 +40,6 @@ package gnu.java.security.x509; import gnu.classpath.debug.Component; import gnu.classpath.debug.SystemLogger; - import gnu.java.security.OID; import gnu.java.security.der.BitString; import gnu.java.security.der.DER; @@ -88,8 +87,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; - -import java.util.logging.Level; import java.util.logging.Logger; import javax.security.auth.x500.X500Principal; @@ -661,10 +658,7 @@ public class X509Certificate extends java.security.cert.X509Certificate der.skip(spki.getLength()); logger.log (Component.X509, "read subjectPublicKey == {0}", subjectKey); - if (version > 1) - { - val = der.read(); - } + val = der.read(); if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1) { byte[] b = (byte[]) val.getValue(); diff --git a/gnu/java/security/x509/ext/GeneralNames.java b/gnu/java/security/x509/ext/GeneralNames.java index e92aedaef..dae94cd9f 100644 --- a/gnu/java/security/x509/ext/GeneralNames.java +++ b/gnu/java/security/x509/ext/GeneralNames.java @@ -52,6 +52,8 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import javax.security.auth.x500.X500Principal; + public class GeneralNames { @@ -81,12 +83,14 @@ public class GeneralNames if (!nameList.isConstructed()) throw new IOException("malformed GeneralNames"); int len = 0; + int i = 0; while (len < nameList.getLength()) { DERValue name = der.read(); List namePair = new ArrayList(2); - if (name.getTagClass() != DER.APPLICATION) - throw new IOException("malformed GeneralName"); + int tagClass = name.getTagClass(); + if (tagClass != DER.CONTEXT) + throw new IOException("malformed GeneralName: Tag class is " + tagClass); namePair.add(new Integer(name.getTag())); DERValue val = null; switch (name.getTag()) @@ -99,6 +103,15 @@ public class GeneralNames break; case OTHER_NAME: + // MUST return the encoded bytes of the OID/OctetString sequence + byte[] anotherName = name.getEncoded(); + anotherName[0] = (byte) (DER.CONSTRUCTED|DER.SEQUENCE); + namePair.add(anotherName); + // DERReader goes back on Constructed things so we need to skip over them + DERValue skip = der.read(); // skip OID + skip = der.read(); // skip Octet String + break; + case EDI_PARTY_NAME: namePair.add(name.getValue()); break; @@ -106,7 +119,9 @@ public class GeneralNames case DIRECTORY_NAME: byte[] b = name.getEncoded(); b[0] = (byte) (DER.CONSTRUCTED|DER.SEQUENCE); - namePair.add(new X500DistinguishedName(b).toString()); + DERReader r = new DERReader (b); + r.read (); + namePair.add(new X500Principal(r.read ().getEncoded ()).toString()); break; case IP_ADDRESS: diff --git a/gnu/javax/crypto/DiffieHellmanImpl.java b/gnu/javax/crypto/DiffieHellmanImpl.java deleted file mode 100644 index 4797af7cf..000000000 --- a/gnu/javax/crypto/DiffieHellmanImpl.java +++ /dev/null @@ -1,159 +0,0 @@ -/* DiffieHellmanImpl.java -- implementation of the Diffie-Hellman key agreement. - Copyright (C) 2005 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package gnu.javax.crypto; - -import gnu.java.security.provider.GnuDHPublicKey; - -import java.math.BigInteger; - -import java.security.Key; -import java.security.InvalidKeyException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.KeyAgreementSpi; -import javax.crypto.SecretKey; -import javax.crypto.interfaces.DHPrivateKey; -import javax.crypto.interfaces.DHPublicKey; -import javax.crypto.spec.DHParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -/** - * The Diffie-Hellman key agreement. - * - * @author Casey Marshall (csm@gnu.org) - */ -public final class DiffieHellmanImpl extends KeyAgreementSpi -{ - - /** The private key being used for this agreement. */ - private DHPrivateKey key; - - /** The current result. */ - private BigInteger result; - - /** True if the caller told us we are done. */ - private boolean last_phase_done; - - /** Trivial default constructor. */ - public DiffieHellmanImpl () - { - key = null; - result = null; - last_phase_done = false; - } - - // KeyAgreementSpi methods. - - protected Key engineDoPhase (final Key incoming, final boolean lastPhase) - throws InvalidKeyException - { - if (key == null) - throw new IllegalStateException ("not initialized"); - if (last_phase_done) - throw new IllegalStateException ("last phase already done"); - - if (!(incoming instanceof DHPublicKey)) - throw new InvalidKeyException ("expecting javax.crypto.interfaces.DHPublicKey"); - DHPublicKey pub = (DHPublicKey) incoming; - DHParameterSpec s1 = key.getParams(); - DHParameterSpec s2 = pub.getParams(); - if (!s1.getG().equals (s2.getG()) - || !s1.getP().equals (s2.getP()) - || s1.getL() != s2.getL()) - throw new InvalidKeyException ("supplied key is not compatible"); - - result = pub.getY().modPow (key.getX(), s1.getP()); - if (lastPhase) - { - last_phase_done = true; - return null; - } - - throw new IllegalArgumentException ("only supports two-party Diffie Hellman"); - } - - protected byte[] engineGenerateSecret () - { - if (result == null || !last_phase_done) - throw new IllegalStateException ("not finished"); - - byte[] buf = result.toByteArray (); - if (buf[0] == 0x00) - { - byte[] buf2 = new byte[buf.length - 1]; - System.arraycopy (buf, 1, buf2, 0, buf2.length); - buf = buf2; - } - return buf; - } - - protected int engineGenerateSecret (final byte[] secret, final int offset) - { - byte[] s = engineGenerateSecret(); - System.arraycopy (s, 0, secret, offset, s.length); - return s.length; - } - - protected SecretKey engineGenerateSecret (final String algorithm) - throws InvalidKeyException - { - byte[] s = engineGenerateSecret(); - return new SecretKeySpec (s, algorithm); - } - - protected void engineInit (final Key key, final SecureRandom random) - throws InvalidKeyException - { - if (!(key instanceof DHPrivateKey)) - throw new InvalidKeyException ("not a javax.crypto.interfaces.DHPrivateKey"); - this.key = (DHPrivateKey) key; - result = null; - last_phase_done = false; - } - - protected void engineInit (final Key key, final AlgorithmParameterSpec params, - final SecureRandom random) - throws InvalidKeyException - { - engineInit (key, random); - } -} diff --git a/gnu/javax/crypto/assembly/Assembly.java b/gnu/javax/crypto/assembly/Assembly.java new file mode 100644 index 000000000..56bc5003b --- /dev/null +++ b/gnu/javax/crypto/assembly/Assembly.java @@ -0,0 +1,298 @@ +/* Assembly.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.util.Map; + +/** + *

An Assembly is a construction consisting of a chain of + * {@link Transformer} elements; each wired in pre- or post- transformation + * mode. This chain is terminated by one LoopbackTransformer + * element.

+ * + *

Once constructed, and correctly initialised, the bulk of the methods + * available on the Assembly are delegated to the head + * of the {@link Transformer} chain of the Assembly.

+ * + * @see Transformer + * @version $Revision: 1.1.4.1 $ + */ +public class Assembly +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String DIRECTION = "gnu.crypto.assembly.assembly.direction"; + + /** Flag that tells if the instance is initialised or not; and if yes how. */ + private Direction wired; + + /** The first Transformer in the chain. */ + private Transformer head; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial constructor that sets the chain to a + * LoopbackTransformer. + */ + public Assembly() + { + super(); + + wired = null; + head = new LoopbackTransformer(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * Adds the designated {@link Transformer} and signals that it should operate + * in pre-processing mode; i.e. it should apply its internal transformation + * algorithm on the input data stream, before it passes that stream to + * the next element in the chain. + * + * @param t the {@link Transformer} to add at the head of the current chain. + * @throws IllegalArgumentException if the designated {@link Transformer} + * has a non-null tail; i.e. it is already an element of a chain. + */ + public void addPreTransformer(Transformer t) + { + wireTransformer(t, Operation.PRE_PROCESSING); + } + + /** + * Adds the designated {@link Transformer} and signals that it should operate + * in post-processing mode; i.e. it should apply its internal transformation + * algorithm on the input data stream, after it passes that stream to + * the next element in the chain. + * + * @param t the {@link Transformer} to add at the head of the current chain. + * @throws IllegalArgumentException if the designated {@link Transformer} + * has a non-null tail; i.e. it is already an element of a chain. + */ + public void addPostTransformer(Transformer t) + { + wireTransformer(t, Operation.POST_PROCESSING); + } + + /** + * Initialises the Assembly for operation with specific + * characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the instance is already initialised. + */ + public void init(Map attributes) throws TransformerException + { + if (wired != null) + { + throw new IllegalStateException(); + } + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + { + flow = Direction.FORWARD; + } + attributes.put(Transformer.DIRECTION, flow); + head.init(attributes); + wired = flow; + } + + /** + * Resets the Assembly for re-initialisation and use with other + * characteristics. This method always succeeds. + */ + public void reset() + { + head.reset(); + wired = null; + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length 1 whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte b) throws TransformerException + { + return update(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the method with same name and three + * arguments. All bytes in in, starting from index position + * 0 are considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte[] in) throws TransformerException + { + return update(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array. + * + * @param in the input data bytes. + * @param offset index of in from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] update(byte[] in, int offset, int length) + throws TransformerException + { + if (wired == null) + { + throw new IllegalStateException(); + } + return head.update(in, offset, length); + } + + /** + * Convenience method that calls the method with same name and three + * arguments using a 0-long byte array. + * + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate() throws TransformerException + { + return lastUpdate(new byte[0], 0, 0); + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length 1 whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte b) throws TransformerException + { + return lastUpdate(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the method with same name and three + * arguments. All bytes in in, starting from index position + * 0 are considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte[] in) throws TransformerException + { + return lastUpdate(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array and + * signals, at the same time, that this is the last push operation for + * this Assembly. + * + * @param in the input data bytes. + * @param offset index of in from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception + * occurs during the operation. + */ + public byte[] lastUpdate(byte[] in, int offset, int length) + throws TransformerException + { + if (wired == null) + { + throw new IllegalStateException(); + } + byte[] result = head.lastUpdate(in, offset, length); + reset(); + return result; + } + + // helper methods ---------------------------------------------------------- + + private void wireTransformer(Transformer t, Operation mode) + { + if (t.tail != null) + { + throw new IllegalArgumentException(); + } + t.setMode(mode); + t.tail = head; + head = t; + } +} diff --git a/gnu/javax/crypto/assembly/Cascade.java b/gnu/javax/crypto/assembly/Cascade.java new file mode 100644 index 000000000..313532d2e --- /dev/null +++ b/gnu/javax/crypto/assembly/Cascade.java @@ -0,0 +1,405 @@ +/* Cascade.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +/** + *

A Cascade Cipher is the concatenation of two or more block ciphers + * each with independent keys. Plaintext is input to the first stage; the output + * of stage i is input to stage i + 1; and the output + * of the last stage is the Cascade's ciphertext output.

+ * + *

In the simplest case, all stages in a Cascade have k-bit + * keys, and the stage inputs and outputs are all n-bit quantities. The stage + * ciphers may differ (general cascade of ciphers), or all be identical (cascade + * of identical ciphers).

+ * + *

The term "block ciphers" used above refers to implementations of + * {@link gnu.crypto.mode.IMode}, including the {@link gnu.crypto.mode.ECB} + * mode which basically exposes a symmetric-key block cipher algorithm as a + * Mode of Operations.

+ * + *

References:

+ * + *
    + *
  1. [HAC]: Handbook of + * Applied Cryptography.
    + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997
    + * Menezes, A., van Oorschot, P. and S. Vanstone.
  2. + *
+ * + * @version $Revision: 1.1.4.1 $ + */ +public class Cascade +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String DIRECTION = "gnu.crypto.assembly.cascade.direction"; + + /** The map of Stages chained in this cascade. */ + protected HashMap stages; + + /** The ordered list of Stage UIDs to their attribute maps. */ + protected LinkedList stageKeys; + + /** The current operational direction of this instance. */ + protected Direction wired; + + /** The curently set block-size for this instance. */ + protected int blockSize; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Cascade() + { + super(); + + stages = new HashMap(3); + stageKeys = new LinkedList(); + wired = null; + blockSize = 0; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * Returns the Least Common Multiple of two integers. + * + * @param a the first integer. + * @param b the second integer. + * @return the LCM of abs(a) and abs(b). + */ + private static final int lcm(int a, int b) + { + BigInteger A = BigInteger.valueOf(a * 1L); + BigInteger B = BigInteger.valueOf(b * 1L); + return A.multiply(B).divide(A.gcd(B)).abs().intValue(); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * Adds to the end of the current chain, a designated {@link Stage}. + * + * @param stage the {@link Stage} to append to the chain. + * @return a unique identifier for this stage, within this cascade. + * @throws IllegalStateException if the instance is already initialised. + * @throws IllegalArgumentException if the designated stage is already in + * the chain, or it has incompatible characteristics with the current + * elements already in the chain. + */ + public Object append(Stage stage) throws IllegalArgumentException + { + return insert(size(), stage); + } + + /** + * Adds to the begining of the current chain, a designated {@link Stage}. + * + * @param stage the {@link Stage} to prepend to the chain. + * @return a unique identifier for this stage, within this cascade. + * @throws IllegalStateException if the instance is already initialised. + * @throws IllegalArgumentException if the designated stage is already in + * the chain, or it has incompatible characteristics with the current + * elements already in the chain. + */ + public Object prepend(Stage stage) throws IllegalArgumentException + { + return insert(0, stage); + } + + /** + * Inserts a {@link Stage} into the current chain, at the specified index + * (zero-based) position. + * + * @param stage the {@link Stage} to insert into the chain. + * @return a unique identifier for this stage, within this cascade. + * @throws IllegalArgumentException if the designated stage is already in + * the chain, or it has incompatible characteristics with the current + * elements already in the chain. + * @throws IllegalStateException if the instance is already initialised. + * @throws IndexOutOfBoundsException if index is less than + * 0 or greater than the current size of this cascade. + */ + public Object insert(int index, Stage stage) throws IllegalArgumentException, + IndexOutOfBoundsException + { + if (stages.containsValue(stage)) + { + throw new IllegalArgumentException(); + } + if (wired != null || stage == null) + { + throw new IllegalStateException(); + } + + if (index < 0 || index > size()) + { + throw new IndexOutOfBoundsException(); + } + + // check that there is a non-empty set of common block-sizes + Set set = stage.blockSizes(); + if (stages.isEmpty()) + { + if (set.isEmpty()) + { + throw new IllegalArgumentException("1st stage with no block sizes"); + } + } + else + { + Set common = this.blockSizes(); + common.retainAll(set); + if (common.isEmpty()) + { + throw new IllegalArgumentException("no common block sizes found"); + } + } + + Object result = new Object(); + stageKeys.add(index, result); + stages.put(result, stage); + + return result; + } + + /** + * Returns the current number of stages in this chain. + * + * @return the current count of stages in this chain. + */ + public int size() + { + return stages.size(); + } + + /** + * Returns an {@link Iterator} over the stages contained in this instance. + * Each element of this iterator is a concrete implementation of a {@link + * Stage}. + * + * @return an {@link Iterator} over the stages contained in this instance. + * Each element of the returned iterator is a concrete instance of a {@link + * Stage}. + */ + public Iterator stages() + { + LinkedList result = new LinkedList(); + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + result.addLast(stages.get(it.next())); + } + return result.listIterator(); + } + + /** + * Returns the {@link Set} of supported block sizes for this + * Cascade that are common to all of its chained stages. Each + * element in the returned {@link Set} is an instance of {@link Integer}. + * + * @return a {@link Set} of supported block sizes common to all the stages + * of the chain. + */ + public Set blockSizes() + { + HashSet result = null; + for (Iterator it = stages.values().iterator(); it.hasNext();) + { + Stage aStage = (Stage) it.next(); + if (result == null) + { // first time + result = new HashSet(aStage.blockSizes()); + } + else + { + result.retainAll(aStage.blockSizes()); + } + } + return result == null ? Collections.EMPTY_SET : result; + } + + /** + * Initialises the chain for operation with specific characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the chain, or any of its stages, is + * already initialised. + * @throws InvalidKeyException if the intialisation data provided with the + * stage is incorrect or causes an invalid key to be generated. + * @see Direction#FORWARD + * @see Direction#REVERSED + */ + public void init(Map attributes) throws InvalidKeyException + { + if (wired != null) + { + throw new IllegalStateException(); + } + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + { + flow = Direction.FORWARD; + } + + int optimalSize = 0; + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + Object id = it.next(); + Map attr = (Map) attributes.get(id); + attr.put(Stage.DIRECTION, flow); + Stage stage = (Stage) stages.get(id); + stage.init(attr); + optimalSize = optimalSize == 0 ? stage.currentBlockSize() + : lcm(optimalSize, + stage.currentBlockSize()); + } + + if (flow == Direction.REVERSED) + { // reverse order + Collections.reverse(stageKeys); + } + wired = flow; + blockSize = optimalSize; + } + + /** + * Returns the currently set block size for the chain. + * + * @return the current block size for the chain. + * @throws IllegalStateException if the instance is not initialised. + */ + public int currentBlockSize() + { + if (wired == null) + { + throw new IllegalStateException(); + } + return blockSize; + } + + /** + * Resets the chain for re-initialisation and use with other characteristics. + * This method always succeeds. + */ + public void reset() + { + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + ((Stage) stages.get(it.next())).reset(); + } + if (wired == Direction.REVERSED) + { // reverse it back + Collections.reverse(stageKeys); + } + wired = null; + blockSize = 0; + } + + /** + * Processes exactly one block of plaintext (if initialised in the + * {@link Direction#FORWARD} state) or ciphertext (if initialised in the + * {@link Direction#REVERSED} state). + * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @throws IllegalStateException if the instance is not initialised. + */ + public void update(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (wired == null) + { + throw new IllegalStateException(); + } + int stageBlockSize, j, i = stages.size(); + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + Stage stage = (Stage) stages.get(it.next()); + stageBlockSize = stage.currentBlockSize(); + for (j = 0; j < blockSize; j += stageBlockSize) + { + stage.update(in, inOffset + j, out, outOffset + j); + } + i--; + if (i > 0) + { + System.arraycopy(out, outOffset, in, inOffset, blockSize); + } + } + } + + /** + * Conducts a simple correctness test that consists of basic symmetric + * encryption / decryption test(s) for all supported block and key sizes of + * underlying block cipher(s) wrapped by Mode leafs. The test also includes + * one (1) variable key Known Answer Test (KAT) for each block cipher. + * + * @return true if the implementation passes simple + * correctness tests. Returns false otherwise. + */ + public boolean selfTest() + { + for (Iterator it = stageKeys.listIterator(); it.hasNext();) + { + if (!((Stage) stages.get(it.next())).selfTest()) + { + return false; + } + } + return true; + } +} diff --git a/gnu/javax/crypto/assembly/CascadeStage.java b/gnu/javax/crypto/assembly/CascadeStage.java new file mode 100644 index 000000000..ba1123713 --- /dev/null +++ b/gnu/javax/crypto/assembly/CascadeStage.java @@ -0,0 +1,109 @@ +/* CascadeStage.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +/** + *

A Cascade Stage in a Cascade Cipher.

+ * + * @version $Revision: 1.1.4.1 $ + */ +class CascadeStage extends Stage +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private Cascade delegate; + + // Constructor(s) + // ------------------------------------------------------------------------- + + CascadeStage(Cascade cascade, Direction forwardDirection) + { + super(forwardDirection); + + this.delegate = cascade; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public Set blockSizes() + { + return Collections.unmodifiableSet(delegate.blockSizes()); + } + + void initDelegate(Map attributes) throws InvalidKeyException + { + Direction flow = (Direction) attributes.get(DIRECTION); + attributes.put(DIRECTION, flow.equals(forward) ? forward + : Direction.reverse(forward)); + // delegate.init(flow.equals(forward) ? forward : backward); + // delegate.init(flow.equals(forward) ? forward : Direction.reverse(forward)); + delegate.init(attributes); + } + + public int currentBlockSize() throws IllegalStateException + { + return delegate.currentBlockSize(); + } + + void resetDelegate() + { + delegate.reset(); + } + + void updateDelegate(byte[] in, int inOffset, byte[] out, int outOffset) + { + delegate.update(in, inOffset, out, outOffset); + } + + public boolean selfTest() + { + return delegate.selfTest(); + } +} diff --git a/gnu/javax/crypto/assembly/CascadeTransformer.java b/gnu/javax/crypto/assembly/CascadeTransformer.java new file mode 100644 index 000000000..828bda343 --- /dev/null +++ b/gnu/javax/crypto/assembly/CascadeTransformer.java @@ -0,0 +1,139 @@ +/* CascadeTransformer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.security.InvalidKeyException; +import java.util.Map; + +/** + * An Adapter to use any {@link Cascade} as a {@link Transformer} in an + * {@link Assembly}. + * + * @version $Revision: 1.1.4.1 $ + */ +class CascadeTransformer extends Transformer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private Cascade delegate; + + private int blockSize; + + // Constructor(s) + // ------------------------------------------------------------------------- + + CascadeTransformer(Cascade delegate) + { + super(); + + this.delegate = delegate; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instant methods + // ------------------------------------------------------------------------- + + void initDelegate(Map attributes) throws TransformerException + { + attributes.put(Cascade.DIRECTION, wired); + try + { + delegate.init(attributes); + } + catch (InvalidKeyException x) + { + throw new TransformerException("initDelegate()", x); + } + blockSize = delegate.currentBlockSize(); + } + + int delegateBlockSize() + { + return blockSize; + } + + void resetDelegate() + { + delegate.reset(); + blockSize = 0; + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result = updateInternal(in, offset, length); + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + if (inBuffer.size() != 0) + { + throw new TransformerException( + "lastUpdateDelegate()", + new IllegalStateException( + "Cascade transformer, after last " + + "update, must be empty but isn't")); + } + return new byte[0]; + } + + private byte[] updateInternal(byte[] in, int offset, int length) + { + byte[] result; + for (int i = 0; i < length; i++) + { + inBuffer.write(in[offset++] & 0xFF); + if (inBuffer.size() >= blockSize) + { + result = inBuffer.toByteArray(); + inBuffer.reset(); + delegate.update(result, 0, result, 0); + outBuffer.write(result, 0, blockSize); + } + } + result = outBuffer.toByteArray(); + outBuffer.reset(); + return result; + } +} diff --git a/gnu/javax/crypto/assembly/DeflateTransformer.java b/gnu/javax/crypto/assembly/DeflateTransformer.java new file mode 100644 index 000000000..35328a6c1 --- /dev/null +++ b/gnu/javax/crypto/assembly/DeflateTransformer.java @@ -0,0 +1,233 @@ +/* DeflateTransformer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.util.Map; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +/** + *

A {@link Transformer} Adapter allowing inclusion of a DEFLATE compression + * algorithm in an {@link Assembly} chain. The {@link Direction#FORWARD} + * transformation is a compression (deflate) of input data, while the + * {@link Direction#REVERSED} one is a decompression (inflate) that restores + * the original data.

+ * + *

This {@link Transformer} uses a {@link Deflater} instance to carry on the + * compression, and an {@link Inflater} to do the decompression.

+ * + *

When using such a {@link Transformer}, in an {@link Assembly}, there must + * be at least one element behind this instance in the constructed chain; + * otherwise, a {@link TransformerException} is thrown at initialisation time.

+ * + * @version Revision: $ + */ +class DeflateTransformer extends Transformer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private Deflater compressor; + + private Inflater decompressor; + + private int outputBlockSize = 512; // default zlib buffer size + + private byte[] zlibBuffer; + + // Constructor(s) + // ------------------------------------------------------------------------- + + DeflateTransformer() + { + super(); + + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + void initDelegate(Map attributes) throws TransformerException + { + if (tail == null) + { + throw new TransformerException( + "initDelegate()", + new IllegalStateException( + "Compression transformer missing its tail!")); + } + outputBlockSize = tail.currentBlockSize(); + zlibBuffer = new byte[outputBlockSize]; + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == Direction.FORWARD) + { + compressor = new Deflater(); + } + else + { + decompressor = new Inflater(); + } + } + + int delegateBlockSize() + { + // return outputBlockSize; + return 1; + } + + void resetDelegate() + { + compressor = null; + decompressor = null; + outputBlockSize = 1; + zlibBuffer = null; + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result; + if (wired == Direction.FORWARD) + { + compressor.setInput(in, offset, length); + while (!compressor.needsInput()) + { + compress(); + } + } + else + { // decompression: inflate first and then update tail + decompress(in, offset, length); + } + + result = inBuffer.toByteArray(); + inBuffer.reset(); + return result; + } + + // byte[] lastUpdateDelegate(byte[] in, int offset, int length) + // throws TransformerException { + // // process multiples of blocksize as much as possible + // byte[] result = this.updateDelegate(in, offset, length); + // inBuffer.write(result, 0, result.length); + // if (wired == Direction.FORWARD) { // compressing + // if (!compressor.finished()) { + // compressor.finish(); + // while (!compressor.finished()) { + // compress(); + // } + // } + // } else { // decompressing + // if (!decompressor.finished()) { + // throw new TransformerException("lastUpdateDelegate()", + // new IllegalStateException("Compression transformer, after last " + // +"update, must be finished but isn't")); + // } + // } + // + // result = inBuffer.toByteArray(); + // inBuffer.reset(); + // return result; + // } + byte[] lastUpdateDelegate() throws TransformerException + { + // process multiples of blocksize as much as possible + if (wired == Direction.FORWARD) + { // compressing + if (!compressor.finished()) + { + compressor.finish(); + while (!compressor.finished()) + { + compress(); + } + } + } + else + { // decompressing + if (!decompressor.finished()) + { + throw new TransformerException( + "lastUpdateDelegate()", + new IllegalStateException( + "Compression transformer, after last " + + "update, must be finished but isn't")); + } + } + byte[] result = inBuffer.toByteArray(); + inBuffer.reset(); + return result; + } + + private void compress() + { + int len = compressor.deflate(zlibBuffer); + if (len > 0) + { + inBuffer.write(zlibBuffer, 0, len); + } + } + + private void decompress(byte[] in, int offset, int length) + throws TransformerException + { + decompressor.setInput(in, offset, length); + int len = 1; + while (len > 0) + { + try + { + len = decompressor.inflate(zlibBuffer); + } + catch (DataFormatException x) + { + throw new TransformerException("decompress()", x); + } + if (len > 0) + { + inBuffer.write(zlibBuffer, 0, len); + } + } + } +} diff --git a/gnu/javax/crypto/assembly/Direction.java b/gnu/javax/crypto/assembly/Direction.java new file mode 100644 index 000000000..eea026d3e --- /dev/null +++ b/gnu/javax/crypto/assembly/Direction.java @@ -0,0 +1,92 @@ +/* Direction.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +/** + *

An enumeration type for wiring {@link Stage} instances into {@link + * Cascade} Cipher chains, as well as for operating a {@link Cascade} in a + * given direction.

+ * + *

The possible values for this type are two:

+ *
    + *
  1. FORWARD: equivalent to {@link gnu.crypto.mode.IMode#ENCRYPTION}, and + * its inverse value
  2. + *
  3. REVERSED: equivalent to {@link gnu.crypto.mode.IMode#DECRYPTION}.
  4. + *
+ * + * @version $Revision: 1.1.4.1 $ + */ +public final class Direction +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final Direction FORWARD = new Direction(1); + + public static final Direction REVERSED = new Direction(2); + + private int value; + + // Constructor(s) + // ------------------------------------------------------------------------- + + private Direction(int value) + { + super(); + + this.value = value; + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final Direction reverse(Direction d) + { + return (d.equals(FORWARD) ? REVERSED : FORWARD); + } + + // Instance methods + // ------------------------------------------------------------------------- + + public String toString() + { + return (this == FORWARD ? "forward" : "reversed"); + } +} diff --git a/gnu/javax/crypto/assembly/LoopbackTransformer.java b/gnu/javax/crypto/assembly/LoopbackTransformer.java new file mode 100644 index 000000000..546b5f86f --- /dev/null +++ b/gnu/javax/crypto/assembly/LoopbackTransformer.java @@ -0,0 +1,116 @@ +/* LoopbackTransformer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.util.Map; + +/** + * A trivial {@link Transformer} to allow closing a chain in an {@link Assembly}. + * This class is not visible outside this package. + * + * @version $Revision: 1.1.4.1 $ + */ +final class LoopbackTransformer extends Transformer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial protected constructor. */ + LoopbackTransformer() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public void init(Map attributes) throws TransformerException + { + } + + public void reset() + { + } + + public byte[] update(byte[] in, int offset, int length) + throws TransformerException + { + return updateDelegate(in, offset, length); + } + + public byte[] lastUpdate() throws TransformerException + { + return lastUpdateDelegate(); + } + + // abstract methods to be implemented by concrete subclasses --------------- + + void initDelegate(Map attributes) throws TransformerException + { + } + + int delegateBlockSize() + { + return 1; + } + + void resetDelegate() + { + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result = new byte[length]; + System.arraycopy(in, offset, result, 0, length); + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + return new byte[0]; + } +} diff --git a/gnu/javax/crypto/assembly/ModeStage.java b/gnu/javax/crypto/assembly/ModeStage.java new file mode 100644 index 000000000..09029a8d8 --- /dev/null +++ b/gnu/javax/crypto/assembly/ModeStage.java @@ -0,0 +1,129 @@ +/* ModeStage.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import gnu.javax.crypto.mode.IMode; + +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + *

An {@link IMode} {@link Stage} in a {@link Cascade} Cipher chain.

+ * + *

Such a stage wraps an implementation of a Block Cipher Mode of Operation + * ({@link IMode}) to allow inclusion of such an instance in a cascade of block + * ciphers.

+ * + * @version $Revision: 1.1.4.1 $ + */ +class ModeStage extends Stage +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private IMode delegate; + + private transient Set cachedBlockSizes; + + // Constructor(s) + // ------------------------------------------------------------------------- + + ModeStage(IMode mode, Direction forwardDirection) + { + super(forwardDirection); + + delegate = mode; + cachedBlockSizes = null; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public Set blockSizes() + { + if (cachedBlockSizes == null) + { + HashSet result = new HashSet(); + for (Iterator it = delegate.blockSizes(); it.hasNext();) + { + result.add(it.next()); + } + cachedBlockSizes = Collections.unmodifiableSet(result); + } + return cachedBlockSizes; + } + + void initDelegate(Map attributes) throws InvalidKeyException + { + Direction flow = (Direction) attributes.get(DIRECTION); + attributes.put(IMode.STATE, + new Integer(flow.equals(forward) ? IMode.ENCRYPTION + : IMode.DECRYPTION)); + + delegate.init(attributes); + } + + public int currentBlockSize() throws IllegalStateException + { + return delegate.currentBlockSize(); + } + + void resetDelegate() + { + delegate.reset(); + } + + void updateDelegate(byte[] in, int inOffset, byte[] out, int outOffset) + { + delegate.update(in, inOffset, out, outOffset); + } + + public boolean selfTest() + { + return delegate.selfTest(); + } +} diff --git a/gnu/javax/crypto/assembly/Operation.java b/gnu/javax/crypto/assembly/Operation.java new file mode 100644 index 000000000..209a9786e --- /dev/null +++ b/gnu/javax/crypto/assembly/Operation.java @@ -0,0 +1,89 @@ +/* Operation.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +/** + *

An enumeration type for specifying the operation type of a + * {@link Transformer}.

+ * + *

The possible values for this type are two:

+ *
    + *
  1. PRE_PROCESSING: where the input data is first processed by the + * current {@link Transformer} before being passed to the rest of the chain; + * and
  2. + *
  3. POST_PROCESSING: where the input data is first passed to the rest of + * the chain, and the resulting bytes are then processed by the current + * {@link Transformer}.
  4. + *
+ * + * @version $Revision: 1.1.4.1 $ + */ +public final class Operation +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final Operation PRE_PROCESSING = new Operation(1); + + public static final Operation POST_PROCESSING = new Operation(2); + + private int value; + + // Constructor(s) + // ------------------------------------------------------------------------- + + private Operation(int value) + { + super(); + + this.value = value; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public String toString() + { + return (this == PRE_PROCESSING ? "pre-processing" : "post-processing"); + } +} diff --git a/gnu/javax/crypto/assembly/PaddingTransformer.java b/gnu/javax/crypto/assembly/PaddingTransformer.java new file mode 100644 index 000000000..5ac27548d --- /dev/null +++ b/gnu/javax/crypto/assembly/PaddingTransformer.java @@ -0,0 +1,178 @@ +/* PaddingTransformer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.WrongPaddingException; + +import java.util.Map; + +/** + *

An Adapter to use any {@link IPad} as a {@link Transformer} in an + * {@link Assembly}.

+ * + *

When using such a {@link Transformer}, in an {@link Assembly}, there must + * be at least one element behind this instance in the constructed chain; + * otherwise, a {@link TransformerException} is thrown at initialisation time.

+ * + * @version $Revision: 1.1.4.1 $ + */ +class PaddingTransformer extends Transformer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private IPad delegate; + + private int outputBlockSize = 1; + + // Constructor(s) + // ------------------------------------------------------------------------- + + PaddingTransformer(IPad padding) + { + super(); + + this.delegate = padding; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + void initDelegate(Map attributes) throws TransformerException + { + if (tail == null) + { + throw new TransformerException( + "initDelegate()", + new IllegalStateException( + "Padding transformer missing its tail!")); + } + outputBlockSize = tail.currentBlockSize(); + delegate.init(outputBlockSize); + } + + int delegateBlockSize() + { + return outputBlockSize; + } + + void resetDelegate() + { + delegate.reset(); + outputBlockSize = 1; + } + + byte[] updateDelegate(byte[] in, int offset, int length) + throws TransformerException + { + inBuffer.write(in, offset, length); + byte[] tmp = inBuffer.toByteArray(); + inBuffer.reset(); + byte[] result; + if (wired == Direction.FORWARD) + { // padding + // buffers remaining bytes from (inBuffer + in) that are less than 1 block + if (tmp.length < outputBlockSize) + { + inBuffer.write(tmp, 0, tmp.length); + result = new byte[0]; + } + else + { + int newlen = outputBlockSize * (tmp.length / outputBlockSize); + inBuffer.write(tmp, newlen, tmp.length - newlen); + result = new byte[newlen]; + System.arraycopy(tmp, 0, result, 0, newlen); + } + } + else + { // unpadding + // always keep in own buffer a max of 1 block to cater for lastUpdate + if (tmp.length < outputBlockSize) + { + inBuffer.write(tmp, 0, tmp.length); + result = new byte[0]; + } + else + { + result = new byte[tmp.length - outputBlockSize]; + System.arraycopy(tmp, 0, result, 0, result.length); + inBuffer.write(tmp, result.length, outputBlockSize); + } + } + return result; + } + + byte[] lastUpdateDelegate() throws TransformerException + { + byte[] result; + // process multiples of blocksize as much as possible + // catenate result from processing inBuffer with last-update( tail ) + if (wired == Direction.FORWARD) + { // padding + result = inBuffer.toByteArray(); + byte[] padding = delegate.pad(result, 0, result.length); + inBuffer.write(padding, 0, padding.length); + } + else + { // unpadding + byte[] tmp = inBuffer.toByteArray(); + inBuffer.reset(); + int realLength; + try + { + realLength = tmp.length; // should be outputBlockSize + realLength -= delegate.unpad(tmp, 0, tmp.length); + } + catch (WrongPaddingException x) + { + throw new TransformerException("lastUpdateDelegate()", x); + } + inBuffer.write(tmp, 0, realLength); + } + result = inBuffer.toByteArray(); + inBuffer.reset(); + return result; + } +} diff --git a/gnu/javax/crypto/assembly/Stage.java b/gnu/javax/crypto/assembly/Stage.java new file mode 100644 index 000000000..41fbb4f88 --- /dev/null +++ b/gnu/javax/crypto/assembly/Stage.java @@ -0,0 +1,218 @@ +/* Stage.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import gnu.javax.crypto.mode.IMode; + +import java.security.InvalidKeyException; +import java.util.Map; +import java.util.Set; + +/** + *

A Stage in a Cascade Cipher.

+ * + *

Each stage may be either an implementation of a Block Cipher Mode of + * Operation ({@link IMode}) or another Cascade Cipher ({@link Cascade}). Each + * stage has also a natural operational direction when constructed for + * inclusion within a {@link Cascade}. This natural direction dictates + * how data flows from one stage into another when stages are chained together + * in a cascade. One can think of a stage and its natural direction as the + * specification of how to wire the stage into the chain. The following diagrams + * may help understand the paradigme. The first shows two stages chained each + * with a {@link Direction#FORWARD} direction.

+ *
+ *           FORWARD         FORWARD
+ *       +------+       +-------+
+ *       |      |       |       |
+ *       |  +--in --+   |   +--in --+
+ *    ---+  | Stage |   |   | Stage |  +---
+ *          +--out--+   |   +--out--+  |
+ *              |       |       |      |
+ *              +-------+       +------+
+ * 
+ *

The second diagram shows two stages, one in a {@link Direction#FORWARD} + * direction, while the other is wired in a {@link Direction#REVERSED} + * direction.

+ *
+ *           FORWARD         REVERSED
+ *       +------+               +------+
+ *       |      |               |      |
+ *       |  +--in --+       +--in --+  |
+ *    ---+  | Stage |       | Stage |  +---
+ *          +--out--+       +--out--+
+ *              |               |
+ *              +---------------+
+ * 
+ * + * @see ModeStage + * @see CascadeStage + * @version $Revision: 1.1.4.1 $ + */ +public abstract class Stage +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String DIRECTION = "gnu.crypto.assembly.stage.direction"; + + protected Direction forward; + + protected Direction wired; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected Stage(Direction forwardDirection) + { + super(); + + this.forward = forwardDirection; + this.wired = null; + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final Stage getInstance(IMode mode, Direction forwardDirection) + { + return new ModeStage(mode, forwardDirection); + } + + public static final Stage getInstance(Cascade cascade, + Direction forwardDirection) + { + return new CascadeStage(cascade, forwardDirection); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * Returns the {@link Set} of supported block sizes for this + * Stage. Each element in the returned {@link Set} is an + * instance of {@link Integer}. + * + * @return a {@link Set} of supported block sizes. + */ + public abstract Set blockSizes(); + + /** + * Initialises the stage for operation with specific characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the instance is already initialised. + * @throws InvalidKeyException if the key data is invalid. + */ + public void init(Map attributes) throws InvalidKeyException + { + if (wired != null) + { + throw new IllegalStateException(); + } + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + { + flow = Direction.FORWARD; + attributes.put(DIRECTION, flow); + } + initDelegate(attributes); + wired = flow; + } + + /** + * Returns the currently set block size for the stage. + * + * @return the current block size for this stage. + * @throws IllegalStateException if the instance is not initialised. + */ + public abstract int currentBlockSize() throws IllegalStateException; + + /** + * Resets the stage for re-initialisation and use with other characteristics. + * This method always succeeds. + */ + public void reset() + { + resetDelegate(); + wired = null; + } + + /** + * Processes exactly one block of plaintext (if initialised in the + * {@link Direction#FORWARD} state) or ciphertext (if initialised in + * the {@link Direction#REVERSED} state). + * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @throws IllegalStateException if the instance is not initialised. + */ + public void update(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (wired == null) + { + throw new IllegalStateException(); + } + updateDelegate(in, inOffset, out, outOffset); + } + + /** + * Conducts a simple correctness test that consists of basic symmetric + * encryption / decryption test(s) for all supported block and key sizes of + * underlying block cipher(s) wrapped by Mode leafs. The test also includes + * one (1) variable key Known Answer Test (KAT) for each block cipher. + * + * @return true if the implementation passes simple + * correctness tests. Returns false otherwise. + */ + public abstract boolean selfTest(); + + // abstract methods to be implemented by concrete subclasses --------------- + + abstract void initDelegate(Map attributes) throws InvalidKeyException; + + abstract void resetDelegate(); + + abstract void updateDelegate(byte[] in, int inOffset, byte[] out, + int outOffset); +} diff --git a/gnu/javax/crypto/assembly/Transformer.java b/gnu/javax/crypto/assembly/Transformer.java new file mode 100644 index 000000000..3e8bced31 --- /dev/null +++ b/gnu/javax/crypto/assembly/Transformer.java @@ -0,0 +1,460 @@ +/* Transformer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import gnu.javax.crypto.pad.IPad; + +import java.io.ByteArrayOutputStream; +import java.util.Map; + +/** + *

A Transformer is an abstract representation of a two-way + * transformation that can be chained together with other instances of + * this type. Examples of such transformations in this library are: + * {@link Cascade} cipher, {@link gnu.crypto.pad.IPad} algorithm, and a + * ZLib-based deflater/inflater algorithm. A special implementation of a + * Transformer to close a chain is also provided.

+ * + *

A Transformer is characterised by the followings:

+ *

    + *
  • It can be chained to other instances, to form an {@link Assembly}.
  • + *
  • When configured in an {@link Assembly}, it can be set to apply its + * internal transformation on the input data stream before (pre-processing) + * or after (post-processing) passing the input data to the next element in + * the chain. Note that the same type Transformer can be used as + * either in pre-processing or a post-processing modes.
  • + *
  • A special transformer --LoopbackTransformer-- is used to + * close the chain.
  • + *
  • A useful type of Transformer --one we're interested in-- + * has internal buffers. The distinction between a casual push (update) + * operation and the last one allows to correctly flush any intermediate + * bytes that may exist in those buffers.
  • + *
+ * + *

To allow wiring Transformer instances together, a + * minimal-output-size in bytes is necessary. The trivial case of a + * value of 1 for such attribute practically means that no output + * buffering, from the previous element, is needed --which is independant of + * buffering the input if the Transformer implementation itself is + * block-based.

+ * + * @see CascadeTransformer + * @see PaddingTransformer + * @see DeflateTransformer + * @version $Revision: 1.1.4.1 $ + */ +public abstract class Transformer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String DIRECTION = "gnu.crypto.assembly.transformer.direction"; + + // public static final String MODE = "gnu.crypto.assembly.transformer.mode"; + + protected Direction wired; + + protected Operation mode; + + protected Transformer tail = null; + + protected ByteArrayOutputStream inBuffer = new ByteArrayOutputStream(2048); + + protected ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(2048); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial protected constructor. */ + protected Transformer() + { + super(); + + this.wired = null; + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final Transformer getCascadeTransformer(Cascade cascade) + { + return new CascadeTransformer(cascade); + } + + public static final Transformer getPaddingTransformer(IPad padding) + { + return new PaddingTransformer(padding); + } + + public static final Transformer getDeflateTransformer() + { + return new DeflateTransformer(); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * Sets the operational mode of this Transformer. + * + * @param mode the processing mode this Transformer is required + * to operate in. + * @throws IllegalStateException if this instance has already been assigned + * an operational mode. + */ + public void setMode(final Operation mode) + { + if (this.mode != null) + { + throw new IllegalStateException(); + } + this.mode = mode; + } + + /** + * Returns true if this Transformer was wired in + * pre-processing mode; false otherwise. + * + * @return true if this Transformer has been wired + * in pre-processing mode; false otherwise. + * @throws IllegalStateException if this instance has not yet been assigned + * an operational type. + */ + public boolean isPreProcessing() + { + if (mode == null) + { + throw new IllegalStateException(); + } + return (mode == Operation.PRE_PROCESSING); + } + + /** + * Returns true if this Transformer was wired in + * post-processing mode; false otherwise. + * + * @return true if this Transformer has been wired + * in post-processing mode; false otherwise. + * @throws IllegalStateException if this instance has not yet been assigned + * an operational type. + */ + public boolean isPostProcessing() + { + return !isPreProcessing(); + } + + /** + * Initialises the Transformer for operation with specific + * characteristics. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalStateException if the instance is already initialised. + */ + public void init(Map attributes) throws TransformerException + { + if (wired != null) + { + throw new IllegalStateException(); + } + Direction flow = (Direction) attributes.get(DIRECTION); + if (flow == null) + { + flow = Direction.FORWARD; + } + wired = flow; + inBuffer.reset(); + outBuffer.reset(); + + tail.init(attributes); // initialise tail first + initDelegate(attributes); // initialise this instance + } + + /** + * Returns the block-size of this Transformer. A value of + * 1 indicates that this instance is block-agnostic. + * + * @return the current minimal required block size. + */ + public int currentBlockSize() + { + if (wired == null) + { + throw new IllegalStateException(); + } + return delegateBlockSize(); + } + + /** + * Resets the Transformer for re-initialisation and use with + * other characteristics. This method always succeeds. + */ + public void reset() + { + resetDelegate(); + wired = null; + inBuffer.reset(); + outBuffer.reset(); + tail.reset(); // reset tail last + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length 1 whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte b) throws TransformerException + { + return update(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the same method with three arguments. All + * bytes in in, starting from index position 0 are + * considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #update(byte[], int, int) + */ + public byte[] update(byte[] in) throws TransformerException + { + return update(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array. + * + * @param in the input data bytes. + * @param offset index of in from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] update(byte[] in, int offset, int length) + throws TransformerException + { + if (wired == null) + { + throw new IllegalStateException(); + } + byte[] result = (wired == Direction.FORWARD ? forwardUpdate(in, offset, + length) + : inverseUpdate(in, offset, + length)); + return result; + } + + /** + * Convenience method that calls the same method with three arguments. A + * zero-long byte array is used. + * + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate() throws TransformerException + { + byte[] result = (wired == Direction.FORWARD ? lastForwardUpdate() + : lastInverseUpdate()); + if (inBuffer.size() != 0) + { // we still have some buffered bytes + throw new TransformerException("lastUpdate(): input buffer not empty"); + } + return result; + } + + /** + * Convenience method that calls the method with same name and three + * arguments, using a byte array of length 1 whose contents are + * the designated byte. + * + * @param b the byte to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte b) throws TransformerException + { + return lastUpdate(new byte[] { b }, 0, 1); + } + + /** + * Convenience method that calls the same method with three arguments. All + * bytes in in, starting from index position 0 are + * considered. + * + * @param in the input data bytes. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + * @see #lastUpdate(byte[], int, int) + */ + public byte[] lastUpdate(byte[] in) throws TransformerException + { + return lastUpdate(in, 0, in.length); + } + + /** + * Processes a designated number of bytes from a given byte array and + * signals, at the same time, that this is the last push operation on + * this Transformer. + * + * @param in the input data bytes. + * @param offset index of in from which to start considering + * data. + * @param length the count of bytes to process. + * @return the result of transformation. + * @throws IllegalStateException if the instance is not initialised. + * @throws TransformerException if a transformation-related exception occurs + * during the operation. + */ + public byte[] lastUpdate(byte[] in, int offset, int length) + throws TransformerException + { + byte[] result = update(in, offset, length); + byte[] rest = lastUpdate(); + if (rest.length > 0) + { + byte[] newResult = new byte[result.length + rest.length]; + System.arraycopy(result, 0, newResult, 0, result.length); + System.arraycopy(rest, 0, newResult, result.length, rest.length); + result = newResult; + } + return result; + } + + // helper methods ---------------------------------------------------------- + + private byte[] forwardUpdate(byte[] in, int off, int len) + throws TransformerException + { + return (isPreProcessing() ? preTransform(in, off, len) : postTransform(in, + off, + len)); + } + + private byte[] inverseUpdate(byte[] in, int off, int len) + throws TransformerException + { + return (isPreProcessing() ? postTransform(in, off, len) : preTransform(in, + off, + len)); + } + + private byte[] preTransform(byte[] in, int off, int len) + throws TransformerException + { + byte[] result = updateDelegate(in, off, len); + result = tail.update(result); + return result; + } + + private byte[] postTransform(byte[] in, int off, int len) + throws TransformerException + { + byte[] result = tail.update(in, off, len); + result = updateDelegate(result, 0, result.length); + return result; + } + + private byte[] lastForwardUpdate() throws TransformerException + { + return (isPreProcessing() ? preLastTransform() : postLastTransform()); + } + + private byte[] lastInverseUpdate() throws TransformerException + { + return (isPreProcessing() ? postLastTransform() : preLastTransform()); + } + + private byte[] preLastTransform() throws TransformerException + { + byte[] result = lastUpdateDelegate(); + result = tail.lastUpdate(result); + return result; + } + + private byte[] postLastTransform() throws TransformerException + { + byte[] result = tail.lastUpdate(); + result = updateDelegate(result, 0, result.length); + byte[] rest = lastUpdateDelegate(); + if (rest.length > 0) + { + byte[] newResult = new byte[result.length + rest.length]; + System.arraycopy(result, 0, newResult, 0, result.length); + System.arraycopy(rest, 0, newResult, result.length, rest.length); + result = newResult; + } + return result; + } + + // abstract methods to be implemented by concrete subclasses --------------- + + abstract void initDelegate(Map attributes) throws TransformerException; + + abstract int delegateBlockSize(); + + abstract void resetDelegate(); + + abstract byte[] updateDelegate(byte[] in, int off, int len) + throws TransformerException; + + abstract byte[] lastUpdateDelegate() throws TransformerException; +} diff --git a/gnu/javax/crypto/assembly/TransformerException.java b/gnu/javax/crypto/assembly/TransformerException.java new file mode 100644 index 000000000..412f0f0f1 --- /dev/null +++ b/gnu/javax/crypto/assembly/TransformerException.java @@ -0,0 +1,158 @@ +/* TransformerException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.assembly; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + */ +public class TransformerException extends Exception +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private Throwable _exception = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public TransformerException() + { + super(); + } + + public TransformerException(String details) + { + super(details); + } + + public TransformerException(Throwable cause) + { + super(); + + this._exception = cause; + } + + public TransformerException(String details, Throwable cause) + { + super(details); + + this._exception = cause; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instant methods + // ------------------------------------------------------------------------- + + public Throwable getCause() + { + return _exception; + } + + /** + * Prints this exception's stack trace to System.err. If this + * exception has a root exception; the stack trace of the root exception is + * also printed to System.err. + */ + public void printStackTrace() + { + super.printStackTrace(); + if (_exception != null) + { + _exception.printStackTrace(); + } + } + + /** + * Prints this exception's stack trace to a print stream. If this exception + * has a root exception; the stack trace of the root exception is also + * printed to the print stream. + * + * @param ps the non-null print stream to which to print. + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if (_exception != null) + { + _exception.printStackTrace(ps); + } + } + + /** + * Prints this exception's stack trace to a print writer. If this exception + * has a root exception; the stack trace of the root exception is also + * printed to the print writer. + * + * @param pw the non-null print writer to use for output. + */ + public void printStackTrace(PrintWriter pw) + { + super.printStackTrace(pw); + if (_exception != null) + { + _exception.printStackTrace(pw); + } + } + + /** + * Returns the string representation of this exception. The string + * representation contains this exception's class name, its detailed + * messsage, and if it has a root exception, the string representation of the + * root exception. This string representation is meant for debugging and not + * meant to be interpreted programmatically. + * + * @return the non-null string representation of this exception. + * @see Throwable#getMessage() + */ + public String toString() + { + StringBuffer sb = new StringBuffer(this.getClass().getName()).append(": ").append( + super.toString()); + if (_exception != null) + { + sb.append("; caused by: ").append(_exception.toString()); + } + return sb.toString(); + } +} diff --git a/gnu/javax/crypto/cipher/Anubis.java b/gnu/javax/crypto/cipher/Anubis.java new file mode 100644 index 000000000..63b97ce4e --- /dev/null +++ b/gnu/javax/crypto/cipher/Anubis.java @@ -0,0 +1,583 @@ +/* Anubis.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +//import java.io.PrintWriter; +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + *

Anubis is a 128-bit block cipher that accepts a variable-length key. The + * cipher is a uniform substitution-permutation network whose inverse only + * differs from the forward operation in the key schedule. The design of both + * the round transformation and the key schedule is based upon the Wide Trail + * strategy and permits a wide variety of implementation trade-offs.

+ * + *

References:

+ * + *
    + *
  1. The + * ANUBIS Block Cipher.
    + * Paulo S.L.M. Barreto and + * Vincent Rijmen.
  2. + *
+ */ +public final class Anubis extends BaseCipher +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + // private static final String NAME = "anubis"; + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + // private static final PrintWriter err = new PrintWriter(System.out, true); + // private static void debug(String s) { + // err.println(">>> "+NAME+": "+s); + // } + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + + private static final String Sd = // p. 25 [ANUBIS] + "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C" + + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC" + + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102" + + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C" + + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB" + + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38" + + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746" + + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C" + + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2" + + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE" + + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E" + + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B" + + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8" + + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856" + + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2" + + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42"; + + private static final byte[] S = new byte[256]; + + private static final int[] T0 = new int[256]; + + private static final int[] T1 = new int[256]; + + private static final int[] T2 = new int[256]; + + private static final int[] T3 = new int[256]; + + private static final int[] T4 = new int[256]; + + private static final int[] T5 = new int[256]; + + /** + * Anubis round constants. This is the largest possible considering that we + * always use R values, R = 8 + N, and 4 <= N <= 10. + */ + private static final int[] rc = new int[18]; + + /** + * KAT vector (from ecb_vk): + * I=83 + * KEY=000000000000000000002000000000000000000000000000 + * CT=2E66AB15773F3D32FB6C697509460DF4 + */ + private static final byte[] KAT_KEY = Util.toBytesFromString("000000000000000000002000000000000000000000000000"); + + private static final byte[] KAT_CT = Util.toBytesFromString("2E66AB15773F3D32FB6C697509460DF4"); + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + // Static code - to initialise lookup tables ------------------------------- + + static + { + long time = System.currentTimeMillis(); + + int ROOT = 0x11d; // para. 2.1 [ANUBIS] + int i, s, s2, s4, s6, s8, t; + char c; + for (i = 0; i < 256; i++) + { + c = Sd.charAt(i >>> 1); + s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF; + S[i] = (byte) s; + + s2 = s << 1; + if (s2 > 0xFF) + { + s2 ^= ROOT; + } + + s4 = s2 << 1; + if (s4 > 0xFF) + { + s4 ^= ROOT; + } + + s6 = s4 ^ s2; + s8 = s4 << 1; + if (s8 > 0xFF) + { + s8 ^= ROOT; + } + + T0[i] = s << 24 | s2 << 16 | s4 << 8 | s6; + T1[i] = s2 << 24 | s << 16 | s6 << 8 | s4; + T2[i] = s4 << 24 | s6 << 16 | s << 8 | s2; + T3[i] = s6 << 24 | s4 << 16 | s2 << 8 | s; + + T4[i] = s << 24 | s << 16 | s << 8 | s; + T5[s] = s << 24 | s2 << 16 | s6 << 8 | s8; + } + + // compute round constant + for (i = 0, s = 0; i < 18;) + { + rc[i++] = S[(s++) & 0xFF] << 24 | (S[(s++) & 0xFF] & 0xFF) << 16 + | (S[(s++) & 0xFF] & 0xFF) << 8 | (S[(s++) & 0xFF] & 0xFF); + } + + time = System.currentTimeMillis() - time; + + if (DEBUG && debuglevel > 8) + { + System.out.println("=========="); + System.out.println(); + System.out.println("Static data"); + System.out.println(); + + System.out.println(); + System.out.println("T0[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T0[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T1[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T1[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T2[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T2[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T3[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T3[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T4[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T4[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T5[]:"); + for (i = 0; i < 64; i++) + { + for (t = 0; t < 4; t++) + { + System.out.print("0x" + Util.toString(T5[i * 4 + t]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("rc[]:"); + for (i = 0; i < 18; i++) + { + System.out.println("0x" + Util.toString(rc[i])); + } + System.out.println(); + + System.out.println(); + System.out.println("Total initialization time: " + time + " ms."); + System.out.println(); + } + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Anubis() + { + super(Registry.ANUBIS_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + private static void anubis(byte[] in, int i, byte[] out, int j, int[][] K) + { + // extract encryption round keys + int R = K.length - 1; + int[] Ker = K[0]; + + // mu function + affine key addition + int a0 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Ker[0]; + int a1 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Ker[1]; + int a2 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Ker[2]; + int a3 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i] & 0xFF)) + ^ Ker[3]; + + int b0, b1, b2, b3; + // round function + for (int r = 1; r < R; r++) + { + Ker = K[r]; + b0 = T0[a0 >>> 24] ^ T1[a1 >>> 24] ^ T2[a2 >>> 24] ^ T3[a3 >>> 24] + ^ Ker[0]; + b1 = T0[(a0 >>> 16) & 0xFF] ^ T1[(a1 >>> 16) & 0xFF] + ^ T2[(a2 >>> 16) & 0xFF] ^ T3[(a3 >>> 16) & 0xFF] ^ Ker[1]; + b2 = T0[(a0 >>> 8) & 0xFF] ^ T1[(a1 >>> 8) & 0xFF] + ^ T2[(a2 >>> 8) & 0xFF] ^ T3[(a3 >>> 8) & 0xFF] ^ Ker[2]; + b3 = T0[a0 & 0xFF] ^ T1[a1 & 0xFF] ^ T2[a2 & 0xFF] ^ T3[a3 & 0xFF] + ^ Ker[3]; + a0 = b0; + a1 = b1; + a2 = b2; + a3 = b3; + if (DEBUG && debuglevel > 6) + { + System.out.println("T" + r + "=" + Util.toString(a0) + + Util.toString(a1) + Util.toString(a2) + + Util.toString(a3)); + } + } + + // last round function + Ker = K[R]; + int tt = Ker[0]; + out[j++] = (byte) (S[a0 >>> 24] ^ (tt >>> 24)); + out[j++] = (byte) (S[a1 >>> 24] ^ (tt >>> 16)); + out[j++] = (byte) (S[a2 >>> 24] ^ (tt >>> 8)); + out[j++] = (byte) (S[a3 >>> 24] ^ tt); + tt = Ker[1]; + out[j++] = (byte) (S[(a0 >>> 16) & 0xFF] ^ (tt >>> 24)); + out[j++] = (byte) (S[(a1 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (S[(a2 >>> 16) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte) (S[(a3 >>> 16) & 0xFF] ^ tt); + tt = Ker[2]; + out[j++] = (byte) (S[(a0 >>> 8) & 0xFF] ^ (tt >>> 24)); + out[j++] = (byte) (S[(a1 >>> 8) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (S[(a2 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte) (S[(a3 >>> 8) & 0xFF] ^ tt); + tt = Ker[3]; + out[j++] = (byte) (S[a0 & 0xFF] ^ (tt >>> 24)); + out[j++] = (byte) (S[a1 & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (S[a2 & 0xFF] ^ (tt >>> 8)); + out[j] = (byte) (S[a3 & 0xFF] ^ tt); + + if (DEBUG && debuglevel > 6) + { + System.out.println("T=" + Util.toString(out, j - 15, 16)); + System.out.println(); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Anubis result = new Anubis(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 4; n < 10; n++) + { + al.add(new Integer(n * 32 / 8)); + } + + return Collections.unmodifiableList(al).iterator(); + } + + /** + *

Expands a user-supplied key material into a session key for a + * designated block size.

+ * + * @param uk the 32N-bit user-supplied key material; 4 <= N <= 10. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16 (128-bit). + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + if (uk == null) + { + throw new InvalidKeyException("Empty key"); + } + if ((uk.length % 4) != 0) + { + throw new InvalidKeyException("Key is not multiple of 32-bit."); + } + int N = uk.length / 4; + if (N < 4 || N > 10) + { + throw new InvalidKeyException("Key is not 32N; 4 <= N <= 10"); + } + int R = 8 + N; + int[][] Ke = new int[R + 1][4]; // encryption round keys + int[][] Kd = new int[R + 1][4]; // decryption round keys + int[] tk = new int[N]; + int[] kk = new int[N]; + int r, i, j, k, k0, k1, k2, k3, tt; + + // apply mu to k0 + for (r = 0, i = 0; r < N;) + { + tk[r++] = uk[i++] << 24 | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 | (uk[i++] & 0xFF); + } + for (r = 0; r <= R; r++) + { + if (r > 0) + { + // psi = key evolution function + kk[0] = T0[(tk[0] >>> 24)] ^ T1[(tk[N - 1] >>> 16) & 0xFF] + ^ T2[(tk[N - 2] >>> 8) & 0xFF] ^ T3[tk[N - 3] & 0xFF]; + kk[1] = T0[(tk[1] >>> 24)] ^ T1[(tk[0] >>> 16) & 0xFF] + ^ T2[(tk[N - 1] >>> 8) & 0xFF] ^ T3[tk[N - 2] & 0xFF]; + kk[2] = T0[(tk[2] >>> 24)] ^ T1[(tk[1] >>> 16) & 0xFF] + ^ T2[(tk[0] >>> 8) & 0xFF] ^ T3[tk[N - 1] & 0xFF]; + kk[3] = T0[(tk[3] >>> 24)] ^ T1[(tk[2] >>> 16) & 0xFF] + ^ T2[(tk[1] >>> 8) & 0xFF] ^ T3[tk[0] & 0xFF]; + + for (i = 4; i < N; i++) + { + kk[i] = T0[tk[i] >>> 24] ^ T1[(tk[i - 1] >>> 16) & 0xFF] + ^ T2[(tk[i - 2] >>> 8) & 0xFF] ^ T3[tk[i - 3] & 0xFF]; + } + // apply sigma (affine addition) to round constant + tk[0] = rc[r - 1] ^ kk[0]; + for (i = 1; i < N; i++) + { + tk[i] = kk[i]; + } + } + + // phi = key selection function + tt = tk[N - 1]; + k0 = T4[tt >>> 24]; + k1 = T4[(tt >>> 16) & 0xFF]; + k2 = T4[(tt >>> 8) & 0xFF]; + k3 = T4[tt & 0xFF]; + + for (k = N - 2; k >= 0; k--) + { + tt = tk[k]; + k0 = T4[tt >>> 24] ^ (T5[(k0 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k0 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k0 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5[k0 & 0xFF] & 0x000000FF); + k1 = T4[(tt >>> 16) & 0xFF] ^ (T5[(k1 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k1 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k1 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5[k1 & 0xFF] & 0x000000FF); + k2 = T4[(tt >>> 8) & 0xFF] ^ (T5[(k2 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k2 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k2 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5[(k2) & 0xFF] & 0x000000FF); + k3 = T4[tt & 0xFF] ^ (T5[(k3 >>> 24) & 0xFF] & 0xFF000000) + ^ (T5[(k3 >>> 16) & 0xFF] & 0x00FF0000) + ^ (T5[(k3 >>> 8) & 0xFF] & 0x0000FF00) + ^ (T5[k3 & 0xFF] & 0x000000FF); + } + + Ke[r][0] = k0; + Ke[r][1] = k1; + Ke[r][2] = k2; + Ke[r][3] = k3; + + if (r == 0 || r == R) + { + Kd[R - r][0] = k0; + Kd[R - r][1] = k1; + Kd[R - r][2] = k2; + Kd[R - r][3] = k3; + } + else + { + Kd[R - r][0] = T0[S[k0 >>> 24] & 0xFF] + ^ T1[S[(k0 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k0 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[k0 & 0xFF] & 0xFF]; + Kd[R - r][1] = T0[S[k1 >>> 24] & 0xFF] + ^ T1[S[(k1 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k1 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[k1 & 0xFF] & 0xFF]; + Kd[R - r][2] = T0[S[k2 >>> 24] & 0xFF] + ^ T1[S[(k2 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k2 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[k2 & 0xFF] & 0xFF]; + Kd[R - r][3] = T0[S[k3 >>> 24] & 0xFF] + ^ T1[S[(k3 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(k3 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[k3 & 0xFF] & 0xFF]; + } + } + + if (DEBUG && debuglevel > 8) + { + System.out.println(); + System.out.println("Key schedule"); + System.out.println(); + System.out.println("Ke[]:"); + for (r = 0; r < R + 1; r++) + { + System.out.print("#" + r + ": "); + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(Ke[r][j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("Kd[]:"); + for (r = 0; r < R + 1; r++) + { + System.out.print("#" + r + ": "); + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(Kd[r][j]) + ", "); + System.out.println(); + } + System.out.println(); + } + + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + + int[][] K = (int[][]) ((Object[]) k)[0]; + anubis(in, i, out, j, K); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + + int[][] K = (int[][]) ((Object[]) k)[1]; + anubis(in, i, out, j, K); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + { + result = testKat(KAT_KEY, KAT_CT); + } + valid = new Boolean(result); + } + return valid.booleanValue(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/BaseCipher.java b/gnu/javax/crypto/cipher/BaseCipher.java new file mode 100644 index 000000000..9d62311ed --- /dev/null +++ b/gnu/javax/crypto/cipher/BaseCipher.java @@ -0,0 +1,304 @@ +/* BaseCipher.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +/** + *

A basic abstract class to facilitate implementing symmetric key block + * ciphers.

+ */ +public abstract class BaseCipher implements IBlockCipher, IBlockCipherSpi +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The canonical name prefix of the cipher. */ + protected String name; + + /** The default block size, in bytes. */ + protected int defaultBlockSize; + + /** The default key size, in bytes. */ + protected int defaultKeySize; + + /** The current block size, in bytes. */ + protected int currentBlockSize; + + /** The session key for this instance. */ + protected transient Object currentKey; + + /** The instance lock. */ + protected Object lock = new Object(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial constructor for use by concrete subclasses.

+ * + * @param name the canonical name prefix of this instance. + * @param defaultBlockSize the default block size in bytes. + * @param defaultKeySize the default key size in bytes. + */ + protected BaseCipher(String name, int defaultBlockSize, int defaultKeySize) + { + super(); + + this.name = name; + this.defaultBlockSize = defaultBlockSize; + this.defaultKeySize = defaultKeySize; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IBlockCipher interface implementation ----------------------------------- + + public abstract Object clone(); + + public String name() + { + StringBuffer sb = new StringBuffer(name).append('-'); + if (currentKey == null) + { + sb.append(String.valueOf(8 * defaultBlockSize)); + } + else + { + sb.append(String.valueOf(8 * currentBlockSize)); + } + return sb.toString(); + } + + public int defaultBlockSize() + { + return defaultBlockSize; + } + + public int defaultKeySize() + { + return defaultKeySize; + } + + public void init(Map attributes) throws InvalidKeyException + { + synchronized (lock) + { + if (currentKey != null) + { + throw new IllegalStateException(); + } + + Integer bs = (Integer) attributes.get(CIPHER_BLOCK_SIZE); + if (bs == null) + { // no block size was specified. + if (currentBlockSize == 0) + { // happy birthday + currentBlockSize = defaultBlockSize; + } // else it's a clone. use as is + } + else + { + currentBlockSize = bs.intValue(); + // ensure that value is valid + Iterator it; + boolean ok = false; + for (it = blockSizes(); it.hasNext();) + { + ok = (currentBlockSize == ((Integer) it.next()).intValue()); + if (ok) + { + break; + } + } + if (!ok) + { + throw new IllegalArgumentException( + IBlockCipher.CIPHER_BLOCK_SIZE); + } + } + + byte[] k = (byte[]) attributes.get(KEY_MATERIAL); + currentKey = makeKey(k, currentBlockSize); + } + } + + public int currentBlockSize() + { + if (currentKey == null) + { + throw new IllegalStateException(); + } + return currentBlockSize; + } + + public void reset() + { + synchronized (lock) + { + // currentBlockSize = 0; + currentKey = null; + } + } + + public void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException + { + synchronized (lock) + { + if (currentKey == null) + { + throw new IllegalStateException(); + } + + encrypt(in, inOffset, out, outOffset, currentKey, currentBlockSize); + } + } + + public void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException + { + synchronized (lock) + { + if (currentKey == null) + { + throw new IllegalStateException(); + } + + decrypt(in, inOffset, out, outOffset, currentKey, currentBlockSize); + } + } + + public boolean selfTest() + { + int ks; + Iterator bit; + + // do symmetry tests for all block-size/key-size combos + for (Iterator kit = keySizes(); kit.hasNext();) + { + ks = ((Integer) kit.next()).intValue(); + for (bit = blockSizes(); bit.hasNext();) + { + if (!testSymmetry(ks, ((Integer) bit.next()).intValue())) + { + return false; + } + } + } + + return true; + } + + // own methods ------------------------------------------------------------- + + private boolean testSymmetry(int ks, int bs) + { + try + { + byte[] kb = new byte[ks]; + byte[] pt = new byte[bs]; + byte[] ct = new byte[bs]; + byte[] cpt = new byte[bs]; + int i; + for (i = 0; i < ks; i++) + { + kb[i] = (byte) i; + } + for (i = 0; i < bs; i++) + { + pt[i] = (byte) i; + } + + Object k = makeKey(kb, bs); + encrypt(pt, 0, ct, 0, k, bs); + decrypt(ct, 0, cpt, 0, k, bs); + + return Arrays.equals(pt, cpt); + + } + catch (Exception x) + { + x.printStackTrace(System.err); + return false; + } + } + + protected boolean testKat(byte[] kb, byte[] ct) + { + return testKat(kb, ct, new byte[ct.length]); // all-zero plaintext + } + + protected boolean testKat(byte[] kb, byte[] ct, byte[] pt) + { + try + { + int bs = pt.length; + byte[] t = new byte[bs]; + + Object k = makeKey(kb, bs); + + // test encryption + encrypt(pt, 0, t, 0, k, bs); + if (!Arrays.equals(t, ct)) + { + return false; + } + // test decryption + decrypt(t, 0, t, 0, k, bs); + return Arrays.equals(t, pt); + + } + catch (Exception x) + { + x.printStackTrace(System.err); + return false; + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Blowfish.java b/gnu/javax/crypto/cipher/Blowfish.java new file mode 100644 index 000000000..5cb958ee4 --- /dev/null +++ b/gnu/javax/crypto/cipher/Blowfish.java @@ -0,0 +1,749 @@ +/* Blowfish.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +// -------------------------------------------------------------------------- +// +// Based on the C implementation from the GNU Privacy Guard. +// +// -------------------------------------------------------------------------- + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Sequence; +import gnu.java.security.util.Util; + +import java.util.Collections; +import java.util.Iterator; + +/** + * Blowfish is a 16-round, 64-bit Feistel cipher designed by Bruce + * Schneier. It accepts a variable-length key of up to 448 bits. + * + *

References:

+ *
    + *
  1. Schneier, Bruce: Applied Cryptography, Second Edition, + * 336--339, 647--654 (1996 Bruce Schneier).
  2. + *
  3. The + * Blowfish Encryption Algorithm.
  4. + *
+ */ +public class Blowfish extends BaseCipher +{ + + // Constants and variables + // ----------------------------------------------------------------- + + private static final int DEFAULT_BLOCK_SIZE = 8; + + private static final int DEFAULT_KEY_SIZE = 8; + + private static final int MAX_KEY_LENGTH = 56; + + /** Initial value of the p-array. */ + private static final int[] P = { 0x243f6a88, 0x85a308d3, 0x13198a2e, + 0x03707344, 0xa4093822, 0x299f31d0, + 0x082efa98, 0xec4e6c89, 0x452821e6, + 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, + 0xb5470917, 0x9216d5d9, 0x8979fb1b }; + + /** Initial value of S-box 1. */ + static final int[] KS0 = { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a }; + + /** Initial value of S-box 2. */ + private static final int[] KS1 = { 0x4b7a70e9, 0xb5b32944, 0xdb75092e, + 0xc4192623, 0xad6ea6b0, 0x49a7df7d, + 0x9cee60b8, 0x8fedb266, 0xecaa8c71, + 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, + 0xe4183a3e, 0x3f54989a, 0x5b429d65, + 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, + 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, + 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, + 0x3c971814, 0x6b6a70a1, 0x687f3584, + 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, + 0x5716f2b8, 0xb03ada37, 0xf0500c0d, + 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, + 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, + 0x22f54701, 0x3ae5e581, 0x37c2dadc, + 0xc8b57634, 0x9af3dda7, 0xa9446146, + 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, + 0x183eb331, 0x4e548b38, 0x4f6db908, + 0x6f420d03, 0xf60a04bf, 0x2cb81290, + 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, + 0xdccf3f2e, 0x5512721f, 0x2e6b7124, + 0x501adde6, 0x9f84cd87, 0x7a584718, + 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, + 0xc464c3d2, 0xef1c1847, 0x3215d908, + 0xdd433b37, 0x24c2ba16, 0x12a14d43, + 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, + 0x5f11199b, 0x043556f1, 0xd7a3c76b, + 0x3c11183b, 0x5924a509, 0xf28fe6ed, + 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, + 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, + 0x2965dcb9, 0x99e71d0f, 0x803e89d6, + 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, + 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, + 0x1939260f, 0x19c27960, 0x5223a708, + 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, + 0x018cff28, 0xc332ddef, 0xbe6c5aa5, + 0x65582185, 0x68ab9802, 0xeecea50f, + 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, + 0x619f1510, 0x13cca830, 0xeb61bd96, + 0x0334fe1e, 0xaa0363cf, 0xb5735c90, + 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, + 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, + 0xa02369b9, 0x655abb50, 0x40685a32, + 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, + 0x623d7da8, 0xf837889a, 0x97e32d77, + 0x11ed935f, 0x16681281, 0x0e358829, + 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, + 0x1ac24696, 0xcdb30aeb, 0x532e3054, + 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, + 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, + 0x203e13e0, 0x45eee2b6, 0xa3aaabea, + 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, + 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, + 0x3d816250, 0xcf62a1f2, 0x5b8d2646, + 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, + 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, + 0x23820e00, 0x58428d2a, 0x0c55f5ea, + 0x1dadf43e, 0x233f7061, 0x3372f092, + 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, + 0xce77326e, 0xa6078084, 0x19f8509e, + 0xe8efd855, 0x61d99735, 0xa969a7aa, + 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, + 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, + 0x675fda79, 0xe3674340, 0xc5c43465, + 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, + 0xdb83adf7 }; + + /** Initial value of S-box 3. */ + private static final int[] KS2 = { 0xe93d5a68, 0x948140f7, 0xf64c261c, + 0x94692934, 0x411520f7, 0x7602d4f7, + 0xbcf46b2e, 0xd4a20068, 0xd4082471, + 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, + 0xbf8b8840, 0x4d95fc1d, 0x96b591af, + 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, + 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, + 0xabca0a9a, 0x28507825, 0x530429f4, + 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, + 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, + 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, + 0xce78a399, 0x406b2a42, 0x20fe9e35, + 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, + 0xeae397b2, 0x3a6efa74, 0xdd5b4332, + 0x6841e7f7, 0xca7820fb, 0xfb0af54e, + 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, + 0xd096954b, 0x55a867bc, 0xa1159a58, + 0xcca92963, 0x99e1db33, 0xa62a4a56, + 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, + 0x05282ce3, 0x95c11548, 0xe4c66d22, + 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, + 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, + 0x41113564, 0x257b7834, 0x602a9c60, + 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, + 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, + 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, + 0xde720c8c, 0x2da2f728, 0xd0127845, + 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, + 0xf33e8d1e, 0x0a476341, 0x992eff74, + 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, + 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, + 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, + 0xb5390f92, 0x690fed0b, 0x667b9ffb, + 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, + 0x763bd6eb, 0x37392eb3, 0xcc115979, + 0x8026e297, 0xf42e312d, 0x6842ada7, + 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, + 0x4bfb6350, 0x1a6b1018, 0x11caedfa, + 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, + 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, + 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, + 0x60787bf8, 0x6003604d, 0xd1fd8346, + 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, + 0x3c005e5f, 0x77a057be, 0xbde8ae24, + 0x55464299, 0xbf582e61, 0x4e58f48f, + 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, + 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, + 0x846a0e79, 0x915f95e2, 0x466e598e, + 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, + 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, + 0x662d09a1, 0xc4324633, 0xe85a1f02, + 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, + 0x2868f169, 0xdcb7da83, 0x573906fe, + 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, + 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, + 0x61a806b5, 0xf0177a28, 0xc0f586e0, + 0x006058aa, 0x30dc7d62, 0x11e69ed7, + 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, + 0xce591d76, 0x6f05e409, 0x4b7c0188, + 0x39720a3d, 0x7c927c24, 0x86e3725f, + 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, + 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, + 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, + 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, + 0x406000e0 }; + + /** Initial value of S-box 4. */ + private static final int[] KS3 = { 0x3a39ce37, 0xd3faf5cf, 0xabc27737, + 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, + 0xd3822740, 0x99bc9bbe, 0xd5118e9d, + 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, + 0x6a366eb4, 0x5748ab2f, 0xbc946e79, + 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, + 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, + 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, + 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, + 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, + 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, + 0x4ba99586, 0xef5562e9, 0xc72fefd3, + 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, + 0x3b3ee593, 0xe990fd5a, 0x9e34d797, + 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, + 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, + 0x5a88f54c, 0xe029ac71, 0xe019a5e6, + 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, + 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, + 0xe3d35e8c, 0x15056dd4, 0x88f46dba, + 0x03a16125, 0x0564f0bd, 0xc3eb9e15, + 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, + 0x26dcf319, 0x7533d928, 0xb155fdf5, + 0x03563482, 0x8aba3cbb, 0x28517711, + 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, + 0x9320f991, 0xea7a90c2, 0xfb3e7bce, + 0x5121ce64, 0x774fbe32, 0xa8b6e37e, + 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, + 0x09072166, 0xb39a460a, 0x6445c0dd, + 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, + 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, + 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, + 0x8d6612ae, 0xbf3c6f47, 0xd29be463, + 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, + 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, + 0x34d2466a, 0x0115af84, 0xe1b00428, + 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, + 0x277227f8, 0x611560b1, 0xe7933fdc, + 0xbb3a792b, 0x344525bd, 0xa08839e1, + 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, + 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, + 0xd0dadecb, 0xd50ada38, 0x0339c32a, + 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, + 0x27d9459c, 0xbf97222c, 0x15e6fc2a, + 0x0f91fc71, 0x9b941525, 0xfae59361, + 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, + 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, + 0x4c98a0be, 0x3278e964, 0x9f1f9532, + 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, + 0xc37632d8, 0xdf359f8d, 0x9b992f2e, + 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, + 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, + 0xf6fb2299, 0xf523f357, 0xa6327623, + 0x93a83531, 0x56cccd02, 0xacf08162, + 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, + 0x71c65614, 0xe6c6c7bd, 0x327a140a, + 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, + 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, + 0xcd769c2b, 0x53113ec0, 0x1640e3d3, + 0x38abbd60, 0x2547adf0, 0xba38209c, + 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, + 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, + 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, + 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, + 0x3ac372e6 }; + + /** Cache of the self test. */ + private static Boolean valid; + + /** + * Test vector, as published in + * href="http://www.counterpane.com/vectors.txt">http://www.counterpane.com/vectors.txt. + * + * KEY=0000000000000000 + * PT=0000000000000000 + * CT=4EF997456198DD78 + */ + private static final byte[] TV_KEY = Util.toBytesFromString("0000000000000000"); + + private static final byte[] TV_CT = Util.toBytesFromString("4EF997456198DD78"); + + // Constructors + // ----------------------------------------------------------------------- + + public Blowfish() + { + super(Registry.BLOWFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Clonable interface implementation. + // ----------------------------------------------------------------------- + + public Object clone() + { + Blowfish result = new Blowfish(); + result.currentBlockSize = currentBlockSize; + return result; + } + + // Implementations of abstract methods from BaseCipher + // ----------------------------------------------------------------------- + + public Iterator keySizes() + { + return new Sequence(8, MAX_KEY_LENGTH, 8).iterator(); + // return new Iterator() { + // private int i = 0; + + // public boolean hasNext() { + // return i <= MAX_KEY_LENGTH-8; + // } + + // public Object next() { + // if (hasNext()) { + // i += 8; + // return new Integer(i); + // } + // return null; + // } + + // public void remove() { + // throw new UnsupportedOperationException(); + // } + // }; + } + + public Iterator blockSizes() + { + return Collections.singleton(new Integer(DEFAULT_BLOCK_SIZE)).iterator(); + } + + public Object makeKey(byte[] k, int bs) + { + Context ctx = new Context(); + System.arraycopy(P, 0, ctx.p, 0, P.length); + System.arraycopy(KS0, 0, ctx.s0, 0, KS0.length); + System.arraycopy(KS1, 0, ctx.s1, 0, KS1.length); + System.arraycopy(KS2, 0, ctx.s2, 0, KS2.length); + System.arraycopy(KS3, 0, ctx.s3, 0, KS3.length); + + // XOR the key with the P-box + int l = 0; + for (int i = 0; i < ctx.p.length; i++) + { + int data = 0; + for (int j = 0; j < 4; j++) + { + data = (data << 8) | (k[l++] & 0xff); + if (l >= k.length) + { + l = 0; + } + } + ctx.p[i] ^= data; + } + + // We swap the left and right words here only, so we can avoid + // swapping altogether during encryption/decryption. + int t; + Block x = new Block(); + x.left = x.right = 0; + for (int i = 0; i < ctx.p.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.p[i] = x.right; + ctx.p[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s0.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s0[i] = x.right; + ctx.s0[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s1.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s1[i] = x.right; + ctx.s1[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s2.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s2[i] = x.right; + ctx.s2[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + for (int i = 0; i < ctx.s3.length; i += 2) + { + blowfishEncrypt(x, ctx); + ctx.s3[i] = x.right; + ctx.s3[i + 1] = x.left; + t = x.right; + x.right = x.left; + x.left = t; + } + x.left = x.right = 0; + return ctx; + } + + public void encrypt(byte[] in, int i, byte[] out, int o, Object k, int bs) + { + Block x = new Block(); + x.left = (in[i] & 0xff) << 24 | (in[i + 1] & 0xff) << 16 + | (in[i + 2] & 0xff) << 8 | (in[i + 3] & 0xff); + x.right = (in[i + 4] & 0xff) << 24 | (in[i + 5] & 0xff) << 16 + | (in[i + 6] & 0xff) << 8 | (in[i + 7] & 0xff); + blowfishEncrypt(x, (Context) k); + out[o] = (byte) (x.right >>> 24); + out[o + 1] = (byte) (x.right >>> 16); + out[o + 2] = (byte) (x.right >>> 8); + out[o + 3] = (byte) x.right; + out[o + 4] = (byte) (x.left >>> 24); + out[o + 5] = (byte) (x.left >>> 16); + out[o + 6] = (byte) (x.left >>> 8); + out[o + 7] = (byte) x.left; + x.left = x.right = 0; + } + + public void decrypt(byte[] in, int i, byte[] out, int o, Object k, int bs) + { + Block x = new Block(); + x.left = (in[i] & 0xff) << 24 | (in[i + 1] & 0xff) << 16 + | (in[i + 2] & 0xff) << 8 | (in[i + 3] & 0xff); + x.right = (in[i + 4] & 0xff) << 24 | (in[i + 5] & 0xff) << 16 + | (in[i + 6] & 0xff) << 8 | (in[i + 7] & 0xff); + blowfishDecrypt(x, (Context) k); + out[o] = (byte) (x.right >>> 24); + out[o + 1] = (byte) (x.right >>> 16); + out[o + 2] = (byte) (x.right >>> 8); + out[o + 3] = (byte) x.right; + out[o + 4] = (byte) (x.left >>> 24); + out[o + 5] = (byte) (x.left >>> 16); + out[o + 6] = (byte) (x.left >>> 8); + out[o + 7] = (byte) x.left; + x.left = x.right = 0; + } + + // Own methods + // ----------------------------------------------------------------- + + /** Encrypt a single pair of 32-bit integers. */ + private void blowfishEncrypt(Block x, Context ctx) + { + int[] p = ctx.p; + int[] s0 = ctx.s0, s1 = ctx.s1, s2 = ctx.s2, s3 = ctx.s3; + x.left ^= p[0]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[1]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[2]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[3]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[4]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[5]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[6]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[7]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[8]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[9]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[10]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[11]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[12]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[13]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[14]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[15]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[16]; + x.right ^= p[17]; + } + + /** Decrypt a single pair of 32-bit integers. */ + private void blowfishDecrypt(Block x, Context ctx) + { + int[] p = ctx.p; + int[] s0 = ctx.s0, s1 = ctx.s1, s2 = ctx.s2, s3 = ctx.s3; + x.left ^= p[17]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[16]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[15]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[14]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[13]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[12]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[11]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[10]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[9]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[8]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[7]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[6]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[5]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[4]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[3]; + x.right ^= ((s0[x.left >>> 24] + s1[x.left >>> 16 & 0xff]) ^ s2[x.left >>> 8 & 0xff]) + + s3[x.left & 0xff] ^ p[2]; + x.left ^= ((s0[x.right >>> 24] + s1[x.right >>> 16 & 0xff]) ^ s2[x.right >>> 8 & 0xff]) + + s3[x.right & 0xff] ^ p[1]; + x.right ^= p[0]; + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // symmetry + if (result) + { + result = testKat(TV_KEY, TV_CT); + } + valid = new Boolean(result); + } + return valid.booleanValue(); + } + + // Inner classes. + // ----------------------------------------------------------------------- + + /** A simple wrapper for the P- and S-boxes. */ + private class Context implements Cloneable + { + + // Constants and variables. + // -------------------------------------------------------------------- + + /** The P-array. */ + int[] p, s0, s1, s2, s3; + + // Constructors. + // -------------------------------------------------------------------- + + /** Default 0-arguments constructor. */ + Context() + { + p = new int[18]; + s0 = new int[256]; + s1 = new int[256]; + s2 = new int[256]; + s3 = new int[256]; + } + + /** + * Private constructor for cloneing. + * + * @param that The instance being cloned. + */ + private Context(Context that) + { + this.p = (int[]) that.p.clone(); + this.s0 = (int[]) that.s0.clone(); + this.s1 = (int[]) that.s1.clone(); + this.s2 = (int[]) that.s2.clone(); + this.s3 = (int[]) that.s3.clone(); + } + + // Clonable interface implementation. + // -------------------------------------------------------------------- + + public Object clone() + { + return new Context(this); + } + } + + private class Block + { + int left, right; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Cast5.java b/gnu/javax/crypto/cipher/Cast5.java new file mode 100644 index 000000000..cbdfe61f5 --- /dev/null +++ b/gnu/javax/crypto/cipher/Cast5.java @@ -0,0 +1,1391 @@ +/* Cast5.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + *

An implmenetation of the CAST5 (a.k.a. CAST-128) algorithm, + * as per RFC-2144, dated May 1997.

+ * + *

In this RFC, Carlisle Adams (the CA in CAST, ST stands for + * Stafford Tavares) describes CAST5 as:

+ * + *
+ * "...a DES-like Substitution-Permutation Network (SPN) cryptosystem which + * appears to have good resistance to differential cryptanalysis, linear + * cryptanalysis, and related-key cryptanalysis. This cipher also possesses + * a number of other desirable cryptographic properties, including avalanche, + * Strict Avalanche Criterion (SAC), Bit Independence Criterion (BIC), no + * complementation property, and an absence of weak and semi-weak keys." + *
+ * + *

CAST5 is a symmetric block cipher with a block-size of 8 + * bytes and a variable key-size of up to 128 bits. Its authors, and their + * employer (Entrust Technologies, a Nortel majority-owned company), made it + * available worldwide on a royalty-free basis for commercial and non-commercial + * uses.

+ * + *

The CAST5 encryption algorithm has been designed to allow a + * key size that can vary from 40 bits to 128 bits, + * in 8-bit increments (that is, the allowable key sizes are 40, 48, 56, + * 64, ..., 112, 120, and 128 bits. For variable keysize + * operation, the specification is as follows:

+ * + *
    + *
  1. For key sizes up to and including 80 bits (i.e., + * 40, 48, 56, 64, 72, and 80 bits), the algorithm + * is exactly as specified but uses 12 rounds instead of + * 16;
  2. + *
  3. For key sizes greater than 80 bits, the algorithm uses + * the full 16 rounds;
  4. + *
  5. For key sizes less than 128 bits, the key is padded with + * zero bytes (in the rightmost, or least significant, positions) out to + * 128 bits (since the CAST5 key schedule assumes + * an input key of 128 bits).
  6. + *
+ * + *

References:

+ * + *
    + *
  1. The CAST-128 Encryption + * Algorithm.
    + * Carlisle Adams.
  2. + *
+ */ +public class Cast5 extends BaseCipher +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int DEFAULT_BLOCK_SIZE = 8; // in bytes + + private static final int DEFAULT_KEY_SIZE = 5; // in bytes + + /** + * KAT vector (from rfc-2144): + * 40-bit key = 01 23 45 67 12 + * = 01 23 45 67 12 00 00 00 00 00 00 00 00 00 00 00 + * plaintext = 01 23 45 67 89 AB CD EF + * ciphertext = 7A C8 16 D1 6E 9B 30 2E + */ + private static final byte[] KAT_KEY = Util.toBytesFromString("0123456712"); + + private static final byte[] KAT_PT = Util.toBytesFromString("0123456789ABCDEF"); + + private static final byte[] KAT_CT = Util.toBytesFromString("7AC816D16E9B302E"); + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + // CAST5 S-boxes + private static final int[] S1 = { 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, + 0x3F258C7A, 0x1E213F2F, 0x9C004DD3, + 0x6003E540, 0xCF9FC949, 0xBFD4AF27, + 0x88BBBDB5, 0xE2034090, 0x98D09675, + 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, + 0x22D4FF8E, 0x28683B6F, 0xC07FD059, + 0xFF2379C8, 0x775F50E2, 0x43C340D3, + 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, + 0xA1C9E0D6, 0x346C4819, 0x61B76D87, + 0x22540F2F, 0x2ABE32E1, 0xAA54166B, + 0x22568E3A, 0xA2D341D0, 0x66DB40C8, + 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, + 0x97943FAC, 0x4A97C1D8, 0x527644B7, + 0xB5F437A7, 0xB82CBAEF, 0xD751D159, + 0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, + 0x90ECF52E, 0x22B0C054, 0xBC8E5935, + 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, + 0xBEE5812D, 0xB7332290, 0xE93B159F, + 0xB48EE411, 0x4BFF345D, 0xFD45C240, + 0xAD31973F, 0xC4F6D02E, 0x55FC8165, + 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, + 0xC19B0C50, 0x882240F2, 0x0C6E4F38, + 0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, + 0xC59C5319, 0xB949E354, 0xB04669FE, + 0xB1B6AB8A, 0xC71358DD, 0x6385C545, + 0x110F935D, 0x57538AD5, 0x6A390493, + 0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, + 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, + 0x29F9D4D5, 0xF61B1891, 0xBB72275E, + 0xAA508167, 0x38901091, 0xC6B505EB, + 0x84C7CB8C, 0x2AD75A0F, 0x874A1427, + 0xA2D1936B, 0x2AD286AF, 0xAA56D291, + 0xD7894360, 0x425C750D, 0x93B39E26, + 0x187184C9, 0x6C00B32D, 0x73E2BB14, + 0xA0BEBC3C, 0x54623779, 0x64459EAB, + 0x3F328B82, 0x7718CF82, 0x59A2CEA6, + 0x04EE002E, 0x89FE78E6, 0x3FAB0950, + 0x325FF6C2, 0x81383F05, 0x6963C5C8, + 0x76CB5AD6, 0xD49974C9, 0xCA180DCF, + 0x380782D5, 0xC7FA5CF6, 0x8AC31511, + 0x35E79E13, 0x47DA91D0, 0xF40F9086, + 0xA7E2419E, 0x31366241, 0x051EF495, + 0xAA573B04, 0x4A805D8D, 0x548300D0, + 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, + 0x75C6372B, 0x50AFD341, 0xA7C13275, + 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426, + 0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, + 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, + 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, + 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98, + 0xE31231B2, 0x2AD5AD6C, 0x954329DE, + 0xADBE4528, 0xD8710F69, 0xAA51C90F, + 0xAA786BF6, 0x22513F1E, 0xAA51A79B, + 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD, + 0x1B069505, 0x41ECE491, 0xB4C332E6, + 0x032268D4, 0xC9600ACC, 0xCE387E6D, + 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, + 0xD4DF39DE, 0xE01063DA, 0x4736F464, + 0x5AD328D8, 0xB347CC96, 0x75BB0FC3, + 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, + 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, + 0xAC39570A, 0x3F04442F, 0x6188B153, + 0xE0397A2E, 0x5727CB79, 0x9CEB418F, + 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, + 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, + 0xEC0E7779, 0x4744EAD4, 0xB11C3274, + 0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, + 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, + 0xD47C27AF, 0x51C85F4D, 0x56907596, + 0xA5BB15E6, 0x580304F0, 0xCA042CF1, + 0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, + 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, + 0x98A52666, 0x5648F725, 0xFF5E569D, + 0x0CED63D0, 0x7C63B2CF, 0x700B45E1, + 0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, + 0xD4234870, 0xA7870BF3, 0x2D3B4D79, + 0x42E04198, 0x0CD0EDE7, 0x26470DB8, + 0xF881814C, 0x474D6AD7, 0x7C0C5E5C, + 0xD1231959, 0x381B7298, 0xF5D2F4DB, + 0xAB838653, 0x6E2F1E23, 0x83719C9E, + 0xBD91E046, 0x9A56456E, 0xDC39200C, + 0x20C8C571, 0x962BDA1C, 0xE1E696FF, + 0xB141AB08, 0x7CCA89B9, 0x1A69E783, + 0x02CC4843, 0xA2F7C579, 0x429EF47D, + 0x427B169C, 0x5AC9F049, 0xDD8F0F00, + 0x5C8165BF }; + + private static final int[] S2 = { 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, + 0x393F4380, 0xFE61CF7A, 0xEEC5207A, + 0x55889C94, 0x72FC0651, 0xADA7EF79, + 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, + 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, + 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605, + 0xEE15B094, 0xE9FFD909, 0xDC440086, + 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, + 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, + 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B, + 0x25A1FF41, 0xE180F806, 0x1FC41080, + 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, + 0x98DE8B7F, 0x77E83F4E, 0x79929269, + 0x24FA9F7B, 0xE113C85B, 0xACC40083, + 0xD7503525, 0xF7EA615F, 0x62143154, + 0x0D554B63, 0x5D681121, 0xC866C359, + 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, + 0x5C672B21, 0x071F6181, 0x39F7627F, + 0x361E3084, 0xE4EB573B, 0x602F64A4, + 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, + 0x2701F50C, 0x99847AB4, 0xA0E3DF79, + 0xBA6CF38C, 0x10843094, 0x2537A95E, + 0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, + 0x8F458C74, 0xD9E0A227, 0x4EC73A34, + 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, + 0x3559648D, 0x8A45388C, 0x1D804366, + 0x721D9BFD, 0xA58684BB, 0xE8256333, + 0x844E8212, 0x128D8098, 0xFED33FB4, + 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, + 0xE49754BD, 0xC5D655DD, 0xEB667064, + 0x77840B4D, 0xA1B6A801, 0x84DB26A9, + 0xE0B56714, 0x21F043B7, 0xE5D05860, + 0x54F03084, 0x066FF472, 0xA31AA153, + 0xDADC4755, 0xB5625DBF, 0x68561BE6, + 0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, + 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, + 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, + 0x5F0E5304, 0x81ED6F61, 0x20E74364, + 0xB45E1378, 0xDE18639B, 0x881CA122, + 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, + 0x5E552D25, 0x5272D237, 0x79D2951C, + 0xC60D894C, 0x488CB402, 0x1BA4FE5B, + 0xA4B09F6B, 0x1CA815CF, 0xA20C3005, + 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, + 0x0BEEFF53, 0xE3214517, 0xB4542835, + 0x9F63293C, 0xEE41E729, 0x6E1D2D7C, + 0x50045286, 0x1E6685F3, 0xF33401C6, + 0x30A22C95, 0x31A70850, 0x60930F13, + 0x73F98417, 0xA1269859, 0xEC645C44, + 0x52C877A9, 0xCDFF33A6, 0xA02B1741, + 0x7CBAD9A2, 0x2180036F, 0x50D99C08, + 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, + 0x80342676, 0x25A75E7B, 0xE4E6D1FC, + 0x20C710E6, 0xCDF0B680, 0x17844D3B, + 0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, + 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, + 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, + 0x30F66F43, 0xB3FAEC54, 0x157FD7FA, + 0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, + 0x8F32CE19, 0x306AF97A, 0x02F03EF8, + 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, + 0xC68E4906, 0xB8DA230C, 0x80823028, + 0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, + 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, + 0xC72FEFFA, 0x22822E99, 0x82C570B4, + 0xD8D94E89, 0x8B1C34BC, 0x301E16E6, + 0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, + 0x00B24869, 0xB7FFCE3F, 0x08DC283B, + 0x43DAF65A, 0xF7E19798, 0x7619B72F, + 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1, + 0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, + 0x1A513742, 0xEF6828BC, 0x520365D6, + 0x2D6A77AB, 0x3527ED4B, 0x821FD216, + 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB, + 0x145892F5, 0x91584F7F, 0x5483697B, + 0x2667A8CC, 0x85196048, 0x8C4BACEA, + 0x833860D4, 0x0D23E0F9, 0x6C387E8A, + 0x0AE6D249, 0xB284600C, 0xD835731D, + 0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, + 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, + 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, + 0x4FB089BD, 0x649DA589, 0xA345415E, + 0x5C038323, 0x3E5D3BB9, 0x43D79572, + 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, + 0x7160A539, 0x73BFBE70, 0x83877605, + 0x4523ECF1 }; + + private static final int[] S3 = { 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, + 0xE810C907, 0x47607FFF, 0x369FE44B, + 0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, + 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, + 0x920E8806, 0xF0AD0548, 0xE13C8D83, + 0x927010D5, 0x11107D9F, 0x07647DB9, + 0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, + 0xFADE82E0, 0xA067268B, 0x8272792E, + 0x553FB2C0, 0x489AE22B, 0xD4EF9794, + 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD, + 0x9255C5ED, 0x1257A240, 0x4E1A8302, + 0xBAE07FFF, 0x528246E7, 0x8E57140E, + 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, + 0xC982B5A5, 0xA8C01DB7, 0x579FC264, + 0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, + 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, + 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, + 0x55819D99, 0xA197C81C, 0x4A012D6E, + 0xC5884A28, 0xCCC36F71, 0xB843C213, + 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, + 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, + 0x5AFB9A04, 0xA747D2D0, 0x1651192E, + 0xAF70BF3E, 0x58C31380, 0x5F98302E, + 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, + 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, + 0x50DA88B8, 0x8427F4A0, 0x1EAC5790, + 0x796FB449, 0x8252DC15, 0xEFBD7D9B, + 0xA672597D, 0xADA840D8, 0x45F54504, + 0xFA5D7403, 0xE83EC305, 0x4F91751A, + 0x925669C2, 0x23EFE941, 0xA903F12E, + 0x60270DF2, 0x0276E4B6, 0x94FD6574, + 0x927985B2, 0x8276DBCB, 0x02778176, + 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, + 0xE29D840E, 0x842F7D83, 0x340CE5C8, + 0x96BBB682, 0x93B4B148, 0xEF303CAB, + 0x984FAF28, 0x779FAF9B, 0x92DC560D, + 0x224D1E20, 0x8437AA88, 0x7D29DC96, + 0x2756D3DC, 0x8B907CEE, 0xB51FD240, + 0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, + 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, + 0x5C76460E, 0x00EA983B, 0xD4D67881, + 0xFD47572C, 0xF76CEDD9, 0xBDA8229C, + 0x127DADAA, 0x438A074E, 0x1F97C090, + 0x081BDB8A, 0x93A07EBE, 0xB938CA15, + 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, + 0x64380E51, 0x68CC7BFB, 0xD90F2788, + 0x12490181, 0x5DE5FFD4, 0xDD7EF86A, + 0x76A2E214, 0xB9A40368, 0x925D958F, + 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, + 0xFAF7933B, 0x6D498623, 0x193CBCFA, + 0x27627545, 0x825CF47A, 0x61BD8BA0, + 0xD11E42D1, 0xCEAD04F4, 0x127EA392, + 0x10428DB7, 0x8272A972, 0x9270C4A8, + 0x127DE50B, 0x285BA1C8, 0x3C62F44F, + 0x35C0EAA5, 0xE805D231, 0x428929FB, + 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, + 0x1F081FAB, 0x108618AE, 0xFCFD086D, + 0xF9FF2889, 0x694BCC11, 0x236A5CAE, + 0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, + 0xF8EF5896, 0xE4CF52DA, 0x95155B67, + 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, + 0x89D36B45, 0x3A609437, 0xEC00C9A9, + 0x44715253, 0x0A874B49, 0xD773BC40, + 0x7C34671C, 0x02717EF6, 0x4FEB5536, + 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, + 0x50B4EF6D, 0x07478CD1, 0x006E1888, + 0xA2E53F55, 0xB9E6D4BC, 0xA2048016, + 0x97573833, 0xD7207D67, 0xDE0F8F3D, + 0x72F87B33, 0xABCC4F33, 0x7688C55D, + 0x7B00A6B0, 0x947B0001, 0x570075D2, + 0xF9BB88F8, 0x8942019E, 0x4264A5FF, + 0x856302E0, 0x72DBD92B, 0xEE971B69, + 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, + 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2, + 0xF1AC2571, 0xCC8239C2, 0x67214CB8, + 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, + 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, + 0x60543A49, 0x5727C148, 0x2BE98A1D, + 0x8AB41738, 0x20E1BE24, 0xAF96DA0F, + 0x68458425, 0x99833BE5, 0x600D457D, + 0x282F9350, 0x8334B362, 0xD91D1120, + 0x2B6D8DA0, 0x642B1E31, 0x9C305A00, + 0x52BCE688, 0x1B03588A, 0xF7BAEFD5, + 0x4142ED9C, 0xA4315C11, 0x83323EC5, + 0xDFEF4636, 0xA133C501, 0xE9D3531C, + 0xEE353783 }; + + private static final int[] S4 = { 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, + 0xD273A298, 0x4A4F7BDB, 0x64AD8C57, + 0x85510443, 0xFA020ED1, 0x7E287AFF, + 0xE60FB663, 0x095F35A1, 0x79EBF120, + 0xFD059D43, 0x6497B7B1, 0xF3641F63, + 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD, + 0xC9430040, 0x0CC32220, 0xFDD30B30, + 0xC0A5374F, 0x1D2D00D9, 0x24147B15, + 0xEE4D111A, 0x0FCA5167, 0x71FF904C, + 0x2D195FFE, 0x1A05645F, 0x0C13FEFE, + 0x081B08CA, 0x05170121, 0x80530100, + 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, + 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, + 0x7293EA25, 0xCE84FFDF, 0xF5718801, + 0x3DD64B04, 0xA26F263B, 0x7ED48400, + 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, + 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, + 0x503F7E93, 0xD3772061, 0x11B638E1, + 0x72500E03, 0xF80EB2BB, 0xABE0502E, + 0xEC8D77DE, 0x57971E81, 0xE14F6746, + 0xC9335400, 0x6920318F, 0x081DBB99, + 0xFFC304A5, 0x4D351805, 0x7F3D5CE3, + 0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, + 0x9F926F91, 0x9F46222F, 0x3991467D, + 0xA5BF6D8E, 0x1143C44F, 0x43958302, + 0xD0214EEB, 0x022083B8, 0x3FB6180C, + 0x18F8931E, 0x281658E6, 0x26486E3E, + 0x8BD78A70, 0x7477E4C1, 0xB506E07C, + 0xF32D0A25, 0x79098B02, 0xE4EABB81, + 0x28123B23, 0x69DEAD38, 0x1574CA16, + 0xDF871B62, 0x211C40B7, 0xA51A9EF9, + 0x0014377B, 0x041E8AC8, 0x09114003, + 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, + 0x2F91A340, 0x557BE8DE, 0x00EAE4A7, + 0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, + 0xDD3369AC, 0xEC17B035, 0x06572327, + 0x99AFC8B0, 0x56C8C391, 0x6B65811C, + 0x5E146119, 0x6E85CB75, 0xBE07C002, + 0xC2325577, 0x893FF4EC, 0x5BBFC92D, + 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, + 0x20C763EF, 0xC366A5FC, 0x9C382880, + 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7, + 0x041AFA32, 0x1D16625A, 0x6701902C, + 0x9B757A54, 0x31D477F7, 0x9126B031, + 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, + 0x56E55A79, 0x026A4CEB, 0x52437EFF, + 0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, + 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, + 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, + 0x2E096B7C, 0x1741A254, 0xE5B6A035, + 0x213D42F6, 0x2C1C7C26, 0x61C2F50F, + 0x6552DAF9, 0xD2C231F8, 0x25130F69, + 0xD8167FA2, 0x0418F2C8, 0x001A96A6, + 0x0D1526AB, 0x63315C21, 0x5E0A72EC, + 0x49BAFEFD, 0x187908D9, 0x8D0DBD86, + 0x311170A7, 0x3E9B640C, 0xCC3E10D7, + 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, + 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E, + 0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, + 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, + 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, + 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6, + 0xD01EE900, 0x24ADFFC2, 0xF4990FC5, + 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, + 0x109873F6, 0x00613096, 0xC32D9521, + 0xADA121FF, 0x29908415, 0x7FBB977F, + 0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, + 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, + 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, + 0x015F1919, 0x77079103, 0xDEA03AF6, + 0x78A8565E, 0xDEE356DF, 0x21F05CBE, + 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, + 0xD8EEB6D2, 0xE523BE77, 0xC2154529, + 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2, + 0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, + 0x1FDA8538, 0x1987832F, 0xCA007367, + 0xA99144F8, 0x296B299E, 0x492FC295, + 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA, + 0xDF7E052F, 0xDB25701C, 0x1B5E51EE, + 0xF65324E6, 0x6AFCE36C, 0x0316CC04, + 0x8644213E, 0xB7DC59D0, 0x7965291F, + 0xCCD6FD43, 0x41823979, 0x932BCDF6, + 0xB657C34D, 0x4EDFD282, 0x7AE5290C, + 0x3CB9536B, 0x851E20FE, 0x9833557E, + 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, + 0x0AEF7ED2 }; + + private static final int[] S5 = { 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, + 0xA6337911, 0xB86A7FFF, 0x1DD358F5, + 0x44DD9D44, 0x1731167F, 0x08FBF1FA, + 0xE7F511CC, 0xD2051B00, 0x735ABA00, + 0x2AB722D8, 0x386381CB, 0xACF6243A, + 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD, + 0xC4494816, 0xCCF5C180, 0x38851640, + 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, + 0x5F480A01, 0x0412B2AA, 0x259814FC, + 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB, + 0x8DBA1CFE, 0x41A99B02, 0x1A550A04, + 0xBA8F65CB, 0x7251F4E7, 0x95A51725, + 0xC106ECD7, 0x97A5980A, 0xC539B9AA, + 0x4D79FE6A, 0xF2F3F763, 0x68AF8040, + 0xED0C9E56, 0x11B4958B, 0xE1EB5A88, + 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, + 0x6366E52D, 0x02D1C000, 0xC4AC8E05, + 0x9377F571, 0x0C05372A, 0x578535F2, + 0x2261BE02, 0xD642A0C9, 0xDF13A280, + 0x74B55BD2, 0x682199C0, 0xD421E5EC, + 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, + 0x3D959981, 0x5C1FF900, 0xFE38D399, + 0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, + 0x4FB96976, 0x90C79505, 0xB0A8A774, + 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, + 0xE66A4263, 0xDF65001F, 0x0EC50966, + 0xDFDD55BC, 0x29DE0655, 0x911E739A, + 0x17AF8975, 0x32C7911C, 0x89F89468, + 0x0D01E980, 0x524755F4, 0x03B63CC9, + 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9, + 0xE53A7426, 0x01B3D82B, 0x1A9E7449, + 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, + 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, + 0x04A5C284, 0x636737B6, 0x50F5B616, + 0xF24766E3, 0x8ECA36C1, 0x136E05DB, + 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, + 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, + 0xEC2941DA, 0x26E46695, 0xB7566419, + 0xF654EFC5, 0xD08D58B7, 0x48925401, + 0xC1BACB7F, 0xE5FF550F, 0xB6083049, + 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, + 0x223A66CE, 0xC62BF3CD, 0x9E0885F9, + 0x68CB3E47, 0x086C010F, 0xA21DE820, + 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, + 0x407EDAC3, 0xCBB3D550, 0x1793084D, + 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C, + 0xDED7DA56, 0x4124BBE4, 0x94CA0B56, + 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, + 0x580A249F, 0x94F74BC0, 0xE327888E, + 0x9F7B5561, 0xC3DC0280, 0x05687715, + 0x646C6BD7, 0x44904DB3, 0x66B4F0A3, + 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, + 0x309E374F, 0x2CB6356A, 0x85808573, + 0x4991F840, 0x76F0AE02, 0x083BE84D, + 0x28421C9A, 0x44489406, 0x736E4CB8, + 0xC1092910, 0x8BC95FC6, 0x7D869CF4, + 0x134F616F, 0x2E77118D, 0xB31B2BE1, + 0xAA90B472, 0x3CA5D717, 0x7D161BBA, + 0x9CAD9010, 0xAF462BA2, 0x9FE459D2, + 0x45D34559, 0xD9F2DA13, 0xDBC65487, + 0xF3E4F94E, 0x176D486F, 0x097C13EA, + 0x631DA5C7, 0x445F7382, 0x175683F4, + 0xCDC66A97, 0x70BE0288, 0xB3CDCF72, + 0x6E5DD2F3, 0x20936079, 0x459B80A5, + 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, + 0x224E42F2, 0x1C5C1572, 0xF6721B2C, + 0x1AD2FFF3, 0x8C25404E, 0x324ED72F, + 0x4067B7FD, 0x0523138E, 0x5CA3BC78, + 0xDC0FD66E, 0x75922283, 0x784D6B17, + 0x58EBB16E, 0x44094F85, 0x3F481D87, + 0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, + 0xAAF47556, 0x5F46B02A, 0x2B092801, + 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, + 0x66D5E7C0, 0xDF3B0874, 0x95055110, + 0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, + 0x20758184, 0xD0CEFA65, 0x88F7BE58, + 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, + 0x5346ABA0, 0x5CE96C28, 0xE176EDA3, + 0x6BAC307F, 0x376829D2, 0x85360FA9, + 0x17E3FE2A, 0x24B79767, 0xF5A96B20, + 0xD6CD2595, 0x68FF1EBF, 0x7555442C, + 0xF19F06BE, 0xF9E0659A, 0xEEB9491D, + 0x34010718, 0xBB30CAB8, 0xE822FE15, + 0x88570983, 0x750E6249, 0xDA627E55, + 0x5E76FFA8, 0xB1534546, 0x6D47DE08, + 0xEFE9E7D4 }; + + private static final int[] S6 = { 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, + 0xE2337F7C, 0x95DB08E7, 0x016843B4, + 0xECED5CBC, 0x325553AC, 0xBF9F0960, + 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, + 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, + 0x8989B138, 0x33F14961, 0xC01937BD, + 0xF506C6DA, 0xE4625E7E, 0xA308EA99, + 0x4E23E33C, 0x79CBD7CC, 0x48A14367, + 0xA3149619, 0xFEC94BD5, 0xA114174A, + 0xEAA01866, 0xA084DB2D, 0x09A8486F, + 0xA888614A, 0x2900AF98, 0x01665991, + 0xE1992863, 0xC8F30C60, 0x2E78EF3C, + 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, + 0xD0A82072, 0xFD41197E, 0x9305A6B0, + 0xE86BE3DA, 0x74BED3CD, 0x372DA53C, + 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, + 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, + 0x4E670C53, 0x5C3D9C01, 0x64BDB941, + 0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, + 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, + 0xF0D48D8C, 0xB88153E2, 0x08A19866, + 0x1AE2EAC8, 0x284CAF89, 0xAA928223, + 0x9334BE53, 0x3B3A21BF, 0x16434BE3, + 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, + 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, + 0xA694A807, 0x5B7C5ECC, 0x221DB3A6, + 0x9A69A02F, 0x68818A54, 0xCEB2296F, + 0x53C0843A, 0xFE893655, 0x25BFE68A, + 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, + 0xA9A99387, 0x53BDDB65, 0xE76FFBE7, + 0xE967FD78, 0x0BA93563, 0x8E342BC1, + 0xE8A11BE9, 0x4980740D, 0xC8087DFC, + 0x8DE4BF99, 0xA11101A0, 0x7FD37975, + 0xDA5A26C0, 0xE81F994F, 0x9528CD89, + 0xFD339FED, 0xB87834BF, 0x5F04456D, + 0x22258698, 0xC9C4C83B, 0x2DC156BE, + 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, + 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0, + 0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, + 0xA8DC8AF0, 0x7345C106, 0xF41E232F, + 0x35162386, 0xE6EA8926, 0x3333B094, + 0x157EC6F2, 0x372B74AF, 0x692573E4, + 0xE9A9D848, 0xF3160289, 0x3A62EF1D, + 0xA787E238, 0xF3A5F676, 0x74364853, + 0x20951063, 0x4576698D, 0xB6FAD407, + 0x592AF950, 0x36F73523, 0x4CFB6E87, + 0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, + 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, + 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, + 0x754613C9, 0x2B05D08D, 0x48B9D585, + 0xDC049441, 0xC8098F9B, 0x7DEDE786, + 0xC39A3373, 0x42410005, 0x6A091751, + 0x0EF3C8A6, 0x890072D6, 0x28207682, + 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75, + 0xB353FD00, 0xCBB0E358, 0x830F220A, + 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, + 0x8CF63166, 0x061C87BE, 0x88C98F88, + 0x6062E397, 0x47CF8E7A, 0xB6C85283, + 0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, + 0x64D8314D, 0xDA3870E3, 0x1E665459, + 0xC10908F0, 0x513021A5, 0x6C5B68B7, + 0x822F8AA0, 0x3007CD3E, 0x74719EEF, + 0xDC872681, 0x073340D4, 0x7E432FD9, + 0x0C5EC241, 0x8809286C, 0xF592D891, + 0x08A930F6, 0x957EF305, 0xB7FBFFBD, + 0xC266E96F, 0x6FE4AC98, 0xB173ECC0, + 0xBC60B42A, 0x953498DA, 0xFBA1AE12, + 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, + 0xE2969123, 0x257F0C3D, 0x9348AF49, + 0x361400BC, 0xE8816F4A, 0x3814F200, + 0xA3F94043, 0x9C7A54C2, 0xBC704F57, + 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, + 0xB17F5505, 0x59357CBE, 0xEDBD15C8, + 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF, + 0x3A479C3A, 0x5302DA25, 0x653D7E6A, + 0x54268D49, 0x51A477EA, 0x5017D55B, + 0xD7D25D88, 0x44136C76, 0x0404A8C8, + 0xB8E5A121, 0xB81A928A, 0x60ED5869, + 0x97C55B96, 0xEAEC991B, 0x29935913, + 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, + 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, + 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB, + 0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, + 0x49C92F54, 0x38B5F331, 0x7128A454, + 0x48392905, 0xA65B1DB8, 0x851C97BD, + 0xD675CF2F }; + + private static final int[] S7 = { 0x85E04019, 0x332BF567, 0x662DBFFF, + 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912, + 0xDE6008A1, 0x2028DA1F, 0x0227BCE7, + 0x4D642916, 0x18FAC300, 0x50F18B82, + 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, + 0xB28707DE, 0xA05FBCF6, 0xCD4181E9, + 0xE150210C, 0xE24EF1BD, 0xB168C381, + 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, + 0x4D495001, 0x38BE4341, 0x913CEE1D, + 0x92A79C3F, 0x089766BE, 0xBAEEADF4, + 0x1286BECF, 0xB6EACB19, 0x2660C200, + 0x7565BDE4, 0x64241F7A, 0x8248DCA9, + 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, + 0x356D1CF2, 0x107789BE, 0xB3B2E9CE, + 0x0502AA8F, 0x0BC0351E, 0x166BF52A, + 0xEB12FF82, 0xE3486911, 0xD34D7516, + 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, + 0x4981AC83, 0x334266CE, 0x8C9341B7, + 0xD0D854C0, 0xCB3A6C88, 0x47BC2829, + 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, + 0x0C5CBAFA, 0x4437F107, 0xB6E79962, + 0x42D2D816, 0x0A961288, 0xE1A5C06E, + 0x13749E67, 0x72FC081A, 0xB1D139F7, + 0xF9583745, 0xCF19DF58, 0xBEC3F756, + 0xC06EBA30, 0x07211B24, 0x45C28829, + 0xC95E317F, 0xBC8EC511, 0x38BC46E9, + 0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, + 0x468F508B, 0x7829435F, 0xF124183B, + 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, + 0x16E39264, 0x92544A8B, 0x009B4FC3, + 0xABA68CED, 0x9AC96F78, 0x06A5B79A, + 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, + 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, + 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C, + 0x16746233, 0x3C034C28, 0xDA6D0C74, + 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, + 0x98F8F35A, 0x1626A49F, 0xEED82B29, + 0x1D382FE3, 0x0C4FB99A, 0xBB325778, + 0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, + 0xD45230C7, 0x2BD1408B, 0x60C03EB7, + 0xB9068D78, 0xA33754F4, 0xF430C87D, + 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE, + 0xBE8B9D2D, 0x7979FB06, 0xE7225308, + 0x8B75CF77, 0x11EF8DA4, 0xE083C858, + 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, + 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310, + 0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, + 0x79D34217, 0x021A718D, 0x9AC6336A, + 0x2711FD60, 0x438050E3, 0x069908A8, + 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476, + 0x488DCF25, 0x36C9D566, 0x28E74E41, + 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, + 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, + 0x9EA80509, 0xF22B017D, 0xA4173F70, + 0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, + 0x2B9F4FD5, 0x625ABA82, 0x6A017962, + 0x2EC01B9C, 0x15488AA9, 0xD716E740, + 0x40055A2C, 0x93D29A22, 0xE32DBF9A, + 0x058745B9, 0x3453DC1E, 0xD699296E, + 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, + 0xB87242D1, 0x19DE7EAE, 0x053E561A, + 0x15AD6F8C, 0x66626C1C, 0x7154C24C, + 0xEA082B2A, 0x93EB2939, 0x17DCB0F0, + 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, + 0x9883FE66, 0x2EC40581, 0x763953C3, + 0x01D6692E, 0xD3A0C108, 0xA1E7160E, + 0xE4F2DFA6, 0x693ED285, 0x74904698, + 0x4C2B0EDD, 0x4F757656, 0x5D393378, + 0xA132234F, 0x3D321C5D, 0xC3F5E194, + 0x4B269301, 0xC79F022F, 0x3C997E7E, + 0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, + 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, + 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, + 0x4E72B567, 0x5592A33D, 0xB5229301, + 0xCFD2A87F, 0x60AEB767, 0x1814386B, + 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, + 0xC363519B, 0x589DD390, 0x5479F8E6, + 0x1CB8D647, 0x97FD61A9, 0xEA7759F4, + 0x2D57539D, 0x569A58CF, 0xE84E63AD, + 0x462E1B78, 0x6580F87E, 0xF3817914, + 0x91DA55F4, 0x40A230F3, 0xD1988F35, + 0xB6E318D2, 0x3FFA50BC, 0x3D40F021, + 0xC3C0BDAE, 0x4958C24C, 0x518F36B2, + 0x84B1D370, 0x0FEDCE83, 0x878DDADA, + 0xF2A279C7, 0x94E01BE8, 0x90716F4B, + 0x954B8AA3 }; + + private static final int[] S8 = { 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, + 0x35648095, 0x7789F8B7, 0xE6C1121B, + 0x0E241600, 0x052CE8B5, 0x11A9CFB0, + 0xE5952F11, 0xECE7990A, 0x9386D174, + 0x2A42931C, 0x76E38111, 0xB12DEF3A, + 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C, + 0xBE197029, 0x84A00940, 0xBB243A0F, + 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, + 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, + 0x669DED42, 0xC7ECE831, 0x3F8F95E7, + 0x72DF191B, 0x7580330D, 0x94074251, + 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, + 0xB301D40A, 0x02E7D1CA, 0x53571DAE, + 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D, + 0x176F43E8, 0x71FB46D4, 0x38129022, + 0xCE949AD4, 0xB84769AD, 0x965BD862, + 0x82F3D055, 0x66FB9767, 0x15B80B4E, + 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8, + 0x57E8726E, 0x647A78FC, 0x99865D44, + 0x608BD593, 0x6C200E03, 0x39DC5FF6, + 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, + 0x70108C0C, 0xBBD35049, 0x2998DF04, + 0x980CF42A, 0x9B6DF491, 0x9E7EDD53, + 0x06918548, 0x58CB7E07, 0x3B74EF2E, + 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, + 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38, + 0x424F7618, 0x35856039, 0x9D17DEE7, + 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, + 0x09C467CD, 0xC18910B1, 0xE11DBF7B, + 0x06CD1AF8, 0x7170C608, 0x2D5E3354, + 0xD4DE495A, 0x64C6D006, 0xBCC0C62C, + 0x3DD00DB3, 0x708F8F34, 0x77D51B42, + 0x264F620F, 0x24B8D2BF, 0x15C1B79E, + 0x46A52564, 0xF8D7E54E, 0x3E378160, + 0x7895CDA5, 0x859C15A5, 0xE6459788, + 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, + 0x7F229B1E, 0x31842E7B, 0x24259FD7, + 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2, + 0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, + 0xE2506D3D, 0x4F9B12EA, 0xF215F225, + 0xA223736F, 0x9FB4C428, 0x25D04979, + 0x34C713F8, 0xC4618187, 0xEA7A6E98, + 0x7CD16EFC, 0x1436876C, 0xF1544107, + 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, + 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, + 0x151682EB, 0xA842EEDF, 0xFDBA60B4, + 0xF1907B75, 0x20E3030F, 0x24D8C29E, + 0xE139673B, 0xEFA63FB8, 0x71873054, + 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, + 0xB01A4504, 0xF1E47D8D, 0x844A1BE5, + 0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, + 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, + 0xCEA4D428, 0x79D130A4, 0x3486EBFB, + 0x33D3CDDC, 0x77853B53, 0x37EFFCB5, + 0xC5068778, 0xE580B3E6, 0x4E68B8F4, + 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, + 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, + 0x223613BD, 0xDD06CAA2, 0x37DF932B, + 0xC4248289, 0xACF3EBC3, 0x5715F6B7, + 0xEF3478DD, 0xF267616F, 0xC148CBE4, + 0x9052815E, 0x5E410FAB, 0xB48A2465, + 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084, + 0x5889E9E1, 0xEFD390FC, 0xDD07D35B, + 0xDB485694, 0x38D7E5B2, 0x57720101, + 0x730EDEBC, 0x5B643113, 0x94917E4F, + 0x503C2FBA, 0x646F1282, 0x7523D24A, + 0xE0779695, 0xF9C17A8F, 0x7A5B2121, + 0xD187B896, 0x29263A4D, 0xBA510CDF, + 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, + 0x1A00726E, 0x11403092, 0x00DA6D77, + 0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, + 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, + 0xA0E736A0, 0x5564A6B9, 0x10853209, + 0xC7EB8F37, 0x2DE705CA, 0x8951570F, + 0xDF09822B, 0xBD691A6C, 0xAA12E4F2, + 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, + 0x4CF1764F, 0x0D771C2B, 0x67CDB156, + 0x350D8384, 0x5938FA0F, 0x42399EF3, + 0x36997B07, 0x0E84093D, 0x4AA93E61, + 0x8360D87B, 0x1FA98B0C, 0x1149382C, + 0xE97625A5, 0x0614D1B7, 0x0E25244B, + 0x0C768347, 0x589E8D82, 0x0D2059D1, + 0xA466BB1E, 0xF8DA0A82, 0x04F19130, + 0xBA6E4EC0, 0x99265164, 0x1EE7230D, + 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, + 0xEA8BF59E }; + + private static final int _12_ROUNDS = 12; + + private static final int _16_ROUNDS = 16; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Cast5() + { + super(Registry.CAST5_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * Assuming the input is a 32-bit block organised as: b31b30b29...b0, this + * method returns an array of 4 Java ints, containing from position 0 onward + * the values: {b31b30b29b28, b27b26b25b24, ... , b3b2b1b0}. + * + * @param x a 32-bit block. + * @return an array of 4 ints, each being the contents of an 8-bit block from + * the input. + */ + private static final int[] unscramble(int x) + { + return new int[] { x >>> 24, (x >>> 16) & 0xFF, (x >>> 8) & 0xFF, x & 0xFF }; + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Cast5 result = new Cast5(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 5; n < 17; n++) + { + al.add(new Integer(n)); + } + + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + if (uk == null) + { + throw new InvalidKeyException("Empty key"); + } + int len = uk.length; + if (len < 5 || len > 16) + { + throw new InvalidKeyException( + "Key size (in bytes) is not in the range [5..16]"); + } + + Cast5Key result = new Cast5Key(); + result.rounds = (len < 11) ? _12_ROUNDS : _16_ROUNDS; + byte[] kk = new byte[16]; + System.arraycopy(uk, 0, kk, 0, len); + + int z0z1z2z3, z4z5z6z7, z8z9zAzB, zCzDzEzF; + int z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, zA, zB, zC, zD, zE, zF; + int x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xA, xB, xC, xD, xE, xF; + int[] b; + + int x0x1x2x3 = kk[0] << 24 | (kk[1] & 0xFF) << 16 | (kk[2] & 0xFF) << 8 + | (kk[3] & 0xFF); + int x4x5x6x7 = kk[4] << 24 | (kk[5] & 0xFF) << 16 | (kk[6] & 0xFF) << 8 + | (kk[7] & 0xFF); + int x8x9xAxB = kk[8] << 24 | (kk[9] & 0xFF) << 16 | (kk[10] & 0xFF) << 8 + | (kk[11] & 0xFF); + int xCxDxExF = kk[12] << 24 | (kk[13] & 0xFF) << 16 | (kk[14] & 0xFF) << 8 + | (kk[15] & 0xFF); + + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + + result.Km0 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]; + result.Km1 = S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6]; + result.Km2 = S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9]; + result.Km3 = S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC]; + + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + + result.Km4 = S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8]; + result.Km5 = S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD]; + result.Km6 = S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3]; + result.Km7 = S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7]; + + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + + result.Km8 = S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9]; + result.Km9 = S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC]; + result.Km10 = S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2]; + result.Km11 = S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6]; + + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + + result.Km12 = S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3]; + result.Km13 = S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7]; + result.Km14 = S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8]; + result.Km15 = S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD]; + + // The remaining half is identical to what is given above, carrying on + // from the last created x0..xF to generate keys K17 - K32. These keys + // will be used as the 'rotation' keys and as such only the five least + // significant bits are to be considered. + + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + + result.Kr0 = (S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]) & 0x1F; + result.Kr1 = (S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6]) & 0x1F; + result.Kr2 = (S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9]) & 0x1F; + result.Kr3 = (S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC]) & 0x1F; + + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + + result.Kr4 = (S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8]) & 0x1F; + result.Kr5 = (S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD]) & 0x1F; + result.Kr6 = (S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3]) & 0x1F; + result.Kr7 = (S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7]) & 0x1F; + + z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]; + b = unscramble(z0z1z2z3); + z0 = b[0]; + z1 = b[1]; + z2 = b[2]; + z3 = b[3]; + z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA]; + b = unscramble(z4z5z6z7); + z4 = b[0]; + z5 = b[1]; + z6 = b[2]; + z7 = b[3]; + z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9]; + b = unscramble(z8z9zAzB); + z8 = b[0]; + z9 = b[1]; + zA = b[2]; + zB = b[3]; + zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB]; + b = unscramble(zCzDzEzF); + zC = b[0]; + zD = b[1]; + zE = b[2]; + zF = b[3]; + + result.Kr8 = (S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9]) & 0x1F; + result.Kr9 = (S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC]) & 0x1F; + result.Kr10 = (S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2]) & 0x1F; + result.Kr11 = (S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6]) & 0x1F; + + x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0]; + b = unscramble(x0x1x2x3); + x0 = b[0]; + x1 = b[1]; + x2 = b[2]; + x3 = b[3]; + x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2]; + b = unscramble(x4x5x6x7); + x4 = b[0]; + x5 = b[1]; + x6 = b[2]; + x7 = b[3]; + x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1]; + b = unscramble(x8x9xAxB); + x8 = b[0]; + x9 = b[1]; + xA = b[2]; + xB = b[3]; + xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3]; + b = unscramble(xCxDxExF); + xC = b[0]; + xD = b[1]; + xE = b[2]; + xF = b[3]; + + result.Kr12 = (S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3]) & 0x1F; + result.Kr13 = (S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7]) & 0x1F; + result.Kr14 = (S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8]) & 0x1F; + result.Kr15 = (S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD]) & 0x1F; + + return result; + } + + /** + *

The full encryption algorithm is given in the following four steps.

+ * + *
+   *    INPUT:  plaintext m1...m64; key K = k1...k128.
+   *    OUTPUT: ciphertext c1...c64.
+   * 
+ * + *
    + *
  1. (key schedule) Compute 16 pairs of subkeys {Kmi, Kri} from a user + * key (see makeKey() method).
  2. + *
  3. (L0,R0) <-- (m1...m64). (Split the plaintext into left and right + * 32-bit halves L0 = m1...m32 and R0 = m33...m64.).
  4. + *
  5. (16 rounds) for i from 1 to 16, compute Li and Ri as follows: + *
      + *
    • Li = Ri-1;
    • + *
    • Ri = Li-1 ^ F(Ri-1,Kmi,Kri), where F is defined in method F() -- + * f is of Type 1, Type 2, or Type 3, depending on i, and ^ being the + * bitwise XOR function.
    • + *
    + *
  6. c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and + * concatenate to form the ciphertext.)
  7. + *
+ * + *

Decryption is identical to the encryption algorithm given above, except + * that the rounds (and therefore the subkey pairs) are used in reverse order + * to compute (L0,R0) from (R16,L16).

+ * + *

Looking at the iterations/rounds in pairs we have:

+ * + *
+   *    (1a)    Li = Ri-1;
+   *    (1b)    Ri = Li-1 ^ Fi(Ri-1);
+   *    (2a)    Li+1 = Ri;
+   *    (2b)    Ri+1 = Li ^ Fi+1(Ri);
+   * 
+ * which by substituting (2a) in (2b) becomes + *
+   *    (2c)    Ri+1 = Li ^ Fi+1(Li+1);
+   * 
+ * by substituting (1b) in (2a) and (1a) in (2c), we get: + *
+   *    (3a)    Li+1 = Li-1 ^ Fi(Ri-1);
+   *    (3b)    Ri+1 = Ri-1 ^ Fi+1(Li+1);
+   * 
+ * Using only one couple of variables L and R, initialised to L0 and R0 + * respectively, the assignments for each pair of rounds become: + *
+   *    (4a)    L ^= Fi(R);
+   *    (4b)    R ^= Fi+1(L);
+   * 
+ * + * @param in contains the plain-text 64-bit block. + * @param i start index within input where data is considered. + * @param out will contain the cipher-text block. + * @param j index in out where cipher-text starts. + * @param k the session key object. + * @param bs the desired block size. + */ + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + Cast5Key K = (Cast5Key) k; + + int L = (in[i++] & 0xFF) << 24 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 | in[i++] & 0xFF; + int R = (in[i++] & 0xFF) << 24 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 | in[i] & 0xFF; + + L ^= f1(R, K.Km0, K.Kr0); + R ^= f2(L, K.Km1, K.Kr1); // round 2 + L ^= f3(R, K.Km2, K.Kr2); + R ^= f1(L, K.Km3, K.Kr3); // round 4 + L ^= f2(R, K.Km4, K.Kr4); + R ^= f3(L, K.Km5, K.Kr5); // round 6 + L ^= f1(R, K.Km6, K.Kr6); + R ^= f2(L, K.Km7, K.Kr7); // round 8 + L ^= f3(R, K.Km8, K.Kr8); + R ^= f1(L, K.Km9, K.Kr9); // round 10 + L ^= f2(R, K.Km10, K.Kr10); + R ^= f3(L, K.Km11, K.Kr11); // round 12 + if (K.rounds == _16_ROUNDS) + { + L ^= f1(R, K.Km12, K.Kr12); + R ^= f2(L, K.Km13, K.Kr13); // round 14 + L ^= f3(R, K.Km14, K.Kr14); + R ^= f1(L, K.Km15, K.Kr15); // round 16 + } + + out[j++] = (byte) (R >>> 24); + out[j++] = (byte) (R >>> 16); + out[j++] = (byte) (R >>> 8); + out[j++] = (byte) R; + out[j++] = (byte) (L >>> 24); + out[j++] = (byte) (L >>> 16); + out[j++] = (byte) (L >>> 8); + out[j] = (byte) L; + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + Cast5Key K = (Cast5Key) k; + + int L = (in[i++] & 0xFF) << 24 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 | in[i++] & 0xFF; + int R = (in[i++] & 0xFF) << 24 | (in[i++] & 0xFF) << 16 + | (in[i++] & 0xFF) << 8 | in[i] & 0xFF; + + if (K.rounds == _16_ROUNDS) + { + L ^= f1(R, K.Km15, K.Kr15); + R ^= f3(L, K.Km14, K.Kr14); + L ^= f2(R, K.Km13, K.Kr13); + R ^= f1(L, K.Km12, K.Kr12); + } + L ^= f3(R, K.Km11, K.Kr11); + R ^= f2(L, K.Km10, K.Kr10); + L ^= f1(R, K.Km9, K.Kr9); + R ^= f3(L, K.Km8, K.Kr8); + L ^= f2(R, K.Km7, K.Kr7); + R ^= f1(L, K.Km6, K.Kr6); + L ^= f3(R, K.Km5, K.Kr5); + R ^= f2(L, K.Km4, K.Kr4); + L ^= f1(R, K.Km3, K.Kr3); + R ^= f3(L, K.Km2, K.Kr2); + L ^= f2(R, K.Km1, K.Kr1); + R ^= f1(L, K.Km0, K.Kr0); + + out[j++] = (byte) (R >>> 24); + out[j++] = (byte) (R >>> 16); + out[j++] = (byte) (R >>> 8); + out[j++] = (byte) R; + out[j++] = (byte) (L >>> 24); + out[j++] = (byte) (L >>> 16); + out[j++] = (byte) (L >>> 8); + out[j] = (byte) L; + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + { + result = testKat(KAT_KEY, KAT_CT, KAT_PT); + } + valid = new Boolean(result); + } + return valid.booleanValue(); + } + + // helper methods ---------------------------------------------------------- + + private final int f1(int I, int m, int r) + { + I = m + I; + I = I << r | I >>> (32 - r); + return (((S1[(I >>> 24) & 0xFF]) ^ S2[(I >>> 16) & 0xFF]) - S3[(I >>> 8) & 0xFF]) + + S4[I & 0xFF]; + } + + private final int f2(int I, int m, int r) + { + I = m ^ I; + I = I << r | I >>> (32 - r); + return (((S1[(I >>> 24) & 0xFF]) - S2[(I >>> 16) & 0xFF]) + S3[(I >>> 8) & 0xFF]) + ^ S4[I & 0xFF]; + } + + private final int f3(int I, int m, int r) + { + I = m - I; + I = I << r | I >>> (32 - r); + return (((S1[(I >>> 24) & 0xFF]) + S2[(I >>> 16) & 0xFF]) ^ S3[(I >>> 8) & 0xFF]) + - S4[I & 0xFF]; + } + + // Inner class(es) + // ========================================================================= + + /** An opaque CAST5 key object. */ + private class Cast5Key + { + int rounds; + + /** Masking session keys. */ + int Km0, Km1, Km2, Km3, Km4, Km5, Km6, Km7, Km8, Km9, Km10, Km11, Km12, + Km13, Km14, Km15; + + /** Rotation session keys. */ + int Kr0, Kr1, Kr2, Kr3, Kr4, Kr5, Kr6, Kr7, Kr8, Kr9, Kr10, Kr11, Kr12, + Kr13, Kr14, Kr15; + } +} diff --git a/gnu/javax/crypto/cipher/CipherFactory.java b/gnu/javax/crypto/cipher/CipherFactory.java new file mode 100644 index 000000000..082bfb8fa --- /dev/null +++ b/gnu/javax/crypto/cipher/CipherFactory.java @@ -0,0 +1,169 @@ +/* CipherFactory.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + *

A Factory to instantiate symmetric block cipher instances.

+ */ +public class CipherFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private CipherFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a block cipher given its name.

+ * + * @param name the case-insensitive name of the symmetric-key block cipher + * algorithm. + * @return an instance of the designated cipher algorithm, or + * null if none is found. + * @exception InternalError if the implementation does not pass its + * self-test. + */ + public static final IBlockCipher getInstance(String name) + { + if (name == null) + { + return null; + } + + name = name.trim(); + IBlockCipher result = null; + if (name.equalsIgnoreCase(ANUBIS_CIPHER)) + { + result = new Anubis(); + } + else if (name.equalsIgnoreCase(BLOWFISH_CIPHER)) + { + result = new Blowfish(); + } + else if (name.equalsIgnoreCase(DES_CIPHER)) + { + result = new DES(); + } + else if (name.equalsIgnoreCase(KHAZAD_CIPHER)) + { + result = new Khazad(); + } + else if (name.equalsIgnoreCase(RIJNDAEL_CIPHER) + || name.equalsIgnoreCase(AES_CIPHER)) + { + result = new Rijndael(); + } + else if (name.equalsIgnoreCase(SERPENT_CIPHER)) + { + result = new Serpent(); + } + else if (name.equalsIgnoreCase(SQUARE_CIPHER)) + { + result = new Square(); + } + else if (name.equalsIgnoreCase(TRIPLEDES_CIPHER) + || name.equalsIgnoreCase(DESEDE_CIPHER)) + { + result = new TripleDES(); + } + else if (name.equalsIgnoreCase(TWOFISH_CIPHER)) + { + result = new Twofish(); + } + else if (name.equalsIgnoreCase(CAST5_CIPHER) + || (name.equalsIgnoreCase(CAST128_CIPHER) || (name.equalsIgnoreCase(CAST_128_CIPHER)))) + { + result = new Cast5(); + } + else if (name.equalsIgnoreCase(NULL_CIPHER)) + { + result = new NullCipher(); + } + + if (result != null && !result.selfTest()) + { + throw new InternalError(result.name()); + } + + return result; + } + + /** + *

Returns a {@link Set} of symmetric key block cipher implementation + * names supported by this Factory.

+ * + * @return a {@link Set} of block cipher names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(ANUBIS_CIPHER); + hs.add(BLOWFISH_CIPHER); + hs.add(DES_CIPHER); + hs.add(KHAZAD_CIPHER); + hs.add(RIJNDAEL_CIPHER); + hs.add(SERPENT_CIPHER); + hs.add(SQUARE_CIPHER); + hs.add(TRIPLEDES_CIPHER); + hs.add(TWOFISH_CIPHER); + hs.add(CAST5_CIPHER); + hs.add(NULL_CIPHER); + + return Collections.unmodifiableSet(hs); + } + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/DES.java b/gnu/javax/crypto/cipher/DES.java new file mode 100644 index 000000000..8b7627cea --- /dev/null +++ b/gnu/javax/crypto/cipher/DES.java @@ -0,0 +1,894 @@ +/* DES.java -- + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.Properties; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; + +/** + *

The Data Encryption Standard. DES is a 64-bit block cipher with a 56-bit + * key, developed by IBM in the 1970's for the standardization process begun by + * the National Bureau of Standards (now NIST).

+ * + *

New applications should not use DES except for compatibility.

+ * + *

This version is based upon the description and sample implementation in + * [1].

+ * + *

References:

+ *
    + *
  1. Bruce Schneier, Applied Cryptography: Protocols, Algorithms, and + * Source Code in C, Second Edition. (1996 John Wiley and Sons) ISBN + * 0-471-11709-9. Pages 265--301, 623--632.
  2. + *
+ */ +public class DES extends BaseCipher +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** DES operates on 64 bit blocks. */ + public static final int BLOCK_SIZE = 8; + + /** DES uses 56 bits of a 64 bit parity-adjusted key. */ + public static final int KEY_SIZE = 8; + + // S-Boxes 1 through 8. + private static final int[] SP1 = new int[] { 0x01010400, 0x00000000, + 0x00010000, 0x01010404, + 0x01010004, 0x00010404, + 0x00000004, 0x00010000, + 0x00000400, 0x01010400, + 0x01010404, 0x00000400, + 0x01000404, 0x01010004, + 0x01000000, 0x00000004, + 0x00000404, 0x01000400, + 0x01000400, 0x00010400, + 0x00010400, 0x01010000, + 0x01010000, 0x01000404, + 0x00010004, 0x01000004, + 0x01000004, 0x00010004, + 0x00000000, 0x00000404, + 0x00010404, 0x01000000, + 0x00010000, 0x01010404, + 0x00000004, 0x01010000, + 0x01010400, 0x01000000, + 0x01000000, 0x00000400, + 0x01010004, 0x00010000, + 0x00010400, 0x01000004, + 0x00000400, 0x00000004, + 0x01000404, 0x00010404, + 0x01010404, 0x00010004, + 0x01010000, 0x01000404, + 0x01000004, 0x00000404, + 0x00010404, 0x01010400, + 0x00000404, 0x01000400, + 0x01000400, 0x00000000, + 0x00010004, 0x00010400, + 0x00000000, 0x01010004 }; + + private static final int[] SP2 = new int[] { 0x80108020, 0x80008000, + 0x00008000, 0x00108020, + 0x00100000, 0x00000020, + 0x80100020, 0x80008020, + 0x80000020, 0x80108020, + 0x80108000, 0x80000000, + 0x80008000, 0x00100000, + 0x00000020, 0x80100020, + 0x00108000, 0x00100020, + 0x80008020, 0x00000000, + 0x80000000, 0x00008000, + 0x00108020, 0x80100000, + 0x00100020, 0x80000020, + 0x00000000, 0x00108000, + 0x00008020, 0x80108000, + 0x80100000, 0x00008020, + 0x00000000, 0x00108020, + 0x80100020, 0x00100000, + 0x80008020, 0x80100000, + 0x80108000, 0x00008000, + 0x80100000, 0x80008000, + 0x00000020, 0x80108020, + 0x00108020, 0x00000020, + 0x00008000, 0x80000000, + 0x00008020, 0x80108000, + 0x00100000, 0x80000020, + 0x00100020, 0x80008020, + 0x80000020, 0x00100020, + 0x00108000, 0x00000000, + 0x80008000, 0x00008020, + 0x80000000, 0x80100020, + 0x80108020, 0x00108000 }; + + private static final int[] SP3 = new int[] { 0x00000208, 0x08020200, + 0x00000000, 0x08020008, + 0x08000200, 0x00000000, + 0x00020208, 0x08000200, + 0x00020008, 0x08000008, + 0x08000008, 0x00020000, + 0x08020208, 0x00020008, + 0x08020000, 0x00000208, + 0x08000000, 0x00000008, + 0x08020200, 0x00000200, + 0x00020200, 0x08020000, + 0x08020008, 0x00020208, + 0x08000208, 0x00020200, + 0x00020000, 0x08000208, + 0x00000008, 0x08020208, + 0x00000200, 0x08000000, + 0x08020200, 0x08000000, + 0x00020008, 0x00000208, + 0x00020000, 0x08020200, + 0x08000200, 0x00000000, + 0x00000200, 0x00020008, + 0x08020208, 0x08000200, + 0x08000008, 0x00000200, + 0x00000000, 0x08020008, + 0x08000208, 0x00020000, + 0x08000000, 0x08020208, + 0x00000008, 0x00020208, + 0x00020200, 0x08000008, + 0x08020000, 0x08000208, + 0x00000208, 0x08020000, + 0x00020208, 0x00000008, + 0x08020008, 0x00020200 }; + + private static final int[] SP4 = new int[] { 0x00802001, 0x00002081, + 0x00002081, 0x00000080, + 0x00802080, 0x00800081, + 0x00800001, 0x00002001, + 0x00000000, 0x00802000, + 0x00802000, 0x00802081, + 0x00000081, 0x00000000, + 0x00800080, 0x00800001, + 0x00000001, 0x00002000, + 0x00800000, 0x00802001, + 0x00000080, 0x00800000, + 0x00002001, 0x00002080, + 0x00800081, 0x00000001, + 0x00002080, 0x00800080, + 0x00002000, 0x00802080, + 0x00802081, 0x00000081, + 0x00800080, 0x00800001, + 0x00802000, 0x00802081, + 0x00000081, 0x00000000, + 0x00000000, 0x00802000, + 0x00002080, 0x00800080, + 0x00800081, 0x00000001, + 0x00802001, 0x00002081, + 0x00002081, 0x00000080, + 0x00802081, 0x00000081, + 0x00000001, 0x00002000, + 0x00800001, 0x00002001, + 0x00802080, 0x00800081, + 0x00002001, 0x00002080, + 0x00800000, 0x00802001, + 0x00000080, 0x00800000, + 0x00002000, 0x00802080 }; + + private static final int[] SP5 = new int[] { 0x00000100, 0x02080100, + 0x02080000, 0x42000100, + 0x00080000, 0x00000100, + 0x40000000, 0x02080000, + 0x40080100, 0x00080000, + 0x02000100, 0x40080100, + 0x42000100, 0x42080000, + 0x00080100, 0x40000000, + 0x02000000, 0x40080000, + 0x40080000, 0x00000000, + 0x40000100, 0x42080100, + 0x42080100, 0x02000100, + 0x42080000, 0x40000100, + 0x00000000, 0x42000000, + 0x02080100, 0x02000000, + 0x42000000, 0x00080100, + 0x00080000, 0x42000100, + 0x00000100, 0x02000000, + 0x40000000, 0x02080000, + 0x42000100, 0x40080100, + 0x02000100, 0x40000000, + 0x42080000, 0x02080100, + 0x40080100, 0x00000100, + 0x02000000, 0x42080000, + 0x42080100, 0x00080100, + 0x42000000, 0x42080100, + 0x02080000, 0x00000000, + 0x40080000, 0x42000000, + 0x00080100, 0x02000100, + 0x40000100, 0x00080000, + 0x00000000, 0x40080000, + 0x02080100, 0x40000100 }; + + private static final int[] SP6 = new int[] { 0x20000010, 0x20400000, + 0x00004000, 0x20404010, + 0x20400000, 0x00000010, + 0x20404010, 0x00400000, + 0x20004000, 0x00404010, + 0x00400000, 0x20000010, + 0x00400010, 0x20004000, + 0x20000000, 0x00004010, + 0x00000000, 0x00400010, + 0x20004010, 0x00004000, + 0x00404000, 0x20004010, + 0x00000010, 0x20400010, + 0x20400010, 0x00000000, + 0x00404010, 0x20404000, + 0x00004010, 0x00404000, + 0x20404000, 0x20000000, + 0x20004000, 0x00000010, + 0x20400010, 0x00404000, + 0x20404010, 0x00400000, + 0x00004010, 0x20000010, + 0x00400000, 0x20004000, + 0x20000000, 0x00004010, + 0x20000010, 0x20404010, + 0x00404000, 0x20400000, + 0x00404010, 0x20404000, + 0x00000000, 0x20400010, + 0x00000010, 0x00004000, + 0x20400000, 0x00404010, + 0x00004000, 0x00400010, + 0x20004010, 0x00000000, + 0x20404000, 0x20000000, + 0x00400010, 0x20004010 }; + + private static final int[] SP7 = new int[] { 0x00200000, 0x04200002, + 0x04000802, 0x00000000, + 0x00000800, 0x04000802, + 0x00200802, 0x04200800, + 0x04200802, 0x00200000, + 0x00000000, 0x04000002, + 0x00000002, 0x04000000, + 0x04200002, 0x00000802, + 0x04000800, 0x00200802, + 0x00200002, 0x04000800, + 0x04000002, 0x04200000, + 0x04200800, 0x00200002, + 0x04200000, 0x00000800, + 0x00000802, 0x04200802, + 0x00200800, 0x00000002, + 0x04000000, 0x00200800, + 0x04000000, 0x00200800, + 0x00200000, 0x04000802, + 0x04000802, 0x04200002, + 0x04200002, 0x00000002, + 0x00200002, 0x04000000, + 0x04000800, 0x00200000, + 0x04200800, 0x00000802, + 0x00200802, 0x04200800, + 0x00000802, 0x04000002, + 0x04200802, 0x04200000, + 0x00200800, 0x00000000, + 0x00000002, 0x04200802, + 0x00000000, 0x00200802, + 0x04200000, 0x00000800, + 0x04000002, 0x04000800, + 0x00000800, 0x00200002 }; + + private static final int[] SP8 = new int[] { 0x10001040, 0x00001000, + 0x00040000, 0x10041040, + 0x10000000, 0x10001040, + 0x00000040, 0x10000000, + 0x00040040, 0x10040000, + 0x10041040, 0x00041000, + 0x10041000, 0x00041040, + 0x00001000, 0x00000040, + 0x10040000, 0x10000040, + 0x10001000, 0x00001040, + 0x00041000, 0x00040040, + 0x10040040, 0x10041000, + 0x00001040, 0x00000000, + 0x00000000, 0x10040040, + 0x10000040, 0x10001000, + 0x00041040, 0x00040000, + 0x00041040, 0x00040000, + 0x10041000, 0x00001000, + 0x00000040, 0x10040040, + 0x00001000, 0x00041040, + 0x10001000, 0x00000040, + 0x10000040, 0x10040000, + 0x10040040, 0x10000000, + 0x00040000, 0x10001040, + 0x00000000, 0x10041040, + 0x00040040, 0x10000040, + 0x10040000, 0x10001000, + 0x10001040, 0x00000000, + 0x10041040, 0x00041000, + 0x00041000, 0x00001040, + 0x00001040, 0x00040040, + 0x10000000, 0x10041000 }; + + /** + * Constants that help in determining whether or not a byte array is parity + * adjusted. + */ + private static final byte[] PARITY = { 8, 1, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, + 0, 2, 8, 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, + 0, 8, 0, 8, 8, 3, 0, 8, 8, 0, 8, 0, 0, + 8, 8, 0, 0, 8, 0, 8, 8, 0, 8, 0, 0, 8, + 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, 0, + 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, + 8, 0, 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, + 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, + 0, 8, 8, 0, 8, 0, 0, 8, 0, 8, 8, 0, 8, + 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, + 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, + 0, 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, + 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, 0, + 8, 8, 0, 8, 0, 0, 8, 0, 8, 8, 0, 8, 0, + 0, 8, 8, 0, 0, 8, 0, 8, 8, 0, 8, 0, 0, + 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8, + 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, + 8, 8, 0, 4, 8, 8, 0, 8, 0, 0, 8, 8, 0, + 0, 8, 0, 8, 8, 0, 8, 5, 0, 8, 0, 8, 8, + 0, 0, 8, 8, 0, 8, 0, 6, 8 }; + + // Key schedule constants. + + private static final byte[] ROTARS = { 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, + 21, 23, 25, 27, 28 }; + + private static final byte[] PC1 = { 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, + 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 62, 54, 46, 38, 30, + 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, + 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, + 3 }; + + private static final byte[] PC2 = { 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, + 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, + 12, 1, 40, 51, 30, 36, 46, 54, 29, 39, 50, + 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, + 41, 49, 35, 28, 31 }; + + /** + * Weak keys (parity adjusted): If all the bits in each half are either 0 + * or 1, then the key used for any cycle of the algorithm is the same as + * all other cycles. + */ + public static final byte[][] WEAK_KEYS = { + Util.toBytesFromString("0101010101010101"), + Util.toBytesFromString("01010101FEFEFEFE"), + Util.toBytesFromString("FEFEFEFE01010101"), + Util.toBytesFromString("FEFEFEFEFEFEFEFE") }; + + /** + * Semi-weak keys (parity adjusted): Some pairs of keys encrypt plain text + * to identical cipher text. In other words, one key in the pair can decrypt + * messages that were encrypted with the other key. These keys are called + * semi-weak keys. This occurs because instead of 16 different sub-keys being + * generated, these semi-weak keys produce only two different sub-keys. + */ + public static final byte[][] SEMIWEAK_KEYS = { + Util.toBytesFromString("01FE01FE01FE01FE"), + Util.toBytesFromString("FE01FE01FE01FE01"), + Util.toBytesFromString("1FE01FE00EF10EF1"), + Util.toBytesFromString("E01FE01FF10EF10E"), + Util.toBytesFromString("01E001E001F101F1"), + Util.toBytesFromString("E001E001F101F101"), + Util.toBytesFromString("1FFE1FFE0EFE0EFE"), + Util.toBytesFromString("FE1FFE1FFE0EFE0E"), + Util.toBytesFromString("011F011F010E010E"), + Util.toBytesFromString("1F011F010E010E01"), + Util.toBytesFromString("E0FEE0FEF1FEF1FE"), + Util.toBytesFromString("FEE0FEE0FEF1FEF1") }; + + /** Possible weak keys (parity adjusted) --produce 4 instead of 16 subkeys. */ + public static final byte[][] POSSIBLE_WEAK_KEYS = { + Util.toBytesFromString("1F1F01010E0E0101"), + Util.toBytesFromString("011F1F01010E0E01"), + Util.toBytesFromString("1F01011F0E01010E"), + Util.toBytesFromString("01011F1F01010E0E"), + Util.toBytesFromString("E0E00101F1F10101"), + Util.toBytesFromString("FEFE0101FEFE0101"), + Util.toBytesFromString("FEE01F01FEF10E01"), + Util.toBytesFromString("E0FE1F01F1FE0E01"), + Util.toBytesFromString("FEE0011FFEF1010E"), + Util.toBytesFromString("E0FE011FF1FE010E"), + Util.toBytesFromString("E0E01F1FF1F10E0E"), + Util.toBytesFromString("FEFE1F1FFEFE0E0E"), + Util.toBytesFromString("1F1F01010E0E0101"), + Util.toBytesFromString("011F1F01010E0E01"), + Util.toBytesFromString("1F01011F0E01010E"), + Util.toBytesFromString("01011F1F01010E0E"), + Util.toBytesFromString("01E0E00101F1F101"), + Util.toBytesFromString("1FFEE0010EFEF001"), + Util.toBytesFromString("1FE0FE010EF1FE01"), + Util.toBytesFromString("01FEFE0101FEFE01"), + Util.toBytesFromString("1FE0E01F0EF1F10E"), + Util.toBytesFromString("01FEE01F01FEF10E"), + Util.toBytesFromString("01E0FE1F01F1FE0E"), + Util.toBytesFromString("1FFEFE1F0EFEFE0E"), + + Util.toBytesFromString("E00101E0F10101F1"), + Util.toBytesFromString("FE1F01E0FE0E0EF1"), + Util.toBytesFromString("FE011FE0FE010EF1"), + Util.toBytesFromString("E01F1FE0F10E0EF1"), + Util.toBytesFromString("FE0101FEFE0101FE"), + Util.toBytesFromString("E01F01FEF10E01FE"), + Util.toBytesFromString("E0011FFEF1010EFE"), + Util.toBytesFromString("FE1F1FFEFE0E0EFE"), + Util.toBytesFromString("1FFE01E00EFE01F1"), + Util.toBytesFromString("01FE1FE001FE0EF1"), + Util.toBytesFromString("1FE001FE0EF101FE"), + Util.toBytesFromString("01E01FFE01F10EFE"), + Util.toBytesFromString("0101E0E00101F1F1"), + Util.toBytesFromString("1F1FE0E00E0EF1F1"), + Util.toBytesFromString("1F01FEE00E01FEF1"), + Util.toBytesFromString("011FFEE0010EFEF1"), + Util.toBytesFromString("1F01E0FE0E01F1FE"), + Util.toBytesFromString("011FE0FE010EF1FE"), + Util.toBytesFromString("0101FEFE0001FEFE"), + Util.toBytesFromString("1F1FFEFE0E0EFEFE"), + Util.toBytesFromString("FEFEE0E0FEFEF1F1"), + Util.toBytesFromString("E0FEFEE0F1FEFEF1"), + Util.toBytesFromString("FEE0E0FEFEF1F1FE"), + Util.toBytesFromString("E0E0FEFEF1F1FEFE") }; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Default 0-argument constructor. */ + public DES() + { + super(Registry.DES_CIPHER, BLOCK_SIZE, KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Adjust the parity for a raw key array. This essentially means that each + * byte in the array will have an odd number of '1' bits (the last bit in + * each byte is unused.

+ * + * @param kb The key array, to be parity-adjusted. + * @param offset The starting index into the key bytes. + */ + public static void adjustParity(byte[] kb, int offset) + { + for (int i = offset; i < KEY_SIZE; i++) + { + kb[i] ^= (PARITY[kb[i] & 0xff] == 8) ? 1 : 0; + } + } + + /** + *

Test if a byte array, which must be at least 8 bytes long, is parity + * adjusted.

+ * + * @param kb The key bytes. + * @param offset The starting index into the key bytes. + * @return true if the first 8 bytes of kb have been + * parity adjusted. false otherwise. + */ + public static boolean isParityAdjusted(byte[] kb, int offset) + { + int w = 0x88888888; + int n = PARITY[kb[offset + 0] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 1] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 2] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 3] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 4] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 5] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 6] & 0xff]; + n <<= 4; + n |= PARITY[kb[offset + 7] & 0xff]; + return (n & w) == 0; + } + + /** + *

Test if a key is a weak key.

+ * + * @param kb The key to test. + * @return true if the key is weak. + */ + public static boolean isWeak(byte[] kb) + { + // return Arrays.equals(kb, WEAK_KEYS[0]) || Arrays.equals(kb, WEAK_KEYS[1]) + // || Arrays.equals(kb, WEAK_KEYS[2]) || Arrays.equals(kb, WEAK_KEYS[3]) + // || Arrays.equals(kb, WEAK_KEYS[4]) || Arrays.equals(kb, WEAK_KEYS[5]) + // || Arrays.equals(kb, WEAK_KEYS[6]) || Arrays.equals(kb, WEAK_KEYS[7]); + for (int i = 0; i < WEAK_KEYS.length; i++) + { + if (Arrays.equals(WEAK_KEYS[i], kb)) + { + return true; + } + } + return false; + } + + /** + *

Test if a key is a semi-weak key.

+ * + * @param kb The key to test. + * @return true if this key is semi-weak. + */ + public static boolean isSemiWeak(byte[] kb) + { + // return Arrays.equals(kb, SEMIWEAK_KEYS[0]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[1]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[2]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[3]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[4]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[5]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[6]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[7]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[8]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[9]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[10]) + // || Arrays.equals(kb, SEMIWEAK_KEYS[11]); + for (int i = 0; i < SEMIWEAK_KEYS.length; i++) + { + if (Arrays.equals(SEMIWEAK_KEYS[i], kb)) + { + return true; + } + } + return false; + } + + /** + *

Test if the designated byte array represents a possibly weak key.

+ * + * @param kb the byte array to test. + * @return true if kbrepresents a possibly weak key. + * Returns false otherwise. + */ + public static boolean isPossibleWeak(byte[] kb) + { + for (int i = 0; i < POSSIBLE_WEAK_KEYS.length; i++) + { + if (Arrays.equals(POSSIBLE_WEAK_KEYS[i], kb)) + { + return true; + } + } + return false; + } + + /** + *

The core DES function. This is used for both encryption and decryption, + * the only difference being the key.

+ * + * @param in The input bytes. + * @param i The starting offset into the input bytes. + * @param out The output bytes. + * @param o The starting offset into the output bytes. + * @param key The working key. + */ + private static void desFunc(byte[] in, int i, byte[] out, int o, int[] key) + { + int right, left, work; + + // Load. + left = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 + | (in[i++] & 0xff) << 8 | in[i++] & 0xff; + right = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 + | (in[i++] & 0xff) << 8 | in[i] & 0xff; + + // Initial permutation. + work = ((left >>> 4) ^ right) & 0x0F0F0F0F; + left ^= work << 4; + right ^= work; + + work = ((left >>> 16) ^ right) & 0x0000FFFF; + left ^= work << 16; + right ^= work; + + work = ((right >>> 2) ^ left) & 0x33333333; + right ^= work << 2; + left ^= work; + + work = ((right >>> 8) ^ left) & 0x00FF00FF; + right ^= work << 8; + left ^= work; + + right = ((right << 1) | ((right >>> 31) & 1)) & 0xFFFFFFFF; + work = (left ^ right) & 0xAAAAAAAA; + left ^= work; + right ^= work; + left = ((left << 1) | ((left >>> 31) & 1)) & 0xFFFFFFFF; + + int k = 0, t; + for (int round = 0; round < 8; round++) + { + work = right >>> 4 | right << 28; + work ^= key[k++]; + t = SP7[work & 0x3F]; + work >>>= 8; + t |= SP5[work & 0x3F]; + work >>>= 8; + t |= SP3[work & 0x3F]; + work >>>= 8; + t |= SP1[work & 0x3F]; + work = right ^ key[k++]; + t |= SP8[work & 0x3F]; + work >>>= 8; + t |= SP6[work & 0x3F]; + work >>>= 8; + t |= SP4[work & 0x3F]; + work >>>= 8; + t |= SP2[work & 0x3F]; + left ^= t; + + work = left >>> 4 | left << 28; + work ^= key[k++]; + t = SP7[work & 0x3F]; + work >>>= 8; + t |= SP5[work & 0x3F]; + work >>>= 8; + t |= SP3[work & 0x3F]; + work >>>= 8; + t |= SP1[work & 0x3F]; + work = left ^ key[k++]; + t |= SP8[work & 0x3F]; + work >>>= 8; + t |= SP6[work & 0x3F]; + work >>>= 8; + t |= SP4[work & 0x3F]; + work >>>= 8; + t |= SP2[work & 0x3F]; + right ^= t; + } + + // The final permutation. + right = (right << 31) | (right >>> 1); + work = (left ^ right) & 0xAAAAAAAA; + left ^= work; + right ^= work; + left = (left << 31) | (left >>> 1); + + work = ((left >>> 8) ^ right) & 0x00FF00FF; + left ^= work << 8; + right ^= work; + + work = ((left >>> 2) ^ right) & 0x33333333; + left ^= work << 2; + right ^= work; + + work = ((right >>> 16) ^ left) & 0x0000FFFF; + right ^= work << 16; + left ^= work; + + work = ((right >>> 4) ^ left) & 0x0F0F0F0F; + right ^= work << 4; + left ^= work; + + out[o++] = (byte) (right >>> 24); + out[o++] = (byte) (right >>> 16); + out[o++] = (byte) (right >>> 8); + out[o++] = (byte) right; + out[o++] = (byte) (left >>> 24); + out[o++] = (byte) (left >>> 16); + out[o++] = (byte) (left >>> 8); + out[o] = (byte) left; + } + + // Instance methods implementing BaseCipher + // ------------------------------------------------------------------------- + + public Object clone() + { + return new DES(); + } + + public Iterator blockSizes() + { + return Collections.singleton(new Integer(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + return Collections.singleton(new Integer(KEY_SIZE)).iterator(); + } + + public Object makeKey(byte[] kb, int bs) throws InvalidKeyException + { + if (kb == null || kb.length != KEY_SIZE) + throw new InvalidKeyException("DES keys must be 8 bytes long"); + + if (Properties.checkForWeakKeys() + && (isWeak(kb) || isSemiWeak(kb) || isPossibleWeak(kb))) + { + throw new WeakKeyException(); + } + + int i, j, l, m, n; + long pc1m = 0, pcr = 0; + + for (i = 0; i < 56; i++) + { + l = PC1[i]; + pc1m |= ((kb[l >>> 3] & (0x80 >>> (l & 7))) != 0) ? (1L << (55 - i)) + : 0; + } + + Context ctx = new Context(); + + // Encryption key first. + for (i = 0; i < 16; i++) + { + pcr = 0; + m = i << 1; + n = m + 1; + for (j = 0; j < 28; j++) + { + l = j + ROTARS[i]; + if (l < 28) + pcr |= ((pc1m & 1L << (55 - l)) != 0) ? (1L << (55 - j)) : 0; + else + pcr |= ((pc1m & 1L << (55 - (l - 28))) != 0) ? (1L << (55 - j)) + : 0; + } + for (j = 28; j < 56; j++) + { + l = j + ROTARS[i]; + if (l < 56) + pcr |= ((pc1m & 1L << (55 - l)) != 0) ? (1L << (55 - j)) : 0; + else + pcr |= ((pc1m & 1L << (55 - (l - 28))) != 0) ? (1L << (55 - j)) + : 0; + } + for (j = 0; j < 24; j++) + { + if ((pcr & 1L << (55 - PC2[j])) != 0) + ctx.ek[m] |= 1 << (23 - j); + if ((pcr & 1L << (55 - PC2[j + 24])) != 0) + ctx.ek[n] |= 1 << (23 - j); + } + } + + // The decryption key is the same, but in reversed order. + for (i = 0; i < Context.EXPANDED_KEY_SIZE; i += 2) + { + ctx.dk[30 - i] = ctx.ek[i]; + ctx.dk[31 - i] = ctx.ek[i + 1]; + } + + // "Cook" the keys. + for (i = 0; i < 32; i += 2) + { + int x, y; + + x = ctx.ek[i]; + y = ctx.ek[i + 1]; + + ctx.ek[i] = ((x & 0x00FC0000) << 6) | ((x & 0x00000FC0) << 10) + | ((y & 0x00FC0000) >>> 10) | ((y & 0x00000FC0) >>> 6); + ctx.ek[i + 1] = ((x & 0x0003F000) << 12) | ((x & 0x0000003F) << 16) + | ((y & 0x0003F000) >>> 4) | (y & 0x0000003F); + + x = ctx.dk[i]; + y = ctx.dk[i + 1]; + + ctx.dk[i] = ((x & 0x00FC0000) << 6) | ((x & 0x00000FC0) << 10) + | ((y & 0x00FC0000) >>> 10) | ((y & 0x00000FC0) >>> 6); + ctx.dk[i + 1] = ((x & 0x0003F000) << 12) | ((x & 0x0000003F) << 16) + | ((y & 0x0003F000) >>> 4) | (y & 0x0000003F); + } + + return ctx; + } + + public void encrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + desFunc(in, i, out, o, ((Context) K).ek); + } + + public void decrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + desFunc(in, i, out, o, ((Context) K).dk); + } + + // Inner classe(s) + // ========================================================================= + + /** + * Simple wrapper class around the session keys. Package-private so TripleDES + * can see it. + */ + final class Context + { + + // Constants and variables + // ---------------------------------------------------------------------- + + private static final int EXPANDED_KEY_SIZE = 32; + + /** The encryption key. */ + int[] ek; + + /** The decryption key. */ + int[] dk; + + // Constructor(s) + // ---------------------------------------------------------------------- + + /** Default 0-arguments constructor. */ + Context() + { + ek = new int[EXPANDED_KEY_SIZE]; + dk = new int[EXPANDED_KEY_SIZE]; + } + + // Class methods + // ---------------------------------------------------------------------- + + // Instance methods + // ---------------------------------------------------------------------- + + byte[] getEncryptionKeyBytes() + { + return toByteArray(ek); + } + + byte[] getDecryptionKeyBytes() + { + return toByteArray(dk); + } + + byte[] toByteArray(int[] k) + { + byte[] result = new byte[4 * k.length]; + for (int i = 0, j = 0; i < k.length; i++) + { + result[j++] = (byte) (k[i] >>> 24); + result[j++] = (byte) (k[i] >>> 16); + result[j++] = (byte) (k[i] >>> 8); + result[j++] = (byte) k[i]; + } + return result; + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/IBlockCipher.java b/gnu/javax/crypto/cipher/IBlockCipher.java new file mode 100644 index 000000000..238ee280f --- /dev/null +++ b/gnu/javax/crypto/cipher/IBlockCipher.java @@ -0,0 +1,205 @@ +/* IBlockCipher.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import java.security.InvalidKeyException; +import java.util.Iterator; +import java.util.Map; + +/** + *

The basic visible methods of any symmetric key block cipher.

+ * + *

A symmetric key block cipher is a function that maps n-bit plaintext + * blocks to n-bit ciphertext blocks; n being the cipher's block size. + * This encryption function is parameterised by a k-bit key, and is invertible. + * Its inverse is the decryption function.

+ * + *

Possible initialisation values for an instance of this type are:

+ * + *
    + *
  • The block size in which to operate this block cipher instance. This + * value is optional, if unspecified, the block cipher's default + * block size shall be used.
  • + * + *
  • The byte array containing the user supplied key material to use for + * generating the cipher's session key(s). This value is mandatory + * and should be included in the initialisation parameters. If it isn't, + * an {@link IllegalStateException} will be thrown if any method, other than + * reset() is invoked on the instance. Furthermore, the size of + * this key material shall be taken as an indication on the key size in which + * to operate this instance.
  • + *
+ * + *

IMPLEMENTATION NOTE: Although all the concrete classes in this + * package implement the {@link Cloneable} interface, it is important to note + * here that such an operation DOES NOT clone any session key material + * that may have been used in initialising the source cipher (the instance to be + * cloned). Instead a clone of an already initialised cipher is another instance + * that operates with the same block size but without any knowledge of + * neither key material nor key size.

+ */ +public interface IBlockCipher extends Cloneable +{ + + // Constants + // ------------------------------------------------------------------------- + + /** + *

Property name of the block size in which to operate a block cipher. + * The value associated with this property name is taken to be an + * {@link Integer}.

+ */ + String CIPHER_BLOCK_SIZE = "gnu.crypto.cipher.block.size"; + + /** + *

Property name of the user-supplied key material. The value associated + * to this property name is taken to be a byte array.

+ */ + String KEY_MATERIAL = "gnu.crypto.cipher.key.material"; + + // Methods + // ------------------------------------------------------------------------- + + /** + *

Returns the canonical name of this instance.

+ * + * @return the canonical name of this instance. + */ + String name(); + + /** + *

Returns the default value, in bytes, of the algorithm's block size.

+ * + * @return the default value, in bytes, of the algorithm's block size. + */ + int defaultBlockSize(); + + /** + *

Returns the default value, in bytes, of the algorithm's key size.

+ * + * @return the default value, in bytes, of the algorithm's key size. + */ + int defaultKeySize(); + + /** + *

Returns an {@link Iterator} over the supported block sizes. Each + * element returned by this object is an {@link Integer}.

+ * + * @return an {@link Iterator} over the supported block sizes. + */ + Iterator blockSizes(); + + /** + *

Returns an {@link Iterator} over the supported key sizes. Each element + * returned by this object is an {@link Integer}.

+ * + * @return an {@link Iterator} over the supported key sizes. + */ + Iterator keySizes(); + + /** + *

Returns a clone of this instance.

+ * + * @return a clone copy of this instance. + */ + Object clone(); + + /** + *

Initialises the algorithm with designated attributes. Permissible names + * and values are described in the class documentation above.

+ * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @exception InvalidKeyException if the key data is invalid. + * @exception IllegalStateException if the instance is already initialised. + * @see #KEY_MATERIAL + * @see #CIPHER_BLOCK_SIZE + */ + void init(Map attributes) throws InvalidKeyException, IllegalStateException; + + /** + *

Returns the currently set block size for this instance.

+ * + * @return the current block size for this instance. + * @exception IllegalStateException if the instance is not initialised. + */ + int currentBlockSize() throws IllegalStateException; + + /** + *

Resets the algorithm instance for re-initialisation and use with other + * characteristics. This method always succeeds.

+ */ + void reset(); + + /** + *

Encrypts exactly one block of plaintext.

+ * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; + + /** + *

Decrypts exactly one block of ciphertext.

+ * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; + + /** + *

A correctness test that consists of basic symmetric encryption / + * decryption test(s) for all supported block and key sizes, as well as one + * (1) variable key Known Answer Test (KAT).

+ * + * @return true if the implementation passes simple + * correctness tests. Returns false otherwise. + */ + boolean selfTest(); +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/IBlockCipherSpi.java b/gnu/javax/crypto/cipher/IBlockCipherSpi.java new file mode 100644 index 000000000..6fe07ca7f --- /dev/null +++ b/gnu/javax/crypto/cipher/IBlockCipherSpi.java @@ -0,0 +1,128 @@ +/* IBlockCipherSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import java.security.InvalidKeyException; +import java.util.Iterator; + +/** + *

Package-private interface exposing mandatory methods to be implemented by + * concrete {@link gnu.crypto.cipher.BaseCipher} sub-classes.

+ */ +interface IBlockCipherSpi extends Cloneable +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + *

Returns an {@link java.util.Iterator} over the supported block sizes. + * Each element returned by this object is a {@link java.lang.Integer}.

+ * + * @return an Iterator over the supported block sizes. + */ + Iterator blockSizes(); + + /** + *

Returns an {@link java.util.Iterator} over the supported key sizes. + * Each element returned by this object is a {@link java.lang.Integer}.

+ * + * @return an Iterator over the supported key sizes. + */ + Iterator keySizes(); + + /** + *

Expands a user-supplied key material into a session key for a + * designated block size.

+ * + * @param k the user-supplied key material. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is invalid. + * @exception InvalidKeyException if the key data is invalid. + */ + Object makeKey(byte[] k, int bs) throws InvalidKeyException; + + /** + *

Encrypts exactly one block of plaintext.

+ * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store the result. + * @param k the session key to use. + * @param bs the block size to use. + * @exception IllegalArgumentException if the block size is invalid. + * @exception ArrayIndexOutOfBoundsException if there is not enough room in + * either the plaintext or ciphertext buffers. + */ + void encrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object k, + int bs); + + /** + *

Decrypts exactly one block of ciphertext.

+ * + * @param in the ciphertext. + * @param inOffset index of in from which to start considering + * data. + * @param out the plaintext. + * @param outOffset index of out from which to store the result. + * @param k the session key to use. + * @param bs the block size to use. + * @exception IllegalArgumentException if the block size is invalid. + * @exception ArrayIndexOutOfBoundsException if there is not enough room in + * either the plaintext or ciphertext buffers. + */ + void decrypt(byte[] in, int inOffset, byte[] out, int outOffset, Object k, + int bs); + + /** + *

A correctness test that consists of basic symmetric encryption / + * decryption test(s) for all supported block and key sizes, as well as one + * (1) variable key Known Answer Test (KAT).

+ * + * @return true if the implementation passes simple + * correctness tests. Returns false otherwise. + */ + boolean selfTest(); +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Khazad.java b/gnu/javax/crypto/cipher/Khazad.java new file mode 100644 index 000000000..b6c27833e --- /dev/null +++ b/gnu/javax/crypto/cipher/Khazad.java @@ -0,0 +1,521 @@ +/* Khazad.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +//import java.io.PrintWriter; +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + *

Khazad is a 64-bit (legacy-level) block cipher that accepts a 128-bit key. + * The cipher is a uniform substitution-permutation network whose inverse only + * differs from the forward operation in the key schedule. The overall cipher + * design follows the Wide Trail strategy, favours component reuse, and permits + * a wide variety of implementation trade-offs.

+ * + *

References:

+ * + *
    + *
  1. The + * Khazad Block Cipher.
    + * Paulo S.L.M. Barreto and + * Vincent Rijmen.
  2. + *
+ */ +public final class Khazad extends BaseCipher +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + // private static final String NAME = "khazad"; + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + // private static final PrintWriter err = new PrintWriter(System.out, true); + // private static void debug(String s) { + // err.println(">>> "+NAME+": "+s); + // } + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int DEFAULT_BLOCK_SIZE = 8; // in bytes + + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + + private static final int R = 8; // standard number of rounds; para. 3.7 + + private static final String Sd = // p. 20 [KHAZAD] + "\uBA54\u2F74\u53D3\uD24D\u50AC\u8DBF\u7052\u9A4C" + + "\uEAD5\u97D1\u3351\u5BA6\uDE48\uA899\uDB32\uB7FC" + + "\uE39E\u919B\uE2BB\u416E\uA5CB\u6B95\uA1F3\uB102" + + "\uCCC4\u1D14\uC363\uDA5D\u5FDC\u7DCD\u7F5A\u6C5C" + + "\uF726\uFFED\uE89D\u6F8E\u19A0\uF089\u0F07\uAFFB" + + "\u0815\u0D04\u0164\uDF76\u79DD\u3D16\u3F37\u6D38" + + "\uB973\uE935\u5571\u7B8C\u7288\uF62A\u3E5E\u2746" + + "\u0C65\u6861\u03C1\u57D6\uD958\uD866\uD73A\uC83C" + + "\uFA96\uA798\uECB8\uC7AE\u694B\uABA9\u670A\u47F2" + + "\uB522\uE5EE\uBE2B\u8112\u831B\u0E23\uF545\u21CE" + + "\u492C\uF9E6\uB628\u1782\u1A8B\uFE8A\u09C9\u874E" + + "\uE12E\uE4E0\uEB90\uA41E\u8560\u0025\uF4F1\u940B" + + "\uE775\uEF34\u31D4\uD086\u7EAD\uFD29\u303B\u9FF8" + + "\uC613\u0605\uC511\u777C\u7A78\u361C\u3959\u1856" + + "\uB3B0\u2420\uB292\uA3C0\u4462\u10B4\u8443\u93C2" + + "\u4ABD\u8F2D\uBC9C\u6A40\uCFA2\u804F\u1FCA\uAA42"; + + private static final byte[] S = new byte[256]; + + private static final int[] T0 = new int[256]; + + private static final int[] T1 = new int[256]; + + private static final int[] T2 = new int[256]; + + private static final int[] T3 = new int[256]; + + private static final int[] T4 = new int[256]; + + private static final int[] T5 = new int[256]; + + private static final int[] T6 = new int[256]; + + private static final int[] T7 = new int[256]; + + private static final int[][] rc = new int[R + 1][2]; // round constants + + /** + * KAT vector (from ecb_vk): + * I=120 + * KEY=00000000000000000000000000000100 + * CT=A0C86A1BBE2CBF4C + */ + private static final byte[] KAT_KEY = Util.toBytesFromString("00000000000000000000000000000100"); + + private static final byte[] KAT_CT = Util.toBytesFromString("A0C86A1BBE2CBF4C"); + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + // Static code - to intialise lookup tables -------------------------------- + + static + { + long time = System.currentTimeMillis(); + + long ROOT = 0x11d; // para. 2.1 [KHAZAD] + int i, j; + int s, s2, s3, s4, s5, s6, s7, s8, sb; + char c; + for (i = 0; i < 256; i++) + { + c = Sd.charAt(i >>> 1); + s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFF; + S[i] = (byte) s; + + s2 = s << 1; + if (s2 > 0xFF) + s2 ^= ROOT; + + s3 = s2 ^ s; + s4 = s2 << 1; + if (s4 > 0xFF) + s4 ^= ROOT; + + s5 = s4 ^ s; + s6 = s4 ^ s2; + s7 = s6 ^ s; + s8 = s4 << 1; + if (s8 > 0xFF) + s8 ^= ROOT; + + sb = s8 ^ s2 ^ s; + + T0[i] = s << 24 | s3 << 16 | s4 << 8 | s5; + T1[i] = s3 << 24 | s << 16 | s5 << 8 | s4; + T2[i] = s4 << 24 | s5 << 16 | s << 8 | s3; + T3[i] = s5 << 24 | s4 << 16 | s3 << 8 | s; + T4[i] = s6 << 24 | s8 << 16 | sb << 8 | s7; + T5[i] = s8 << 24 | s6 << 16 | s7 << 8 | sb; + T6[i] = sb << 24 | s7 << 16 | s6 << 8 | s8; + T7[i] = s7 << 24 | sb << 16 | s8 << 8 | s6; + } + + for (i = 0, j = 0; i < R + 1; i++) + { + // compute round constant + rc[i][0] = S[j++] << 24 | (S[j++] & 0xFF) << 16 + | (S[j++] & 0xFF) << 8 | (S[j++] & 0xFF); + rc[i][1] = S[j++] << 24 | (S[j++] & 0xFF) << 16 + | (S[j++] & 0xFF) << 8 | (S[j++] & 0xFF); + } + + time = System.currentTimeMillis() - time; + + if (DEBUG && debuglevel > 8) + { + System.out.println("=========="); + System.out.println(); + System.out.println("Static data"); + System.out.println(); + + System.out.println(); + System.out.println("T0[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T0[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T1[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T1[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T2[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T2[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T3[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T3[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T4[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T4[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T5[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T6[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T6[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("T7[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + System.out.print("0x" + Util.toString(T7[i * 4 + j]) + ", "); + System.out.println(); + } + System.out.println(); + System.out.println("rc[]:"); + for (i = 0; i < R + 1; i++) + System.out.print("0x" + Util.toString(rc[i][0]) + + Util.toString(rc[i][1])); + System.out.println(); + + System.out.println("Total initialization time: " + time + " ms."); + System.out.println(); + } + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Khazad() + { + super(Registry.KHAZAD_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + private static void khazad(byte[] in, int i, byte[] out, int j, int[][] K) + { + // sigma(K[0]) + int k0 = K[0][0]; + int k1 = K[0][1]; + int a0 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ k0; + int a1 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i] & 0xFF)) + ^ k1; + + int b0, b1; + // round function + for (int r = 1; r < R; r++) + { + k0 = K[r][0]; + k1 = K[r][1]; + b0 = T0[a0 >>> 24] ^ T1[(a0 >>> 16) & 0xFF] ^ T2[(a0 >>> 8) & 0xFF] + ^ T3[a0 & 0xFF] ^ T4[a1 >>> 24] ^ T5[(a1 >>> 16) & 0xFF] + ^ T6[(a1 >>> 8) & 0xFF] ^ T7[a1 & 0xFF] ^ k0; + b1 = T0[a1 >>> 24] ^ T1[(a1 >>> 16) & 0xFF] ^ T2[(a1 >>> 8) & 0xFF] + ^ T3[a1 & 0xFF] ^ T4[a0 >>> 24] ^ T5[(a0 >>> 16) & 0xFF] + ^ T6[(a0 >>> 8) & 0xFF] ^ T7[a0 & 0xFF] ^ k1; + a0 = b0; + a1 = b1; + + if (DEBUG && debuglevel > 6) + { + System.out.println("T" + r + "=" + Util.toString(a0) + + Util.toString(a1)); + } + } + + // sigma(K[R]) o gamma applied to previous output + k0 = K[R][0]; + k1 = K[R][1]; + + out[j++] = (byte) (S[a0 >>> 24] ^ (k0 >>> 24)); + out[j++] = (byte) (S[(a0 >>> 16) & 0xFF] ^ (k0 >>> 16)); + out[j++] = (byte) (S[(a0 >>> 8) & 0xFF] ^ (k0 >>> 8)); + out[j++] = (byte) (S[a0 & 0xFF] ^ k0); + out[j++] = (byte) (S[a1 >>> 24] ^ (k1 >>> 24)); + out[j++] = (byte) (S[(a1 >>> 16) & 0xFF] ^ (k1 >>> 16)); + out[j++] = (byte) (S[(a1 >>> 8) & 0xFF] ^ (k1 >>> 8)); + out[j] = (byte) (S[a1 & 0xFF] ^ k1); + + if (DEBUG && debuglevel > 6) + { + System.out.println("T=" + Util.toString(out, j - 7, 8)); + System.out.println(); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Khazad result = new Khazad(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_KEY_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + /** + *

Expands a user-supplied key material into a session key for a + * designated block size.

+ * + * @param uk the 128-bit user-supplied key material. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16 (128-bit). + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + if (uk == null) + { + throw new InvalidKeyException("Empty key"); + } + if (uk.length != 16) + { + throw new InvalidKeyException("Key is not 128-bit."); + } + int[][] Ke = new int[R + 1][2]; // encryption round keys + int[][] Kd = new int[R + 1][2]; // decryption round keys + + int r, i; + int k20, k21, k10, k11, rc0, rc1, kr0, kr1; + + i = 0; + k20 = uk[i++] << 24 | (uk[i++] & 0xFF) << 16 | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + k21 = uk[i++] << 24 | (uk[i++] & 0xFF) << 16 | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + k10 = uk[i++] << 24 | (uk[i++] & 0xFF) << 16 | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + k11 = uk[i++] << 24 | (uk[i++] & 0xFF) << 16 | (uk[i++] & 0xFF) << 8 + | (uk[i++] & 0xFF); + + for (r = 0, i = 0; r <= R; r++) + { + rc0 = rc[r][0]; + rc1 = rc[r][1]; + + kr0 = T0[k10 >>> 24] ^ T1[(k10 >>> 16) & 0xFF] ^ T2[(k10 >>> 8) & 0xFF] + ^ T3[k10 & 0xFF] ^ T4[(k11 >>> 24) & 0xFF] + ^ T5[(k11 >>> 16) & 0xFF] ^ T6[(k11 >>> 8) & 0xFF] + ^ T7[k11 & 0xFF] ^ rc0 ^ k20; + kr1 = T0[k11 >>> 24] ^ T1[(k11 >>> 16) & 0xFF] ^ T2[(k11 >>> 8) & 0xFF] + ^ T3[k11 & 0xFF] ^ T4[(k10 >>> 24) & 0xFF] + ^ T5[(k10 >>> 16) & 0xFF] ^ T6[(k10 >>> 8) & 0xFF] + ^ T7[k10 & 0xFF] ^ rc1 ^ k21; + + Ke[r][0] = kr0; + Ke[r][1] = kr1; + k20 = k10; + k21 = k11; + k10 = kr0; + k11 = kr1; + + if (r == 0 || r == R) + { + Kd[R - r][0] = kr0; + Kd[R - r][1] = kr1; + } + else + { + Kd[R - r][0] = T0[S[kr0 >>> 24] & 0xFF] + ^ T1[S[(kr0 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(kr0 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[kr0 & 0xFF] & 0xFF] + ^ T4[S[kr1 >>> 24] & 0xFF] + ^ T5[S[(kr1 >>> 16) & 0xFF] & 0xFF] + ^ T6[S[(kr1 >>> 8) & 0xFF] & 0xFF] + ^ T7[S[kr1 & 0xFF] & 0xFF]; + Kd[R - r][1] = T0[S[kr1 >>> 24] & 0xFF] + ^ T1[S[(kr1 >>> 16) & 0xFF] & 0xFF] + ^ T2[S[(kr1 >>> 8) & 0xFF] & 0xFF] + ^ T3[S[kr1 & 0xFF] & 0xFF] + ^ T4[S[kr0 >>> 24] & 0xFF] + ^ T5[S[(kr0 >>> 16) & 0xFF] & 0xFF] + ^ T6[S[(kr0 >>> 8) & 0xFF] & 0xFF] + ^ T7[S[kr0 & 0xFF] & 0xFF]; + } + } + + if (DEBUG && debuglevel > 8) + { + System.out.println(); + System.out.println("Key schedule"); + System.out.println(); + System.out.println("Ke[]:"); + for (r = 0; r < R + 1; r++) + { + System.out.println("#" + r + ": 0x" + Util.toString(Ke[r][0]) + + Util.toString(Ke[r][1])); + } + System.out.println(); + System.out.println("Kd[]:"); + for (r = 0; r < R + 1; r++) + { + System.out.println("#" + r + ": 0x" + Util.toString(Kd[r][0]) + + Util.toString(Kd[r][1])); + } + System.out.println(); + } + + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + + int[][] K = (int[][]) ((Object[]) k)[0]; + khazad(in, i, out, j, K); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + + int[][] K = (int[][]) ((Object[]) k)[1]; + khazad(in, i, out, j, K); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + { + result = testKat(KAT_KEY, KAT_CT); + } + valid = new Boolean(result); + } + return valid.booleanValue(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/NullCipher.java b/gnu/javax/crypto/cipher/NullCipher.java new file mode 100644 index 000000000..09252db90 --- /dev/null +++ b/gnu/javax/crypto/cipher/NullCipher.java @@ -0,0 +1,129 @@ +/* NullCipher.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + *

The implementation of a Null block cipher.

+ * + *

This cipher does not alter its input at all, claims to process block sizes + * 128-, 192- and 256-bit long, and key sizes from 64- to 512-bit in 8-bit + * increments.

+ */ +public final class NullCipher extends BaseCipher +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public NullCipher() + { + super(Registry.NULL_CIPHER, 16, 16); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + NullCipher result = new NullCipher(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(64 / 8)); + al.add(new Integer(128 / 8)); + al.add(new Integer(192 / 8)); + al.add(new Integer(256 / 8)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 8; n < 64; n++) + { + al.add(new Integer(n)); + } + + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + return new Object(); + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + System.arraycopy(in, i, out, j, bs); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + System.arraycopy(in, i, out, j, bs); + } + + public boolean selfTest() + { + return true; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Rijndael.java b/gnu/javax/crypto/cipher/Rijndael.java new file mode 100644 index 000000000..058c8b346 --- /dev/null +++ b/gnu/javax/crypto/cipher/Rijndael.java @@ -0,0 +1,859 @@ +/* Rijndael.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +//import java.io.PrintWriter; +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + *

Rijndael --pronounced Reindaal-- is the AES. It is a variable block-size + * (128-, 192- and 256-bit), variable key-size (128-, 192- and 256-bit) + * symmetric key block cipher.

+ * + *

References:

+ * + *
    + *
  1. The + * Rijndael Block Cipher - AES Proposal.
    + * Vincent Rijmen and + * Joan Daemen.
  2. + *
+ */ +public final class Rijndael extends BaseCipher +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + // private static final String NAME = "rijndael"; + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + // private static final PrintWriter err = new PrintWriter(System.out, true); + // private static void debug(String s) { + // err.println(">>> "+NAME+": "+s); + // } + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + + private static final String SS = "\u637C\u777B\uF26B\u6FC5\u3001\u672B\uFED7\uAB76" + + "\uCA82\uC97D\uFA59\u47F0\uADD4\uA2AF\u9CA4\u72C0" + + "\uB7FD\u9326\u363F\uF7CC\u34A5\uE5F1\u71D8\u3115" + + "\u04C7\u23C3\u1896\u059A\u0712\u80E2\uEB27\uB275" + + "\u0983\u2C1A\u1B6E\u5AA0\u523B\uD6B3\u29E3\u2F84" + + "\u53D1\u00ED\u20FC\uB15B\u6ACB\uBE39\u4A4C\u58CF" + + "\uD0EF\uAAFB\u434D\u3385\u45F9\u027F\u503C\u9FA8" + + "\u51A3\u408F\u929D\u38F5\uBCB6\uDA21\u10FF\uF3D2" + + "\uCD0C\u13EC\u5F97\u4417\uC4A7\u7E3D\u645D\u1973" + + "\u6081\u4FDC\u222A\u9088\u46EE\uB814\uDE5E\u0BDB" + + "\uE032\u3A0A\u4906\u245C\uC2D3\uAC62\u9195\uE479" + + "\uE7C8\u376D\u8DD5\u4EA9\u6C56\uF4EA\u657A\uAE08" + + "\uBA78\u252E\u1CA6\uB4C6\uE8DD\u741F\u4BBD\u8B8A" + + "\u703E\uB566\u4803\uF60E\u6135\u57B9\u86C1\u1D9E" + + "\uE1F8\u9811\u69D9\u8E94\u9B1E\u87E9\uCE55\u28DF" + + "\u8CA1\u890D\uBFE6\u4268\u4199\u2D0F\uB054\uBB16"; + + private static final byte[] S = new byte[256]; + + private static final byte[] Si = new byte[256]; + + private static final int[] T1 = new int[256]; + + private static final int[] T2 = new int[256]; + + private static final int[] T3 = new int[256]; + + private static final int[] T4 = new int[256]; + + private static final int[] T5 = new int[256]; + + private static final int[] T6 = new int[256]; + + private static final int[] T7 = new int[256]; + + private static final int[] T8 = new int[256]; + + private static final int[] U1 = new int[256]; + + private static final int[] U2 = new int[256]; + + private static final int[] U3 = new int[256]; + + private static final int[] U4 = new int[256]; + + private static final byte[] rcon = new byte[30]; + + private static final int[][][] shifts = new int[][][] { + { { 0, 0 }, { 1, 3 }, + { 2, 2 }, { 3, 1 } }, + { { 0, 0 }, { 1, 5 }, + { 2, 4 }, { 3, 3 } }, + { { 0, 0 }, { 1, 7 }, + { 3, 5 }, { 4, 4 } } }; + + /** + * KAT vector (from ecb_vk): + * I=96 + * KEY=0000000000000000000000010000000000000000000000000000000000000000 + * CT=E44429474D6FC3084EB2A6B8B46AF754 + */ + private static final byte[] KAT_KEY = Util.toBytesFromString("0000000000000000000000010000000000000000000000000000000000000000"); + + private static final byte[] KAT_CT = Util.toBytesFromString("E44429474D6FC3084EB2A6B8B46AF754"); + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + // Static code - to intialise lookup tables -------------------------------- + + static + { + long time = System.currentTimeMillis(); + + int ROOT = 0x11B; + int i, j = 0; + + // S-box, inverse S-box, T-boxes, U-boxes + int s, s2, s3, i2, i4, i8, i9, ib, id, ie, t; + char c; + for (i = 0; i < 256; i++) + { + c = SS.charAt(i >>> 1); + S[i] = (byte) (((i & 1) == 0) ? c >>> 8 : c & 0xFF); + s = S[i] & 0xFF; + Si[s] = (byte) i; + s2 = s << 1; + if (s2 >= 0x100) + { + s2 ^= ROOT; + } + s3 = s2 ^ s; + i2 = i << 1; + if (i2 >= 0x100) + { + i2 ^= ROOT; + } + i4 = i2 << 1; + if (i4 >= 0x100) + { + i4 ^= ROOT; + } + i8 = i4 << 1; + if (i8 >= 0x100) + { + i8 ^= ROOT; + } + i9 = i8 ^ i; + ib = i9 ^ i2; + id = i9 ^ i4; + ie = i8 ^ i4 ^ i2; + + T1[i] = t = (s2 << 24) | (s << 16) | (s << 8) | s3; + T2[i] = (t >>> 8) | (t << 24); + T3[i] = (t >>> 16) | (t << 16); + T4[i] = (t >>> 24) | (t << 8); + + T5[s] = U1[i] = t = (ie << 24) | (i9 << 16) | (id << 8) | ib; + T6[s] = U2[i] = (t >>> 8) | (t << 24); + T7[s] = U3[i] = (t >>> 16) | (t << 16); + T8[s] = U4[i] = (t >>> 24) | (t << 8); + } + // + // round constants + // + int r = 1; + rcon[0] = 1; + for (i = 1; i < 30; i++) + { + r <<= 1; + if (r >= 0x100) + { + r ^= ROOT; + } + rcon[i] = (byte) r; + } + + time = System.currentTimeMillis() - time; + + if (DEBUG && debuglevel > 8) + { + System.out.println("=========="); + System.out.println(); + System.out.println("Static Data"); + System.out.println(); + System.out.println("S[]:"); + for (i = 0; i < 16; i++) + { + for (j = 0; j < 16; j++) + { + System.out.print("0x" + Util.toString(S[i * 16 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("Si[]:"); + for (i = 0; i < 16; i++) + { + for (j = 0; j < 16; j++) + { + System.out.print("0x" + Util.toString(Si[i * 16 + j]) + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("T1[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T1[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T2[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T2[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T3[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T3[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T4[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T4[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T5[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T6[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T6[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T7[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T7[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("T8[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(T8[i * 4 + j]) + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("U1[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(U1[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("U2[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(U2[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("U3[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(U3[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("U4[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.println("0x" + Util.toString(U4[i * 4 + j]) + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("rcon[]:"); + for (i = 0; i < 5; i++) + { + for (j = 0; j < 6; j++) + { + System.out.print("0x" + Util.toString(rcon[i * 6 + j]) + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("Total initialization time: " + time + " ms."); + System.out.println(); + } + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Rijndael() + { + super(Registry.RIJNDAEL_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns the number of rounds for a given Rijndael's key and block + * sizes.

+ * + * @param ks the size of the user key material in bytes. + * @param bs the desired block size in bytes. + * @return the number of rounds for a given Rijndael's key and block sizes. + */ + public static int getRounds(int ks, int bs) + { + switch (ks) + { + case 16: + return bs == 16 ? 10 : (bs == 24 ? 12 : 14); + case 24: + return bs != 32 ? 12 : 14; + default: // 32 bytes = 256 bits + return 14; + } + } + + private static void rijndaelEncrypt(byte[] in, int inOffset, byte[] out, + int outOffset, Object sessionKey, int bs) + { + Object[] sKey = (Object[]) sessionKey; // extract encryption round keys + int[][] Ke = (int[][]) sKey[0]; + + int BC = bs / 4; + int ROUNDS = Ke.length - 1; + int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2); + int s1 = shifts[SC][1][0]; + int s2 = shifts[SC][2][0]; + int s3 = shifts[SC][3][0]; + int[] a = new int[BC]; + int[] t = new int[BC]; // temporary work array + int i, tt; + + for (i = 0; i < BC; i++) + { // plaintext to ints + key + t[i] = (in[inOffset++] << 24 | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF)) + ^ Ke[0][i]; + } + + for (int r = 1; r < ROUNDS; r++) + { // apply round transforms + for (i = 0; i < BC; i++) + { + a[i] = (T1[(t[i] >>> 24)] ^ T2[(t[(i + s1) % BC] >>> 16) & 0xFF] + ^ T3[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ T4[t[(i + s3) % BC] & 0xFF]) + ^ Ke[r][i]; + } + + System.arraycopy(a, 0, t, 0, BC); + + if (DEBUG && debuglevel > 6) + { + System.out.println("CT" + r + "=" + Util.toString(t)); + } + } + + for (i = 0; i < BC; i++) + { // last round is special + tt = Ke[ROUNDS][i]; + out[outOffset++] = (byte) (S[(t[i] >>> 24)] ^ (tt >>> 24)); + out[outOffset++] = (byte) (S[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16)); + out[outOffset++] = (byte) (S[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8)); + out[outOffset++] = (byte) (S[t[(i + s3) % BC] & 0xFF] ^ tt); + } + + if (DEBUG && debuglevel > 6) + { + System.out.println("CT=" + Util.toString(out, outOffset - bs + 1, bs)); + System.out.println(); + } + } + + private static void rijndaelDecrypt(byte[] in, int inOffset, byte[] out, + int outOffset, Object sessionKey, int bs) + { + Object[] sKey = (Object[]) sessionKey; // extract decryption round keys + int[][] Kd = (int[][]) sKey[1]; + + int BC = bs / 4; + int ROUNDS = Kd.length - 1; + int SC = BC == 4 ? 0 : (BC == 6 ? 1 : 2); + int s1 = shifts[SC][1][1]; + int s2 = shifts[SC][2][1]; + int s3 = shifts[SC][3][1]; + int[] a = new int[BC]; + int[] t = new int[BC]; // temporary work array + int i, tt; + + for (i = 0; i < BC; i++) + { // ciphertext to ints + key + t[i] = (in[inOffset++] << 24 | (in[inOffset++] & 0xFF) << 16 + | (in[inOffset++] & 0xFF) << 8 | (in[inOffset++] & 0xFF)) + ^ Kd[0][i]; + } + + for (int r = 1; r < ROUNDS; r++) + { // apply round transforms + for (i = 0; i < BC; i++) + { + a[i] = (T5[(t[i] >>> 24)] ^ T6[(t[(i + s1) % BC] >>> 16) & 0xFF] + ^ T7[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ T8[t[(i + s3) % BC] & 0xFF]) + ^ Kd[r][i]; + } + + System.arraycopy(a, 0, t, 0, BC); + + if (DEBUG && debuglevel > 6) + { + System.out.println("PT" + r + "=" + Util.toString(t)); + } + } + + for (i = 0; i < BC; i++) + { // last round is special + tt = Kd[ROUNDS][i]; + out[outOffset++] = (byte) (Si[(t[i] >>> 24)] ^ (tt >>> 24)); + out[outOffset++] = (byte) (Si[(t[(i + s1) % BC] >>> 16) & 0xFF] ^ (tt >>> 16)); + out[outOffset++] = (byte) (Si[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8)); + out[outOffset++] = (byte) (Si[t[(i + s3) % BC] & 0xFF] ^ tt); + } + + if (DEBUG && debuglevel > 6) + { + System.out.println("PT=" + Util.toString(out, outOffset - bs + 1, bs)); + System.out.println(); + } + } + + private static void aesEncrypt(byte[] in, int i, byte[] out, int j, Object key) + { + int[][] Ke = (int[][]) ((Object[]) key)[0]; // extract encryption round keys + int ROUNDS = Ke.length - 1; + int[] Ker = Ke[0]; + + // plaintext to ints + key + int t0 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Ker[0]; + int t1 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Ker[1]; + int t2 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Ker[2]; + int t3 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Ker[3]; + + int a0, a1, a2, a3; + for (int r = 1; r < ROUNDS; r++) + { // apply round transforms + Ker = Ke[r]; + a0 = (T1[(t0 >>> 24)] ^ T2[(t1 >>> 16) & 0xFF] ^ T3[(t2 >>> 8) & 0xFF] ^ T4[t3 & 0xFF]) + ^ Ker[0]; + a1 = (T1[(t1 >>> 24)] ^ T2[(t2 >>> 16) & 0xFF] ^ T3[(t3 >>> 8) & 0xFF] ^ T4[t0 & 0xFF]) + ^ Ker[1]; + a2 = (T1[(t2 >>> 24)] ^ T2[(t3 >>> 16) & 0xFF] ^ T3[(t0 >>> 8) & 0xFF] ^ T4[t1 & 0xFF]) + ^ Ker[2]; + a3 = (T1[(t3 >>> 24)] ^ T2[(t0 >>> 16) & 0xFF] ^ T3[(t1 >>> 8) & 0xFF] ^ T4[t2 & 0xFF]) + ^ Ker[3]; + t0 = a0; + t1 = a1; + t2 = a2; + t3 = a3; + + if (DEBUG && debuglevel > 6) + { + System.out.println("CT" + r + "=" + Util.toString(t0) + + Util.toString(t1) + Util.toString(t2) + + Util.toString(t3)); + } + } + + // last round is special + Ker = Ke[ROUNDS]; + int tt = Ker[0]; + out[j++] = (byte) (S[(t0 >>> 24)] ^ (tt >>> 24)); + out[j++] = (byte) (S[(t1 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (S[(t2 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte) (S[t3 & 0xFF] ^ tt); + tt = Ker[1]; + out[j++] = (byte) (S[(t1 >>> 24)] ^ (tt >>> 24)); + out[j++] = (byte) (S[(t2 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (S[(t3 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte) (S[t0 & 0xFF] ^ tt); + tt = Ker[2]; + out[j++] = (byte) (S[(t2 >>> 24)] ^ (tt >>> 24)); + out[j++] = (byte) (S[(t3 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (S[(t0 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte) (S[t1 & 0xFF] ^ tt); + tt = Ker[3]; + out[j++] = (byte) (S[(t3 >>> 24)] ^ (tt >>> 24)); + out[j++] = (byte) (S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (S[(t1 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte) (S[t2 & 0xFF] ^ tt); + + if (DEBUG && debuglevel > 6) + { + System.out.println("CT=" + Util.toString(out, j - 15, 16)); + System.out.println(); + } + } + + private static void aesDecrypt(byte[] in, int i, byte[] out, int j, Object key) + { + int[][] Kd = (int[][]) ((Object[]) key)[1]; // extract decryption round keys + int ROUNDS = Kd.length - 1; + int[] Kdr = Kd[0]; + + // ciphertext to ints + key + int t0 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Kdr[0]; + int t1 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Kdr[1]; + int t2 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Kdr[2]; + int t3 = (in[i++] << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ Kdr[3]; + + int a0, a1, a2, a3; + for (int r = 1; r < ROUNDS; r++) + { // apply round transforms + Kdr = Kd[r]; + a0 = (T5[(t0 >>> 24)] ^ T6[(t3 >>> 16) & 0xFF] ^ T7[(t2 >>> 8) & 0xFF] ^ T8[t1 & 0xFF]) + ^ Kdr[0]; + a1 = (T5[(t1 >>> 24)] ^ T6[(t0 >>> 16) & 0xFF] ^ T7[(t3 >>> 8) & 0xFF] ^ T8[t2 & 0xFF]) + ^ Kdr[1]; + a2 = (T5[(t2 >>> 24)] ^ T6[(t1 >>> 16) & 0xFF] ^ T7[(t0 >>> 8) & 0xFF] ^ T8[t3 & 0xFF]) + ^ Kdr[2]; + a3 = (T5[(t3 >>> 24)] ^ T6[(t2 >>> 16) & 0xFF] ^ T7[(t1 >>> 8) & 0xFF] ^ T8[t0 & 0xFF]) + ^ Kdr[3]; + t0 = a0; + t1 = a1; + t2 = a2; + t3 = a3; + + if (DEBUG && debuglevel > 6) + { + System.out.println("PT" + r + "=" + Util.toString(t0) + + Util.toString(t1) + Util.toString(t2) + + Util.toString(t3)); + } + } + + // last round is special + Kdr = Kd[ROUNDS]; + int tt = Kdr[0]; + out[j++] = (byte) (Si[(t0 >>> 24)] ^ (tt >>> 24)); + out[j++] = (byte) (Si[(t3 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (Si[(t2 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte) (Si[t1 & 0xFF] ^ tt); + tt = Kdr[1]; + out[j++] = (byte) (Si[(t1 >>> 24)] ^ (tt >>> 24)); + out[j++] = (byte) (Si[(t0 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (Si[(t3 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte) (Si[t2 & 0xFF] ^ tt); + tt = Kdr[2]; + out[j++] = (byte) (Si[(t2 >>> 24)] ^ (tt >>> 24)); + out[j++] = (byte) (Si[(t1 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (Si[(t0 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte) (Si[t3 & 0xFF] ^ tt); + tt = Kdr[3]; + out[j++] = (byte) (Si[(t3 >>> 24)] ^ (tt >>> 24)); + out[j++] = (byte) (Si[(t2 >>> 16) & 0xFF] ^ (tt >>> 16)); + out[j++] = (byte) (Si[(t1 >>> 8) & 0xFF] ^ (tt >>> 8)); + out[j++] = (byte) (Si[t0 & 0xFF] ^ tt); + + if (DEBUG && debuglevel > 6) + { + System.out.println("PT=" + Util.toString(out, j - 15, 16)); + System.out.println(); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Rijndael result = new Rijndael(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(128 / 8)); + al.add(new Integer(192 / 8)); + al.add(new Integer(256 / 8)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(128 / 8)); + al.add(new Integer(192 / 8)); + al.add(new Integer(256 / 8)); + + return Collections.unmodifiableList(al).iterator(); + } + + /** + * Expands a user-supplied key material into a session key for a designated + * block size. + * + * @param k the 128/192/256-bit user-key to use. + * @param bs the block size in bytes of this Rijndael. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16, 24 or 32. + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] k, int bs) throws InvalidKeyException + { + if (k == null) + { + throw new InvalidKeyException("Empty key"); + } + if (!(k.length == 16 || k.length == 24 || k.length == 32)) + { + throw new InvalidKeyException("Incorrect key length"); + } + if (!(bs == 16 || bs == 24 || bs == 32)) + { + throw new IllegalArgumentException(); + } + + int ROUNDS = getRounds(k.length, bs); + int BC = bs / 4; + int[][] Ke = new int[ROUNDS + 1][BC]; // encryption round keys + int[][] Kd = new int[ROUNDS + 1][BC]; // decryption round keys + int ROUND_KEY_COUNT = (ROUNDS + 1) * BC; + int KC = k.length / 4; + int[] tk = new int[KC]; + int i, j; + + // copy user material bytes into temporary ints + for (i = 0, j = 0; i < KC;) + { + tk[i++] = k[j++] << 24 | (k[j++] & 0xFF) << 16 | (k[j++] & 0xFF) << 8 + | (k[j++] & 0xFF); + } + // copy values into round key arrays + int t = 0; + for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) + { + Ke[t / BC][t % BC] = tk[j]; + Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; + } + int tt, rconpointer = 0; + while (t < ROUND_KEY_COUNT) + { + // extrapolate using phi (the round key evolution function) + tt = tk[KC - 1]; + tk[0] ^= (S[(tt >>> 16) & 0xFF] & 0xFF) << 24 + ^ (S[(tt >>> 8) & 0xFF] & 0xFF) << 16 + ^ (S[tt & 0xFF] & 0xFF) << 8 ^ (S[(tt >>> 24)] & 0xFF) + ^ rcon[rconpointer++] << 24; + if (KC != 8) + { + for (i = 1, j = 0; i < KC;) + { + tk[i++] ^= tk[j++]; + } + } + else + { + for (i = 1, j = 0; i < KC / 2;) + { + tk[i++] ^= tk[j++]; + } + tt = tk[KC / 2 - 1]; + tk[KC / 2] ^= (S[tt & 0xFF] & 0xFF) + ^ (S[(tt >>> 8) & 0xFF] & 0xFF) << 8 + ^ (S[(tt >>> 16) & 0xFF] & 0xFF) << 16 + ^ S[(tt >>> 24) & 0xFF] << 24; + for (j = KC / 2, i = j + 1; i < KC;) + { + tk[i++] ^= tk[j++]; + } + } + // copy values into round key arrays + for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) + { + Ke[t / BC][t % BC] = tk[j]; + Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; + } + } + for (int r = 1; r < ROUNDS; r++) + { // inverse MixColumn where needed + for (j = 0; j < BC; j++) + { + tt = Kd[r][j]; + Kd[r][j] = U1[(tt >>> 24)] ^ U2[(tt >>> 16) & 0xFF] + ^ U3[(tt >>> 8) & 0xFF] ^ U4[tt & 0xFF]; + } + } + + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (!(bs == 16 || bs == 24 || bs == 32)) + { + throw new IllegalArgumentException(); + } + + if (bs == DEFAULT_BLOCK_SIZE) + { + aesEncrypt(in, i, out, j, k); + } + else + { + rijndaelEncrypt(in, i, out, j, k, bs); + } + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (!(bs == 16 || bs == 24 || bs == 32)) + { + throw new IllegalArgumentException(); + } + + if (bs == DEFAULT_BLOCK_SIZE) + { + aesDecrypt(in, i, out, j, k); + } + else + { + rijndaelDecrypt(in, i, out, j, k, bs); + } + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + { + result = testKat(KAT_KEY, KAT_CT); + } + valid = new Boolean(result); + } + return valid.booleanValue(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Serpent.java b/gnu/javax/crypto/cipher/Serpent.java new file mode 100644 index 000000000..b323b5017 --- /dev/null +++ b/gnu/javax/crypto/cipher/Serpent.java @@ -0,0 +1,1830 @@ +/* Serpent.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + *

Serpent is a 32-round substitution-permutation network block cipher, + * operating on 128-bit blocks and accepting keys of 128, 192, and 256 bits in + * length. At each round the plaintext is XORed with a 128 bit portion of the + * session key -- a 4224 bit key computed from the input key -- then one of + * eight S-boxes are applied, and finally a simple linear transformation is + * done. Decryption does the exact same thing in reverse order, and using the + * eight inverses of the S-boxes.

+ * + *

Serpent was designed by Ross Anderson, Eli Biham, and Lars Knudsen as a + * proposed cipher for the Advanced Encryption Standard.

+ * + *

Serpent can be sped up greatly by replacing S-box substitution with a + * sequence of binary operations, and the optimal implementation depends + * upon finding the fastest sequence of binary operations that reproduce this + * substitution. This implementation uses the S-boxes discovered by + * Dag Arne Osvik, which are + * optimized for the Pentium family of processors.

+ * + *

References:

+ * + *
    + *
  1. Serpent: A + * Candidate Block Cipher for the Advanced Encryption Standard.
  2. + *
+ */ +public class Serpent extends BaseCipher +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int DEFAULT_KEY_SIZE = 16; + + private static final int DEFAULT_BLOCK_SIZE = 16; + + private static final int ROUNDS = 32; + + /** The fractional part of the golden ratio, (sqrt(5)+1)/2. */ + private static final int PHI = 0x9e3779b9; + + /** + * KAT vector (from ecb_vk): + * I=9 + * KEY=008000000000000000000000000000000000000000000000 + * CT=5587B5BCB9EE5A28BA2BACC418005240 + */ + private static final byte[] KAT_KEY = Util.toReversedBytesFromString("008000000000000000000000000000000000000000000000"); + + private static final byte[] KAT_CT = Util.toReversedBytesFromString("5587B5BCB9EE5A28BA2BACC418005240"); + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + private int x0, x1, x2, x3, x4; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial zero-argument constructor. */ + public Serpent() + { + super(Registry.SERPENT_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Serpent result = new Serpent(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + return Collections.singleton(new Integer(DEFAULT_BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + ArrayList keySizes = new ArrayList(); + keySizes.add(new Integer(16)); + keySizes.add(new Integer(24)); + keySizes.add(new Integer(32)); + + return Collections.unmodifiableList(keySizes).iterator(); + } + + public Object makeKey(byte[] kb, int blockSize) throws InvalidKeyException + { + // Not strictly true, but here to conform with the AES proposal. + // This restriction can be removed if deemed necessary. + if (kb.length != 16 && kb.length != 24 && kb.length != 32) + { + throw new InvalidKeyException("Key length is not 16, 24, or 32 bytes"); + } + Key key = new Key(); + + // Here w is our "pre-key". + int[] w = new int[4 * (ROUNDS + 1)]; + int i, j; + for (i = 0, j = 0; i < 8 && j < kb.length; i++) + { + w[i] = (kb[j++] & 0xff) | (kb[j++] & 0xff) << 8 + | (kb[j++] & 0xff) << 16 | (kb[j++] & 0xff) << 24; + } + // Pad key if < 256 bits. + if (i != 8) + { + w[i] = 1; + } + // Transform using w_i-8 ... w_i-1 + for (i = 8, j = 0; i < 16; i++) + { + int t = w[j] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ j++; + w[i] = t << 11 | t >>> 21; + } + // Translate by 8. + for (i = 0; i < 8; i++) + { + w[i] = w[i + 8]; + } + // Transform the rest of the key. + for (; i < w.length; i++) + { + int t = w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i; + w[i] = t << 11 | t >>> 21; + } + + // After these s-boxes the pre-key (w, above) will become the + // session key (key, below). + sbox3(w[0], w[1], w[2], w[3]); + key.k0 = x0; + key.k1 = x1; + key.k2 = x2; + key.k3 = x3; + sbox2(w[4], w[5], w[6], w[7]); + key.k4 = x0; + key.k5 = x1; + key.k6 = x2; + key.k7 = x3; + sbox1(w[8], w[9], w[10], w[11]); + key.k8 = x0; + key.k9 = x1; + key.k10 = x2; + key.k11 = x3; + sbox0(w[12], w[13], w[14], w[15]); + key.k12 = x0; + key.k13 = x1; + key.k14 = x2; + key.k15 = x3; + sbox7(w[16], w[17], w[18], w[19]); + key.k16 = x0; + key.k17 = x1; + key.k18 = x2; + key.k19 = x3; + sbox6(w[20], w[21], w[22], w[23]); + key.k20 = x0; + key.k21 = x1; + key.k22 = x2; + key.k23 = x3; + sbox5(w[24], w[25], w[26], w[27]); + key.k24 = x0; + key.k25 = x1; + key.k26 = x2; + key.k27 = x3; + sbox4(w[28], w[29], w[30], w[31]); + key.k28 = x0; + key.k29 = x1; + key.k30 = x2; + key.k31 = x3; + sbox3(w[32], w[33], w[34], w[35]); + key.k32 = x0; + key.k33 = x1; + key.k34 = x2; + key.k35 = x3; + sbox2(w[36], w[37], w[38], w[39]); + key.k36 = x0; + key.k37 = x1; + key.k38 = x2; + key.k39 = x3; + sbox1(w[40], w[41], w[42], w[43]); + key.k40 = x0; + key.k41 = x1; + key.k42 = x2; + key.k43 = x3; + sbox0(w[44], w[45], w[46], w[47]); + key.k44 = x0; + key.k45 = x1; + key.k46 = x2; + key.k47 = x3; + sbox7(w[48], w[49], w[50], w[51]); + key.k48 = x0; + key.k49 = x1; + key.k50 = x2; + key.k51 = x3; + sbox6(w[52], w[53], w[54], w[55]); + key.k52 = x0; + key.k53 = x1; + key.k54 = x2; + key.k55 = x3; + sbox5(w[56], w[57], w[58], w[59]); + key.k56 = x0; + key.k57 = x1; + key.k58 = x2; + key.k59 = x3; + sbox4(w[60], w[61], w[62], w[63]); + key.k60 = x0; + key.k61 = x1; + key.k62 = x2; + key.k63 = x3; + sbox3(w[64], w[65], w[66], w[67]); + key.k64 = x0; + key.k65 = x1; + key.k66 = x2; + key.k67 = x3; + sbox2(w[68], w[69], w[70], w[71]); + key.k68 = x0; + key.k69 = x1; + key.k70 = x2; + key.k71 = x3; + sbox1(w[72], w[73], w[74], w[75]); + key.k72 = x0; + key.k73 = x1; + key.k74 = x2; + key.k75 = x3; + sbox0(w[76], w[77], w[78], w[79]); + key.k76 = x0; + key.k77 = x1; + key.k78 = x2; + key.k79 = x3; + sbox7(w[80], w[81], w[82], w[83]); + key.k80 = x0; + key.k81 = x1; + key.k82 = x2; + key.k83 = x3; + sbox6(w[84], w[85], w[86], w[87]); + key.k84 = x0; + key.k85 = x1; + key.k86 = x2; + key.k87 = x3; + sbox5(w[88], w[89], w[90], w[91]); + key.k88 = x0; + key.k89 = x1; + key.k90 = x2; + key.k91 = x3; + sbox4(w[92], w[93], w[94], w[95]); + key.k92 = x0; + key.k93 = x1; + key.k94 = x2; + key.k95 = x3; + sbox3(w[96], w[97], w[98], w[99]); + key.k96 = x0; + key.k97 = x1; + key.k98 = x2; + key.k99 = x3; + sbox2(w[100], w[101], w[102], w[103]); + key.k100 = x0; + key.k101 = x1; + key.k102 = x2; + key.k103 = x3; + sbox1(w[104], w[105], w[106], w[107]); + key.k104 = x0; + key.k105 = x1; + key.k106 = x2; + key.k107 = x3; + sbox0(w[108], w[109], w[110], w[111]); + key.k108 = x0; + key.k109 = x1; + key.k110 = x2; + key.k111 = x3; + sbox7(w[112], w[113], w[114], w[115]); + key.k112 = x0; + key.k113 = x1; + key.k114 = x2; + key.k115 = x3; + sbox6(w[116], w[117], w[118], w[119]); + key.k116 = x0; + key.k117 = x1; + key.k118 = x2; + key.k119 = x3; + sbox5(w[120], w[121], w[122], w[123]); + key.k120 = x0; + key.k121 = x1; + key.k122 = x2; + key.k123 = x3; + sbox4(w[124], w[125], w[126], w[127]); + key.k124 = x0; + key.k125 = x1; + key.k126 = x2; + key.k127 = x3; + sbox3(w[128], w[129], w[130], w[131]); + key.k128 = x0; + key.k129 = x1; + key.k130 = x2; + key.k131 = x3; + + return key; + } + + public synchronized void encrypt(byte[] in, int i, byte[] out, int o, + Object K, int bs) + { + Key key = (Key) K; + + x0 = (in[i] & 0xff) | (in[i + 1] & 0xff) << 8 | (in[i + 2] & 0xff) << 16 + | (in[i + 3] & 0xff) << 24; + x1 = (in[i + 4] & 0xff) | (in[i + 5] & 0xff) << 8 + | (in[i + 6] & 0xff) << 16 | (in[i + 7] & 0xff) << 24; + x2 = (in[i + 8] & 0xff) | (in[i + 9] & 0xff) << 8 + | (in[i + 10] & 0xff) << 16 | (in[i + 11] & 0xff) << 24; + x3 = (in[i + 12] & 0xff) | (in[i + 13] & 0xff) << 8 + | (in[i + 14] & 0xff) << 16 | (in[i + 15] & 0xff) << 24; + + x0 ^= key.k0; + x1 ^= key.k1; + x2 ^= key.k2; + x3 ^= key.k3; + sbox0(); + x1 ^= key.k4; + x4 ^= key.k5; + x2 ^= key.k6; + x0 ^= key.k7; + sbox1(); + x0 ^= key.k8; + x4 ^= key.k9; + x2 ^= key.k10; + x1 ^= key.k11; + sbox2(); + x2 ^= key.k12; + x1 ^= key.k13; + x4 ^= key.k14; + x3 ^= key.k15; + sbox3(); + x1 ^= key.k16; + x4 ^= key.k17; + x3 ^= key.k18; + x0 ^= key.k19; + sbox4(); + x4 ^= key.k20; + x2 ^= key.k21; + x1 ^= key.k22; + x0 ^= key.k23; + sbox5(); + x2 ^= key.k24; + x0 ^= key.k25; + x4 ^= key.k26; + x1 ^= key.k27; + sbox6(); + x2 ^= key.k28; + x0 ^= key.k29; + x3 ^= key.k30; + x4 ^= key.k31; + sbox7(); + x0 = x3; + x3 = x2; + x2 = x4; + + x0 ^= key.k32; + x1 ^= key.k33; + x2 ^= key.k34; + x3 ^= key.k35; + sbox0(); + x1 ^= key.k36; + x4 ^= key.k37; + x2 ^= key.k38; + x0 ^= key.k39; + sbox1(); + x0 ^= key.k40; + x4 ^= key.k41; + x2 ^= key.k42; + x1 ^= key.k43; + sbox2(); + x2 ^= key.k44; + x1 ^= key.k45; + x4 ^= key.k46; + x3 ^= key.k47; + sbox3(); + x1 ^= key.k48; + x4 ^= key.k49; + x3 ^= key.k50; + x0 ^= key.k51; + sbox4(); + x4 ^= key.k52; + x2 ^= key.k53; + x1 ^= key.k54; + x0 ^= key.k55; + sbox5(); + x2 ^= key.k56; + x0 ^= key.k57; + x4 ^= key.k58; + x1 ^= key.k59; + sbox6(); + x2 ^= key.k60; + x0 ^= key.k61; + x3 ^= key.k62; + x4 ^= key.k63; + sbox7(); + x0 = x3; + x3 = x2; + x2 = x4; + + x0 ^= key.k64; + x1 ^= key.k65; + x2 ^= key.k66; + x3 ^= key.k67; + sbox0(); + x1 ^= key.k68; + x4 ^= key.k69; + x2 ^= key.k70; + x0 ^= key.k71; + sbox1(); + x0 ^= key.k72; + x4 ^= key.k73; + x2 ^= key.k74; + x1 ^= key.k75; + sbox2(); + x2 ^= key.k76; + x1 ^= key.k77; + x4 ^= key.k78; + x3 ^= key.k79; + sbox3(); + x1 ^= key.k80; + x4 ^= key.k81; + x3 ^= key.k82; + x0 ^= key.k83; + sbox4(); + x4 ^= key.k84; + x2 ^= key.k85; + x1 ^= key.k86; + x0 ^= key.k87; + sbox5(); + x2 ^= key.k88; + x0 ^= key.k89; + x4 ^= key.k90; + x1 ^= key.k91; + sbox6(); + x2 ^= key.k92; + x0 ^= key.k93; + x3 ^= key.k94; + x4 ^= key.k95; + sbox7(); + x0 = x3; + x3 = x2; + x2 = x4; + + x0 ^= key.k96; + x1 ^= key.k97; + x2 ^= key.k98; + x3 ^= key.k99; + sbox0(); + x1 ^= key.k100; + x4 ^= key.k101; + x2 ^= key.k102; + x0 ^= key.k103; + sbox1(); + x0 ^= key.k104; + x4 ^= key.k105; + x2 ^= key.k106; + x1 ^= key.k107; + sbox2(); + x2 ^= key.k108; + x1 ^= key.k109; + x4 ^= key.k110; + x3 ^= key.k111; + sbox3(); + x1 ^= key.k112; + x4 ^= key.k113; + x3 ^= key.k114; + x0 ^= key.k115; + sbox4(); + x4 ^= key.k116; + x2 ^= key.k117; + x1 ^= key.k118; + x0 ^= key.k119; + sbox5(); + x2 ^= key.k120; + x0 ^= key.k121; + x4 ^= key.k122; + x1 ^= key.k123; + sbox6(); + x2 ^= key.k124; + x0 ^= key.k125; + x3 ^= key.k126; + x4 ^= key.k127; + sbox7noLT(); + x0 = x3; + x3 = x2; + x2 = x4; + x0 ^= key.k128; + x1 ^= key.k129; + x2 ^= key.k130; + x3 ^= key.k131; + + out[o] = (byte) x0; + out[o + 1] = (byte) (x0 >>> 8); + out[o + 2] = (byte) (x0 >>> 16); + out[o + 3] = (byte) (x0 >>> 24); + out[o + 4] = (byte) x1; + out[o + 5] = (byte) (x1 >>> 8); + out[o + 6] = (byte) (x1 >>> 16); + out[o + 7] = (byte) (x1 >>> 24); + out[o + 8] = (byte) x2; + out[o + 9] = (byte) (x2 >>> 8); + out[o + 10] = (byte) (x2 >>> 16); + out[o + 11] = (byte) (x2 >>> 24); + out[o + 12] = (byte) x3; + out[o + 13] = (byte) (x3 >>> 8); + out[o + 14] = (byte) (x3 >>> 16); + out[o + 15] = (byte) (x3 >>> 24); + } + + public synchronized void decrypt(byte[] in, int i, byte[] out, int o, + Object K, int bs) + { + Key key = (Key) K; + + x0 = (in[i] & 0xff) | (in[i + 1] & 0xff) << 8 | (in[i + 2] & 0xff) << 16 + | (in[i + 3] & 0xff) << 24; + x1 = (in[i + 4] & 0xff) | (in[i + 5] & 0xff) << 8 + | (in[i + 6] & 0xff) << 16 | (in[i + 7] & 0xff) << 24; + x2 = (in[i + 8] & 0xff) | (in[i + 9] & 0xff) << 8 + | (in[i + 10] & 0xff) << 16 | (in[i + 11] & 0xff) << 24; + x3 = (in[i + 12] & 0xff) | (in[i + 13] & 0xff) << 8 + | (in[i + 14] & 0xff) << 16 | (in[i + 15] & 0xff) << 24; + + x0 ^= key.k128; + x1 ^= key.k129; + x2 ^= key.k130; + x3 ^= key.k131; + sboxI7noLT(); + x3 ^= key.k124; + x0 ^= key.k125; + x1 ^= key.k126; + x4 ^= key.k127; + sboxI6(); + x0 ^= key.k120; + x1 ^= key.k121; + x2 ^= key.k122; + x4 ^= key.k123; + sboxI5(); + x1 ^= key.k116; + x3 ^= key.k117; + x4 ^= key.k118; + x2 ^= key.k119; + sboxI4(); + x1 ^= key.k112; + x2 ^= key.k113; + x4 ^= key.k114; + x0 ^= key.k115; + sboxI3(); + x0 ^= key.k108; + x1 ^= key.k109; + x4 ^= key.k110; + x2 ^= key.k111; + sboxI2(); + x1 ^= key.k104; + x3 ^= key.k105; + x4 ^= key.k106; + x2 ^= key.k107; + sboxI1(); + x0 ^= key.k100; + x1 ^= key.k101; + x2 ^= key.k102; + x4 ^= key.k103; + sboxI0(); + x0 ^= key.k96; + x3 ^= key.k97; + x1 ^= key.k98; + x4 ^= key.k99; + sboxI7(); + x1 = x3; + x3 = x4; + x4 = x2; + + x3 ^= key.k92; + x0 ^= key.k93; + x1 ^= key.k94; + x4 ^= key.k95; + sboxI6(); + x0 ^= key.k88; + x1 ^= key.k89; + x2 ^= key.k90; + x4 ^= key.k91; + sboxI5(); + x1 ^= key.k84; + x3 ^= key.k85; + x4 ^= key.k86; + x2 ^= key.k87; + sboxI4(); + x1 ^= key.k80; + x2 ^= key.k81; + x4 ^= key.k82; + x0 ^= key.k83; + sboxI3(); + x0 ^= key.k76; + x1 ^= key.k77; + x4 ^= key.k78; + x2 ^= key.k79; + sboxI2(); + x1 ^= key.k72; + x3 ^= key.k73; + x4 ^= key.k74; + x2 ^= key.k75; + sboxI1(); + x0 ^= key.k68; + x1 ^= key.k69; + x2 ^= key.k70; + x4 ^= key.k71; + sboxI0(); + x0 ^= key.k64; + x3 ^= key.k65; + x1 ^= key.k66; + x4 ^= key.k67; + sboxI7(); + x1 = x3; + x3 = x4; + x4 = x2; + + x3 ^= key.k60; + x0 ^= key.k61; + x1 ^= key.k62; + x4 ^= key.k63; + sboxI6(); + x0 ^= key.k56; + x1 ^= key.k57; + x2 ^= key.k58; + x4 ^= key.k59; + sboxI5(); + x1 ^= key.k52; + x3 ^= key.k53; + x4 ^= key.k54; + x2 ^= key.k55; + sboxI4(); + x1 ^= key.k48; + x2 ^= key.k49; + x4 ^= key.k50; + x0 ^= key.k51; + sboxI3(); + x0 ^= key.k44; + x1 ^= key.k45; + x4 ^= key.k46; + x2 ^= key.k47; + sboxI2(); + x1 ^= key.k40; + x3 ^= key.k41; + x4 ^= key.k42; + x2 ^= key.k43; + sboxI1(); + x0 ^= key.k36; + x1 ^= key.k37; + x2 ^= key.k38; + x4 ^= key.k39; + sboxI0(); + x0 ^= key.k32; + x3 ^= key.k33; + x1 ^= key.k34; + x4 ^= key.k35; + sboxI7(); + x1 = x3; + x3 = x4; + x4 = x2; + + x3 ^= key.k28; + x0 ^= key.k29; + x1 ^= key.k30; + x4 ^= key.k31; + sboxI6(); + x0 ^= key.k24; + x1 ^= key.k25; + x2 ^= key.k26; + x4 ^= key.k27; + sboxI5(); + x1 ^= key.k20; + x3 ^= key.k21; + x4 ^= key.k22; + x2 ^= key.k23; + sboxI4(); + x1 ^= key.k16; + x2 ^= key.k17; + x4 ^= key.k18; + x0 ^= key.k19; + sboxI3(); + x0 ^= key.k12; + x1 ^= key.k13; + x4 ^= key.k14; + x2 ^= key.k15; + sboxI2(); + x1 ^= key.k8; + x3 ^= key.k9; + x4 ^= key.k10; + x2 ^= key.k11; + sboxI1(); + x0 ^= key.k4; + x1 ^= key.k5; + x2 ^= key.k6; + x4 ^= key.k7; + sboxI0(); + x2 = x1; + x1 = x3; + x3 = x4; + + x0 ^= key.k0; + x1 ^= key.k1; + x2 ^= key.k2; + x3 ^= key.k3; + + out[o] = (byte) x0; + out[o + 1] = (byte) (x0 >>> 8); + out[o + 2] = (byte) (x0 >>> 16); + out[o + 3] = (byte) (x0 >>> 24); + out[o + 4] = (byte) x1; + out[o + 5] = (byte) (x1 >>> 8); + out[o + 6] = (byte) (x1 >>> 16); + out[o + 7] = (byte) (x1 >>> 24); + out[o + 8] = (byte) x2; + out[o + 9] = (byte) (x2 >>> 8); + out[o + 10] = (byte) (x2 >>> 16); + out[o + 11] = (byte) (x2 >>> 24); + out[o + 12] = (byte) x3; + out[o + 13] = (byte) (x3 >>> 8); + out[o + 14] = (byte) (x3 >>> 16); + out[o + 15] = (byte) (x3 >>> 24); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + { + result = testKat(KAT_KEY, KAT_CT); + } + valid = new Boolean(result); + } + return valid.booleanValue(); + } + + // Own methods. ---------------------------------------------------------- + + // These first few S-boxes operate directly on the "registers", + // x0..x4, and perform the linear transform. + + private void sbox0() + { + x3 ^= x0; + x4 = x1; + x1 &= x3; + x4 ^= x2; + x1 ^= x0; + x0 |= x3; + x0 ^= x4; + x4 ^= x3; + x3 ^= x2; + x2 |= x1; + x2 ^= x4; + x4 ^= -1; + x4 |= x1; + x1 ^= x3; + x1 ^= x4; + x3 |= x0; + x1 ^= x3; + x4 ^= x3; + + x1 = (x1 << 13) | (x1 >>> 19); + x4 ^= x1; + x3 = x1 << 3; + x2 = (x2 << 3) | (x2 >>> 29); + x4 ^= x2; + x0 ^= x2; + x4 = (x4 << 1) | (x4 >>> 31); + x0 ^= x3; + x0 = (x0 << 7) | (x0 >>> 25); + x3 = x4; + x1 ^= x4; + x3 <<= 7; + x1 ^= x0; + x2 ^= x0; + x2 ^= x3; + x1 = (x1 << 5) | (x1 >>> 27); + x2 = (x2 << 22) | (x2 >>> 10); + } + + private void sbox1() + { + x4 = ~x4; + x3 = x1; + x1 ^= x4; + x3 |= x4; + x3 ^= x0; + x0 &= x1; + x2 ^= x3; + x0 ^= x4; + x0 |= x2; + x1 ^= x3; + x0 ^= x1; + x4 &= x2; + x1 |= x4; + x4 ^= x3; + x1 ^= x2; + x3 |= x0; + x1 ^= x3; + x3 = ~x3; + x4 ^= x0; + x3 &= x2; + x4 = ~x4; + x3 ^= x1; + x4 ^= x3; + + x0 = (x0 << 13) | (x0 >>> 19); + x4 ^= x0; + x3 = x0 << 3; + x2 = (x2 << 3) | (x2 >>> 29); + x4 ^= x2; + x1 ^= x2; + x4 = (x4 << 1) | (x4 >>> 31); + x1 ^= x3; + x1 = (x1 << 7) | (x1 >>> 25); + x3 = x4; + x0 ^= x4; + x3 <<= 7; + x0 ^= x1; + x2 ^= x1; + x2 ^= x3; + x0 = (x0 << 5) | (x0 >>> 27); + x2 = (x2 << 22) | (x2 >>> 10); + } + + private void sbox2() + { + x3 = x0; + x0 = x0 & x2; + x0 = x0 ^ x1; + x2 = x2 ^ x4; + x2 = x2 ^ x0; + x1 = x1 | x3; + x1 = x1 ^ x4; + x3 = x3 ^ x2; + x4 = x1; + x1 = x1 | x3; + x1 = x1 ^ x0; + x0 = x0 & x4; + x3 = x3 ^ x0; + x4 = x4 ^ x1; + x4 = x4 ^ x3; + x3 = ~x3; + + x2 = (x2 << 13) | (x2 >>> 19); + x1 ^= x2; + x0 = x2 << 3; + x4 = (x4 << 3) | (x4 >>> 29); + x1 ^= x4; + x3 ^= x4; + x1 = (x1 << 1) | (x1 >>> 31); + x3 ^= x0; + x3 = (x3 << 7) | (x3 >>> 25); + x0 = x1; + x2 ^= x1; + x0 <<= 7; + x2 ^= x3; + x4 ^= x3; + x4 ^= x0; + x2 = (x2 << 5) | (x2 >>> 27); + x4 = (x4 << 22) | (x4 >>> 10); + } + + private void sbox3() + { + x0 = x2; + x2 = x2 | x3; + x3 = x3 ^ x1; + x1 = x1 & x0; + x0 = x0 ^ x4; + x4 = x4 ^ x3; + x3 = x3 & x2; + x0 = x0 | x1; + x3 = x3 ^ x0; + x2 = x2 ^ x1; + x0 = x0 & x2; + x1 = x1 ^ x3; + x0 = x0 ^ x4; + x1 = x1 | x2; + x1 = x1 ^ x4; + x2 = x2 ^ x3; + x4 = x1; + x1 = x1 | x3; + x1 = x1 ^ x2; + + x1 = (x1 << 13) | (x1 >>> 19); + x4 ^= x1; + x2 = x1 << 3; + x3 = (x3 << 3) | (x3 >>> 29); + x4 ^= x3; + x0 ^= x3; + x4 = (x4 << 1) | (x4 >>> 31); + x0 ^= x2; + x0 = (x0 << 7) | (x0 >>> 25); + x2 = x4; + x1 ^= x4; + x2 <<= 7; + x1 ^= x0; + x3 ^= x0; + x3 ^= x2; + x1 = (x1 << 5) | (x1 >>> 27); + x3 = (x3 << 22) | (x3 >>> 10); + } + + private void sbox4() + { + x4 = x4 ^ x0; + x0 = ~x0; + x3 = x3 ^ x0; + x0 = x0 ^ x1; + x2 = x4; + x4 = x4 & x0; + x4 = x4 ^ x3; + x2 = x2 ^ x0; + x1 = x1 ^ x2; + x3 = x3 & x2; + x3 = x3 ^ x1; + x1 = x1 & x4; + x0 = x0 ^ x1; + x2 = x2 | x4; + x2 = x2 ^ x1; + x1 = x1 | x0; + x1 = x1 ^ x3; + x3 = x3 & x0; + x1 = ~x1; + x2 = x2 ^ x3; + + x4 = (x4 << 13) | (x4 >>> 19); + x2 ^= x4; + x3 = x4 << 3; + x1 = (x1 << 3) | (x1 >>> 29); + x2 ^= x1; + x0 ^= x1; + x2 = (x2 << 1) | (x2 >>> 31); + x0 ^= x3; + x0 = (x0 << 7) | (x0 >>> 25); + x3 = x2; + x4 ^= x2; + x3 <<= 7; + x4 ^= x0; + x1 ^= x0; + x1 ^= x3; + x4 = (x4 << 5) | (x4 >>> 27); + x1 = (x1 << 22) | (x1 >>> 10); + } + + private void sbox5() + { + x4 = x4 ^ x2; + x2 = x2 ^ x0; + x0 = ~x0; + x3 = x2; + x2 = x2 & x4; + x1 = x1 ^ x0; + x2 = x2 ^ x1; + x1 = x1 | x3; + x3 = x3 ^ x0; + x0 = x0 & x2; + x0 = x0 ^ x4; + x3 = x3 ^ x2; + x3 = x3 ^ x1; + x1 = x1 ^ x4; + x4 = x4 & x0; + x1 = ~x1; + x4 = x4 ^ x3; + x3 = x3 | x0; + x1 = x1 ^ x3; + + x2 = (x2 << 13) | (x2 >>> 19); + x0 ^= x2; + x3 = x2 << 3; + x4 = (x4 << 3) | (x4 >>> 29); + x0 ^= x4; + x1 ^= x4; + x0 = (x0 << 1) | (x0 >>> 31); + x1 ^= x3; + x1 = (x1 << 7) | (x1 >>> 25); + x3 = x0; + x2 ^= x0; + x3 <<= 7; + x2 ^= x1; + x4 ^= x1; + x4 ^= x3; + x2 = (x2 << 5) | (x2 >>> 27); + x4 = (x4 << 22) | (x4 >>> 10); + } + + private void sbox6() + { + x4 = ~x4; + x3 = x1; + x1 = x1 & x2; + x2 = x2 ^ x3; + x1 = x1 ^ x4; + x4 = x4 | x3; + x0 = x0 ^ x1; + x4 = x4 ^ x2; + x2 = x2 | x0; + x4 = x4 ^ x0; + x3 = x3 ^ x2; + x2 = x2 | x1; + x2 = x2 ^ x4; + x3 = x3 ^ x1; + x3 = x3 ^ x2; + x1 = ~x1; + x4 = x4 & x3; + x4 = x4 ^ x1; + x2 = (x2 << 13) | (x2 >>> 19); + x0 ^= x2; + x1 = x2 << 3; + x3 = (x3 << 3) | (x3 >>> 29); + x0 ^= x3; + x4 ^= x3; + x0 = (x0 << 1) | (x0 >>> 31); + x4 ^= x1; + x4 = (x4 << 7) | (x4 >>> 25); + x1 = x0; + x2 ^= x0; + x1 <<= 7; + x2 ^= x4; + x3 ^= x4; + x3 ^= x1; + x2 = (x2 << 5) | (x2 >>> 27); + x3 = (x3 << 22) | (x3 >>> 10); + } + + private void sbox7() + { + x1 = x3; + x3 = x3 & x0; + x3 = x3 ^ x4; + x4 = x4 & x0; + x1 = x1 ^ x3; + x3 = x3 ^ x0; + x0 = x0 ^ x2; + x2 = x2 | x1; + x2 = x2 ^ x3; + x4 = x4 ^ x0; + x3 = x3 ^ x4; + x4 = x4 & x2; + x4 = x4 ^ x1; + x1 = x1 ^ x3; + x3 = x3 & x2; + x1 = ~x1; + x3 = x3 ^ x1; + x1 = x1 & x2; + x0 = x0 ^ x4; + x1 = x1 ^ x0; + x3 = (x3 << 13) | (x3 >>> 19); + x1 ^= x3; + x0 = x3 << 3; + x4 = (x4 << 3) | (x4 >>> 29); + x1 ^= x4; + x2 ^= x4; + x1 = (x1 << 1) | (x1 >>> 31); + x2 ^= x0; + x2 = (x2 << 7) | (x2 >>> 25); + x0 = x1; + x3 ^= x1; + x0 <<= 7; + x3 ^= x2; + x4 ^= x2; + x4 ^= x0; + x3 = (x3 << 5) | (x3 >>> 27); + x4 = (x4 << 22) | (x4 >>> 10); + } + + /** The final S-box, with no transform. */ + private void sbox7noLT() + { + x1 = x3; + x3 = x3 & x0; + x3 = x3 ^ x4; + x4 = x4 & x0; + x1 = x1 ^ x3; + x3 = x3 ^ x0; + x0 = x0 ^ x2; + x2 = x2 | x1; + x2 = x2 ^ x3; + x4 = x4 ^ x0; + x3 = x3 ^ x4; + x4 = x4 & x2; + x4 = x4 ^ x1; + x1 = x1 ^ x3; + x3 = x3 & x2; + x1 = ~x1; + x3 = x3 ^ x1; + x1 = x1 & x2; + x0 = x0 ^ x4; + x1 = x1 ^ x0; + } + + private void sboxI7noLT() + { + x4 = x2; + x2 ^= x0; + x0 &= x3; + x2 = ~x2; + x4 |= x3; + x3 ^= x1; + x1 |= x0; + x0 ^= x2; + x2 &= x4; + x1 ^= x2; + x2 ^= x0; + x0 |= x2; + x3 &= x4; + x0 ^= x3; + x4 ^= x1; + x3 ^= x4; + x4 |= x0; + x3 ^= x2; + x4 ^= x2; + } + + private void sboxI6() + { + x1 = (x1 >>> 22) | (x1 << 10); + x3 = (x3 >>> 5) | (x3 << 27); + x2 = x0; + x1 ^= x4; + x2 <<= 7; + x3 ^= x4; + x1 ^= x2; + x3 ^= x0; + x4 = (x4 >>> 7) | (x4 << 25); + x0 = (x0 >>> 1) | (x0 << 31); + x0 ^= x3; + x2 = x3 << 3; + x4 ^= x2; + x3 = (x3 >>> 13) | (x3 << 19); + x0 ^= x1; + x4 ^= x1; + x1 = (x1 >>> 3) | (x1 << 29); + x3 ^= x1; + x2 = x1; + x1 &= x3; + x2 ^= x4; + x1 = ~x1; + x4 ^= x0; + x1 ^= x4; + x2 |= x3; + x3 ^= x1; + x4 ^= x2; + x2 ^= x0; + x0 &= x4; + x0 ^= x3; + x3 ^= x4; + x3 |= x1; + x4 ^= x0; + x2 ^= x3; + } + + private void sboxI5() + { + x2 = (x2 >>> 22) | (x2 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x3 = x1; + x2 ^= x4; + x3 <<= 7; + x0 ^= x4; + x2 ^= x3; + x0 ^= x1; + x4 = (x4 >>> 7) | (x4 << 25); + x1 = (x1 >>> 1) | (x1 << 31); + x1 ^= x0; + x3 = x0 << 3; + x4 ^= x3; + x0 = (x0 >>> 13) | (x0 << 19); + x1 ^= x2; + x4 ^= x2; + x2 = (x2 >>> 3) | (x2 << 29); + x1 = ~x1; + x3 = x4; + x2 ^= x1; + x4 |= x0; + x4 ^= x2; + x2 |= x1; + x2 &= x0; + x3 ^= x4; + x2 ^= x3; + x3 |= x0; + x3 ^= x1; + x1 &= x2; + x1 ^= x4; + x3 ^= x2; + x4 &= x3; + x3 ^= x1; + x4 ^= x0; + x4 ^= x3; + x3 = ~x3; + } + + private void sboxI4() + { + x4 = (x4 >>> 22) | (x4 << 10); + x1 = (x1 >>> 5) | (x1 << 27); + x0 = x3; + x4 ^= x2; + x0 <<= 7; + x1 ^= x2; + x4 ^= x0; + x1 ^= x3; + x2 = (x2 >>> 7) | (x2 << 25); + x3 = (x3 >>> 1) | (x3 << 31); + x3 ^= x1; + x0 = x1 << 3; + x2 ^= x0; + x1 = (x1 >>> 13) | (x1 << 19); + x3 ^= x4; + x2 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x0 = x4; + x4 &= x2; + x4 ^= x3; + x3 |= x2; + x3 &= x1; + x0 ^= x4; + x0 ^= x3; + x3 &= x4; + x1 = ~x1; + x2 ^= x0; + x3 ^= x2; + x2 &= x1; + x2 ^= x4; + x1 ^= x3; + x4 &= x1; + x2 ^= x1; + x4 ^= x0; + x4 |= x2; + x2 ^= x1; + x4 ^= x3; + } + + private void sboxI3() + { + x4 = (x4 >>> 22) | (x4 << 10); + x1 = (x1 >>> 5) | (x1 << 27); + x3 = x2; + x4 ^= x0; + x3 <<= 7; + x1 ^= x0; + x4 ^= x3; + x1 ^= x2; + x0 = (x0 >>> 7) | (x0 << 25); + x2 = (x2 >>> 1) | (x2 << 31); + x2 ^= x1; + x3 = x1 << 3; + x0 ^= x3; + x1 = (x1 >>> 13) | (x1 << 19); + x2 ^= x4; + x0 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x3 = x4; + x4 ^= x2; + x2 &= x4; + x2 ^= x1; + x1 &= x3; + x3 ^= x0; + x0 |= x2; + x0 ^= x4; + x1 ^= x3; + x4 ^= x1; + x1 |= x0; + x1 ^= x2; + x3 ^= x4; + x4 &= x0; + x2 |= x0; + x2 ^= x4; + x3 ^= x1; + x4 ^= x3; + } + + private void sboxI2() + { + x4 = (x4 >>> 22) | (x4 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x3 = x1; + x4 ^= x2; + x3 <<= 7; + x0 ^= x2; + x4 ^= x3; + x0 ^= x1; + x2 = (x2 >>> 7) | (x2 << 25); + x1 = (x1 >>> 1) | (x1 << 31); + x1 ^= x0; + x3 = x0 << 3; + x2 ^= x3; + x0 = (x0 >>> 13) | (x0 << 19); + x1 ^= x4; + x2 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x4 ^= x2; + x2 ^= x0; + x3 = x2; + x2 &= x4; + x2 ^= x1; + x1 |= x4; + x1 ^= x3; + x3 &= x2; + x4 ^= x2; + x3 &= x0; + x3 ^= x4; + x4 &= x1; + x4 |= x0; + x2 = ~x2; + x4 ^= x2; + x0 ^= x2; + x0 &= x1; + x2 ^= x3; + x2 ^= x0; + } + + private void sboxI1() + { + x4 = (x4 >>> 22) | (x4 << 10); + x1 = (x1 >>> 5) | (x1 << 27); + x0 = x3; + x4 ^= x2; + x0 <<= 7; + x1 ^= x2; + x4 ^= x0; + x1 ^= x3; + x2 = (x2 >>> 7) | (x2 << 25); + x3 = (x3 >>> 1) | (x3 << 31); + x3 ^= x1; + x0 = x1 << 3; + x2 ^= x0; + x1 = (x1 >>> 13) | (x1 << 19); + x3 ^= x4; + x2 ^= x4; + x4 = (x4 >>> 3) | (x4 << 29); + x0 = x3; + x3 ^= x2; + x2 &= x3; + x0 ^= x4; + x2 ^= x1; + x1 |= x3; + x4 ^= x2; + x1 ^= x0; + x1 |= x4; + x3 ^= x2; + x1 ^= x3; + x3 |= x2; + x3 ^= x1; + x0 = ~x0; + x0 ^= x3; + x3 |= x1; + x3 ^= x1; + x3 |= x0; + x2 ^= x3; + } + + private void sboxI0() + { + x2 = (x2 >>> 22) | (x2 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x3 = x1; + x2 ^= x4; + x3 <<= 7; + x0 ^= x4; + x2 ^= x3; + x0 ^= x1; + x4 = (x4 >>> 7) | (x4 << 25); + x1 = (x1 >>> 1) | (x1 << 31); + x1 ^= x0; + x3 = x0 << 3; + x4 ^= x3; + x0 = (x0 >>> 13) | (x0 << 19); + x1 ^= x2; + x4 ^= x2; + x2 = (x2 >>> 3) | (x2 << 29); + x2 = ~x2; + x3 = x1; + x1 |= x0; + x3 = ~x3; + x1 ^= x2; + x2 |= x3; + x1 ^= x4; + x0 ^= x3; + x2 ^= x0; + x0 &= x4; + x3 ^= x0; + x0 |= x1; + x0 ^= x2; + x4 ^= x3; + x2 ^= x1; + x4 ^= x0; + x4 ^= x1; + x2 &= x4; + x3 ^= x2; + } + + private void sboxI7() + { + x1 = (x1 >>> 22) | (x1 << 10); + x0 = (x0 >>> 5) | (x0 << 27); + x2 = x3; + x1 ^= x4; + x2 <<= 7; + x0 ^= x4; + x1 ^= x2; + x0 ^= x3; + x4 = (x4 >>> 7) | (x4 << 25); + x3 = (x3 >>> 1) | (x3 << 31); + x3 ^= x0; + x2 = x0 << 3; + x4 ^= x2; + x0 = (x0 >>> 13) | (x0 << 19); + x3 ^= x1; + x4 ^= x1; + x1 = (x1 >>> 3) | (x1 << 29); + x2 = x1; + x1 ^= x0; + x0 &= x4; + x1 = ~x1; + x2 |= x4; + x4 ^= x3; + x3 |= x0; + x0 ^= x1; + x1 &= x2; + x3 ^= x1; + x1 ^= x0; + x0 |= x1; + x4 &= x2; + x0 ^= x4; + x2 ^= x3; + x4 ^= x2; + x2 |= x0; + x4 ^= x1; + x2 ^= x1; + } + + // These S-Box functions are used in the key setup. + + /** S-Box 0. */ + private void sbox0(int r0, int r1, int r2, int r3) + { + int r4 = r1 ^ r2; + r3 ^= r0; + r1 = r1 & r3 ^ r0; + r0 = (r0 | r3) ^ r4; + r4 ^= r3; + r3 ^= r2; + r2 = (r2 | r1) ^ r4; + r4 = ~r4 | r1; + r1 ^= r3 ^ r4; + r3 |= r0; + x0 = r1 ^ r3; + x1 = r4 ^ r3; + x2 = r2; + x3 = r0; + } + + /** S-Box 1. */ + private void sbox1(int r0, int r1, int r2, int r3) + { + r0 = ~r0; + int r4 = r0; + r2 = ~r2; + r0 &= r1; + r2 ^= r0; + r0 |= r3; + r3 ^= r2; + r1 ^= r0; + r0 ^= r4; + r4 |= r1; + r1 ^= r3; + r2 = (r2 | r0) & r4; + r0 ^= r1; + x0 = r2; + x1 = r0 & r2 ^ r4; + x2 = r3; + x3 = r1 & r2 ^ r0; + } + + /** S-Box 2. */ + private void sbox2(int r0, int r1, int r2, int r3) + { + int r4 = r0; + r0 = r0 & r2 ^ r3; + r2 = r2 ^ r1 ^ r0; + r3 = (r3 | r4) ^ r1; + r4 ^= r2; + r1 = r3; + r3 = (r3 | r4) ^ r0; + r0 &= r1; + r4 ^= r0; + x0 = r2; + x1 = r3; + x2 = r1 ^ r3 ^ r4; + x3 = ~r4; + } + + /** S-Box 3. */ + private void sbox3(int r0, int r1, int r2, int r3) + { + int r4 = r0; + r0 |= r3; + r3 ^= r1; + r1 &= r4; + r4 = r4 ^ r2 | r1; + r2 ^= r3; + r3 = r3 & r0 ^ r4; + r0 ^= r1; + r4 = r4 & r0 ^ r2; + r1 = (r1 ^ r3 | r0) ^ r2; + r0 ^= r3; + x0 = (r1 | r3) ^ r0; + x1 = r1; + x2 = r3; + x3 = r4; + } + + /** S-Box 4. */ + private void sbox4(int r0, int r1, int r2, int r3) + { + r1 ^= r3; + int r4 = r1; + r3 = ~r3; + r2 ^= r3; + r3 ^= r0; + r1 = r1 & r3 ^ r2; + r4 ^= r3; + r0 ^= r4; + r2 = r2 & r4 ^ r0; + r0 &= r1; + r3 ^= r0; + r4 = (r4 | r1) ^ r0; + x0 = r1; + x1 = r4 ^ (r2 & r3); + x2 = ~((r0 | r3) ^ r2); + x3 = r3; + } + + /** S-Box 5. */ + private void sbox5(int r0, int r1, int r2, int r3) + { + r0 ^= r1; + r1 ^= r3; + int r4 = r1; + r3 = ~r3; + r1 &= r0; + r2 ^= r3; + r1 ^= r2; + r2 |= r4; + r4 ^= r3; + r3 = r3 & r1 ^ r0; + r4 = r4 ^ r1 ^ r2; + x0 = r1; + x1 = r3; + x2 = r0 & r3 ^ r4; + x3 = ~(r2 ^ r0) ^ (r4 | r3); + } + + /** S-Box 6. */ + private void sbox6(int r0, int r1, int r2, int r3) + { + int r4 = r3; + r2 = ~r2; + r3 = r3 & r0 ^ r2; + r0 ^= r4; + r2 = (r2 | r4) ^ r0; + r1 ^= r3; + r0 |= r1; + r2 ^= r1; + r4 ^= r0; + r0 = (r0 | r3) ^ r2; + r4 = r4 ^ r3 ^ r0; + x0 = r0; + x1 = r1; + x2 = r4; + x3 = r2 & r4 ^ ~r3; + } + + /** S-Box 7. */ + private void sbox7(int r0, int r1, int r2, int r3) + { + int r4 = r1; + r1 = (r1 | r2) ^ r3; + r4 ^= r2; + r2 ^= r1; + r3 = (r3 | r4) & r0; + r4 ^= r2; + r3 ^= r1; + r1 = (r1 | r4) ^ r0; + r0 = (r0 | r4) ^ r2; + r1 ^= r4; + r2 ^= r1; + x0 = r4 ^ (~r2 | r0); + x1 = r3; + x2 = r1 & r0 ^ r4; + x3 = r0; + } + + // Inner classes. + // ----------------------------------------------------------------------- + + private class Key implements Cloneable + { + + // Constants and variables. + // -------------------------------------------------------------------- + + int k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, + k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, + k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, + k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, + k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, + k72, k73, k74, k75, k76, k77, k78, k79, k80, k81, k82, k83, k84, k85, + k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, + k100, k101, k102, k103, k104, k105, k106, k107, k108, k109, k110, k111, + k112, k113, k114, k115, k116, k117, k118, k119, k120, k121, k122, k123, + k124, k125, k126, k127, k128, k129, k130, k131; + + // Constructors. + // -------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + Key() + { + } + + /** Cloning constructor. */ + private Key(Key that) + { + this.k0 = that.k0; + this.k1 = that.k1; + this.k2 = that.k2; + this.k3 = that.k3; + this.k4 = that.k4; + this.k5 = that.k5; + this.k6 = that.k6; + this.k7 = that.k7; + this.k8 = that.k8; + this.k9 = that.k9; + this.k10 = that.k10; + this.k11 = that.k11; + this.k12 = that.k12; + this.k13 = that.k13; + this.k14 = that.k14; + this.k15 = that.k15; + this.k16 = that.k16; + this.k17 = that.k17; + this.k18 = that.k18; + this.k19 = that.k19; + this.k20 = that.k20; + this.k21 = that.k21; + this.k22 = that.k22; + this.k23 = that.k23; + this.k24 = that.k24; + this.k25 = that.k25; + this.k26 = that.k26; + this.k27 = that.k27; + this.k28 = that.k28; + this.k29 = that.k29; + this.k30 = that.k30; + this.k31 = that.k31; + this.k32 = that.k32; + this.k33 = that.k33; + this.k34 = that.k34; + this.k35 = that.k35; + this.k36 = that.k36; + this.k37 = that.k37; + this.k38 = that.k38; + this.k39 = that.k39; + this.k40 = that.k40; + this.k41 = that.k41; + this.k42 = that.k42; + this.k43 = that.k43; + this.k44 = that.k44; + this.k45 = that.k45; + this.k46 = that.k46; + this.k47 = that.k47; + this.k48 = that.k48; + this.k49 = that.k49; + this.k50 = that.k50; + this.k51 = that.k51; + this.k52 = that.k52; + this.k53 = that.k53; + this.k54 = that.k54; + this.k55 = that.k55; + this.k56 = that.k56; + this.k57 = that.k57; + this.k58 = that.k58; + this.k59 = that.k59; + this.k60 = that.k60; + this.k61 = that.k61; + this.k62 = that.k62; + this.k63 = that.k63; + this.k64 = that.k64; + this.k65 = that.k65; + this.k66 = that.k66; + this.k67 = that.k67; + this.k68 = that.k68; + this.k69 = that.k69; + this.k70 = that.k70; + this.k71 = that.k71; + this.k72 = that.k72; + this.k73 = that.k73; + this.k74 = that.k74; + this.k75 = that.k75; + this.k76 = that.k76; + this.k77 = that.k77; + this.k78 = that.k78; + this.k79 = that.k79; + this.k80 = that.k80; + this.k81 = that.k81; + this.k82 = that.k82; + this.k83 = that.k83; + this.k84 = that.k84; + this.k85 = that.k85; + this.k86 = that.k86; + this.k87 = that.k87; + this.k88 = that.k88; + this.k89 = that.k89; + this.k90 = that.k90; + this.k91 = that.k91; + this.k92 = that.k92; + this.k93 = that.k93; + this.k94 = that.k94; + this.k95 = that.k95; + this.k96 = that.k96; + this.k97 = that.k97; + this.k98 = that.k98; + this.k99 = that.k99; + this.k100 = that.k100; + this.k101 = that.k101; + this.k102 = that.k102; + this.k103 = that.k103; + this.k104 = that.k104; + this.k105 = that.k105; + this.k106 = that.k106; + this.k107 = that.k107; + this.k108 = that.k108; + this.k109 = that.k109; + this.k110 = that.k110; + this.k111 = that.k111; + this.k112 = that.k112; + this.k113 = that.k113; + this.k114 = that.k114; + this.k115 = that.k115; + this.k116 = that.k116; + this.k117 = that.k117; + this.k118 = that.k118; + this.k119 = that.k119; + this.k120 = that.k120; + this.k121 = that.k121; + this.k122 = that.k122; + this.k123 = that.k123; + this.k124 = that.k124; + this.k125 = that.k125; + this.k126 = that.k126; + this.k127 = that.k127; + this.k128 = that.k128; + this.k129 = that.k129; + this.k130 = that.k130; + this.k131 = that.k131; + } + + // Cloneable interface implementation. + // -------------------------------------------------------------------- + + public Object clone() + { + return new Key(this); + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Square.java b/gnu/javax/crypto/cipher/Square.java new file mode 100644 index 000000000..55e986526 --- /dev/null +++ b/gnu/javax/crypto/cipher/Square.java @@ -0,0 +1,520 @@ +/* Square.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + *

Square is a 128-bit key, 128-bit block cipher algorithm developed by Joan + * Daemen, Lars Knudsen and Vincent Rijmen.

+ * + *

References:

+ * + *
    + *
  1. The block + * cipher Square.
    + * Joan Daemen, + * Lars Knudsen and + * Vincent Rijmen.
  2. + *
+ * + * @version $Revision: 1.1.4.1 $ + */ +public final class Square extends BaseCipher +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + + private static final int ROUNDS = 8; + + private static final int ROOT = 0x1F5; // for generating GF(2**8) + + private static final int[] OFFSET = new int[ROUNDS]; + + private static final String Sdata = "\uB1CE\uC395\u5AAD\uE702\u4D44\uFB91\u0C87\uA150" + + "\uCB67\u54DD\u468F\uE14E\uF0FD\uFCEB\uF9C4\u1A6E" + + "\u5EF5\uCC8D\u1C56\u43FE\u0761\uF875\u59FF\u0322" + + "\u8AD1\u13EE\u8800\u0E34\u1580\u94E3\uEDB5\u5323" + + "\u4B47\u17A7\u9035\uABD8\uB8DF\u4F57\u9A92\uDB1B" + + "\u3CC8\u9904\u8EE0\uD77D\u85BB\u402C\u3A45\uF142" + + "\u6520\u4118\u7225\u9370\u3605\uF20B\uA379\uEC08" + + "\u2731\u32B6\u7CB0\u0A73\u5B7B\uB781\uD20D\u6A26" + + "\u9E58\u9C83\u74B3\uAC30\u7A69\u770F\uAE21\uDED0" + + "\u2E97\u10A4\u98A8\uD468\u2D62\u296D\u1649\u76C7" + + "\uE8C1\u9637\uE5CA\uF4E9\u6312\uC2A6\u14BC\uD328" + + "\uAF2F\uE624\u52C6\uA009\uBD8C\uCF5D\u115F\u01C5" + + "\u9F3D\uA29B\uC93B\uBE51\u191F\u3F5C\uB2EF\u4ACD" + + "\uBFBA\u6F64\uD9F3\u3EB4\uAADC\uD506\uC07E\uF666" + + "\u6C84\u7138\uB91D\u7F9D\u488B\u2ADA\uA533\u8239" + + "\uD678\u86FA\uE42B\uA91E\u8960\u6BEA\u554C\uF7E2"; + + /** Substitution boxes for encryption and decryption. */ + private static final byte[] Se = new byte[256]; + + private static final byte[] Sd = new byte[256]; + + /** Transposition boxes for encryption and decryption. */ + private static final int[] Te = new int[256]; + + private static final int[] Td = new int[256]; + + /** + * KAT vector (from ecb_vk): + * I=87 + * KEY=00000000000000000000020000000000 + * CT=A9DF031B4E25E89F527EFFF89CB0BEBA + */ + private static final byte[] KAT_KEY = Util.toBytesFromString("00000000000000000000020000000000"); + + private static final byte[] KAT_CT = Util.toBytesFromString("A9DF031B4E25E89F527EFFF89CB0BEBA"); + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + // Static code - to intialise lookup tables + // ------------------------------------------------------------------------- + + static + { + int i, j; + /* + // Generate exp and log tables used in multiplication over GF(2 ** m) + byte[] exp = new byte[256]; + byte[] log = new byte[256]; + + exp[0] = 1; + for (i = 1; i < 256; i++) { + j = exp[i - 1] << 1; + if ((j & 0x100) != 0) { + j ^= ROOT; // reduce j (mod ROOT) + } + + exp[i] = (byte) j; + log[j & 0xFF] = (byte) i; + } + + // Compute the substitution box Se[] and its inverse Sd[] based on + // F(x) = x**{-1} plus affine transform of the output. + Se[0] = 0; + Se[1] = 1; + for (i = 2; i < 256; i++) { + Se[i] = exp[(255 - log[i]) & 0xFF]; + } + + // Let Se[i] be represented as an 8-row vector V over GF(2); the affine + // transformation is A * V + T, where the rows of the 8 x 8 matrix A are + // contained in trans[0]...trans[7] and the 8-row vector T is contained + // in 0xB1. + int[] trans = new int[] {0x01, 0x03, 0x05, 0x0F, 0x1F, 0x3D, 0x7B, 0xD6}; + int u, v; + for (i = 0; i < 256; i++) { + v = 0xB1; // affine part of the transform + for (j = 0; j < 8; j++) { + u = Se[i] & trans[j] & 0xFF; // column-wise mult. over GF(2) + u ^= u >>> 4; // sum of all bits of u over GF(2) + u ^= u >>> 2; + u ^= u >>> 1; + u &= 1; + v ^= u << j; // row alignment of the result + } + Se[i] = (byte) v; + Sd[v] = (byte) i; // inverse substitution box + } + + System.out.println("Se="+Util.toUnicodeString(Se)); + System.out.println("Sd="+Util.toUnicodeString(Sd)); + */ + /**/ + // re-construct Se box values + int limit = Sdata.length(); + char c1; + for (i = 0, j = 0; i < limit; i++) + { + c1 = Sdata.charAt(i); + Se[j++] = (byte) (c1 >>> 8); + Se[j++] = (byte) c1; + } + + // compute Sd box values + for (i = 0; i < 256; i++) + { + Sd[Se[i] & 0xFF] = (byte) i; + } + + // generate OFFSET values + OFFSET[0] = 1; + for (i = 1; i < ROUNDS; i++) + { + OFFSET[i] = mul(OFFSET[i - 1], 2); + OFFSET[i - 1] <<= 24; + } + + OFFSET[ROUNDS - 1] <<= 24; + + // generate Te and Td boxes if we're not reading their values + // Notes: + // (1) The function mul() computes the product of two elements of GF(2**8) + // with ROOT as reduction polynomial. + // (2) the values used in computing the Te and Td are the GF(2**8) + // coefficients of the diffusion polynomial c(x) and its inverse + // (modulo x**4 + 1) d(x), defined in sections 2.1 and 4 of the Square + // paper. + for (i = 0; i < 256; i++) + { + j = Se[i] & 0xFF; + Te[i] = (Se[i & 3] == 0) ? 0 : mul(j, 2) << 24 | j << 16 | j << 8 + | mul(j, 3); + + j = Sd[i] & 0xFF; + Td[i] = (Sd[i & 3] == 0) ? 0 : mul(j, 14) << 24 | mul(j, 9) << 16 + | mul(j, 13) << 8 | mul(j, 11); + } + /**/ + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Square() + { + super(Registry.SQUARE_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + private static void square(byte[] in, int i, byte[] out, int j, int[][] K, + int[] T, byte[] S) + { + int a = ((in[i++]) << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ K[0][0]; + int b = ((in[i++]) << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ K[0][1]; + int c = ((in[i++]) << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i++] & 0xFF)) + ^ K[0][2]; + int d = ((in[i++]) << 24 | (in[i++] & 0xFF) << 16 | (in[i++] & 0xFF) << 8 | (in[i] & 0xFF)) + ^ K[0][3]; + + int r, aa, bb, cc, dd; + for (r = 1; r < ROUNDS; r++) + { // R - 1 full rounds + aa = T[(a >>> 24)] ^ rot32R(T[(b >>> 24)], 8) + ^ rot32R(T[(c >>> 24)], 16) ^ rot32R(T[(d >>> 24)], 24) ^ K[r][0]; + bb = T[(a >>> 16) & 0xFF] ^ rot32R(T[(b >>> 16) & 0xFF], 8) + ^ rot32R(T[(c >>> 16) & 0xFF], 16) + ^ rot32R(T[(d >>> 16) & 0xFF], 24) ^ K[r][1]; + cc = T[(a >>> 8) & 0xFF] ^ rot32R(T[(b >>> 8) & 0xFF], 8) + ^ rot32R(T[(c >>> 8) & 0xFF], 16) + ^ rot32R(T[(d >>> 8) & 0xFF], 24) ^ K[r][2]; + dd = T[a & 0xFF] ^ rot32R(T[b & 0xFF], 8) ^ rot32R(T[c & 0xFF], 16) + ^ rot32R(T[d & 0xFF], 24) ^ K[r][3]; + + a = aa; + b = bb; + c = cc; + d = dd; + } + + // last round (diffusion becomes only transposition) + aa = ((S[(a >>> 24)]) << 24 | (S[(b >>> 24)] & 0xFF) << 16 + | (S[(c >>> 24)] & 0xFF) << 8 | (S[(d >>> 24)] & 0xFF)) + ^ K[r][0]; + bb = ((S[(a >>> 16) & 0xFF]) << 24 | (S[(b >>> 16) & 0xFF] & 0xFF) << 16 + | (S[(c >>> 16) & 0xFF] & 0xFF) << 8 | (S[(d >>> 16) & 0xFF] & 0xFF)) + ^ K[r][1]; + cc = ((S[(a >>> 8) & 0xFF]) << 24 | (S[(b >>> 8) & 0xFF] & 0xFF) << 16 + | (S[(c >>> 8) & 0xFF] & 0xFF) << 8 | (S[(d >>> 8) & 0xFF] & 0xFF)) + ^ K[r][2]; + dd = ((S[a & 0xFF]) << 24 | (S[b & 0xFF] & 0xFF) << 16 + | (S[c & 0xFF] & 0xFF) << 8 | (S[d & 0xFF] & 0xFF)) + ^ K[r][3]; + + out[j++] = (byte) (aa >>> 24); + out[j++] = (byte) (aa >>> 16); + out[j++] = (byte) (aa >>> 8); + out[j++] = (byte) aa; + out[j++] = (byte) (bb >>> 24); + out[j++] = (byte) (bb >>> 16); + out[j++] = (byte) (bb >>> 8); + out[j++] = (byte) bb; + out[j++] = (byte) (cc >>> 24); + out[j++] = (byte) (cc >>> 16); + out[j++] = (byte) (cc >>> 8); + out[j++] = (byte) cc; + out[j++] = (byte) (dd >>> 24); + out[j++] = (byte) (dd >>> 16); + out[j++] = (byte) (dd >>> 8); + out[j] = (byte) dd; + } + + /** + *

Applies the Theta function to an input in in order to produce in + * out an internal session sub-key.

+ * + *

Both in and out are arrays of four ints.

+ * + *

Pseudo-code is:

+ * + *
+   *    for (i = 0; i < 4; i++) {
+   *       out[i] = 0;
+   *       for (j = 0, n = 24; j < 4; j++, n -= 8) {
+   *          k = mul(in[i] >>> 24, G[0][j]) ^
+   *              mul(in[i] >>> 16, G[1][j]) ^
+   *              mul(in[i] >>>  8, G[2][j]) ^
+   *              mul(in[i]       , G[3][j]);
+   *          out[i] ^= k << n;
+   *       }
+   *    }
+   * 
+ */ + private static void transform(int[] in, int[] out) + { + int l3, l2, l1, l0, m; + for (int i = 0; i < 4; i++) + { + l3 = in[i]; + l2 = l3 >>> 8; + l1 = l3 >>> 16; + l0 = l3 >>> 24; + m = ((mul(l0, 2) ^ mul(l1, 3) ^ l2 ^ l3) & 0xFF) << 24; + m ^= ((l0 ^ mul(l1, 2) ^ mul(l2, 3) ^ l3) & 0xFF) << 16; + m ^= ((l0 ^ l1 ^ mul(l2, 2) ^ mul(l3, 3)) & 0xFF) << 8; + m ^= ((mul(l0, 3) ^ l1 ^ l2 ^ mul(l3, 2)) & 0xFF); + out[i] = m; + } + } + + /** + *

Left rotate a 32-bit chunk.

+ * + * @param x the 32-bit data to rotate + * @param s number of places to left-rotate by + * @return the newly permutated value. + */ + private static int rot32L(int x, int s) + { + return x << s | x >>> (32 - s); + } + + /** + *

Right rotate a 32-bit chunk.

+ * + * @param x the 32-bit data to rotate + * @param s number of places to right-rotate by + * @return the newly permutated value. + */ + private static int rot32R(int x, int s) + { + return x >>> s | x << (32 - s); + } + + /** + *

Returns the product of two binary numbers a and b, using the generator + * ROOT as the modulus: p = (a * b) mod ROOT. ROOT Generates a suitable + * Galois Field in GF(2**8).

+ * + *

For best performance call it with abs(b) < abs(a).

+ * + * @param a operand for multiply. + * @param b operand for multiply. + * @return the result of (a * b) % ROOT. + */ + private static final int mul(int a, int b) + { + if (a == 0) + { + return 0; + } + + a &= 0xFF; + b &= 0xFF; + int result = 0; + while (b != 0) + { + if ((b & 0x01) != 0) + { + result ^= a; + } + + b >>>= 1; + a <<= 1; + if (a > 0xFF) + { + a ^= ROOT; + } + } + return result & 0xFF; + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Square result = new Square(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_KEY_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] uk, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + if (uk == null) + { + throw new InvalidKeyException("Empty key"); + } + if (uk.length != DEFAULT_KEY_SIZE) + { + throw new InvalidKeyException("Key is not 128-bit."); + } + + int[][] Ke = new int[ROUNDS + 1][4]; + int[][] Kd = new int[ROUNDS + 1][4]; + int[][] tK = new int[ROUNDS + 1][4]; + int i = 0; + + Ke[0][0] = (uk[i++] & 0xFF) << 24 | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 | (uk[i++] & 0xFF); + tK[0][0] = Ke[0][0]; + Ke[0][1] = (uk[i++] & 0xFF) << 24 | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 | (uk[i++] & 0xFF); + tK[0][1] = Ke[0][1]; + Ke[0][2] = (uk[i++] & 0xFF) << 24 | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 | (uk[i++] & 0xFF); + tK[0][2] = Ke[0][2]; + Ke[0][3] = (uk[i++] & 0xFF) << 24 | (uk[i++] & 0xFF) << 16 + | (uk[i++] & 0xFF) << 8 | (uk[i] & 0xFF); + tK[0][3] = Ke[0][3]; + + int j; + for (i = 1, j = 0; i < ROUNDS + 1; i++, j++) + { + tK[i][0] = tK[j][0] ^ rot32L(tK[j][3], 8) ^ OFFSET[j]; + tK[i][1] = tK[j][1] ^ tK[i][0]; + tK[i][2] = tK[j][2] ^ tK[i][1]; + tK[i][3] = tK[j][3] ^ tK[i][2]; + + System.arraycopy(tK[i], 0, Ke[i], 0, 4); + + transform(Ke[j], Ke[j]); + } + + for (i = 0; i < ROUNDS; i++) + { + System.arraycopy(tK[ROUNDS - i], 0, Kd[i], 0, 4); + } + + transform(tK[0], Kd[ROUNDS]); + + return new Object[] { Ke, Kd }; + } + + public void encrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + + int[][] K = (int[][]) ((Object[]) k)[0]; + square(in, i, out, j, K, Te, Se); + } + + public void decrypt(byte[] in, int i, byte[] out, int j, Object k, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + + int[][] K = (int[][]) ((Object[]) k)[1]; + square(in, i, out, j, K, Td, Sd); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + { + result = testKat(KAT_KEY, KAT_CT); + } + valid = new Boolean(result); + } + return valid.booleanValue(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/TripleDES.java b/gnu/javax/crypto/cipher/TripleDES.java new file mode 100644 index 000000000..9b44c9ca7 --- /dev/null +++ b/gnu/javax/crypto/cipher/TripleDES.java @@ -0,0 +1,196 @@ +/* TripleDES.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.Iterator; +import java.security.InvalidKeyException; + +/** + * Triple-DES, 3DES, or DESede is a combined cipher that uses + * three iterations of the Data Encryption Standard cipher to improve + * the security (at the cost of speed) of plain DES. + * + *

Triple-DES runs the DES algorithm three times with three + * independent 56 bit keys. To encrypt:

+ * + *
Ci = + * Ek3 ( Ek2-1 ( Ek1 ( Pi )))
+ * + *

And to decrypt:

+ * + *
Pi = + * Ek1-1 ( Ek2 ( Ek3-1 ( Ci )))
+ * + *

(The "ede" comes from the encryption operation, which runs + * Encrypt-Decrypt-Encrypt)

+ * + *

References:

+ *
    + *
  1. Bruce Schneier, Applied Cryptography: Protocols, Algorithms, + * and Source Code in C, Second Edition. (1996 John Wiley and Sons) + * ISBN 0-471-11709-9. Page 294--295.
  2. + *
+ */ +public class TripleDES extends BaseCipher +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** Triple-DES only operates on 64 bit blocks. */ + public static final int BLOCK_SIZE = 8; + + /** Triple-DES uses 168 bits of a parity-adjusted 192 bit key. */ + public static final int KEY_SIZE = 24; + + /** The underlying DES instance. */ + private DES des; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * Default 0-arguments constructor. + */ + public TripleDES() + { + super(Registry.TRIPLEDES_CIPHER, BLOCK_SIZE, KEY_SIZE); + des = new DES(); + } + + // Class methods. + // ----------------------------------------------------------------------- + + /** + * Transform a key so it will be parity adjusted. + * + * @param kb The key bytes to adjust. + * @param offset The starting offset into the key bytes. + * @see DES#adjustParity(byte[],int) + */ + public static void adjustParity(byte[] kb, int offset) + { + DES.adjustParity(kb, offset); + DES.adjustParity(kb, offset + 8); + DES.adjustParity(kb, offset + 16); + } + + /** + * Tests if a byte array has already been parity adjusted. + * + * @param kb The key bytes to test. + * @param offset The starting offset into the key bytes. + * @return true if the bytes in kb starting at + * offset are parity adjusted. + * @see DES#isParityAdjusted(byte[],int) + * @see #adjustParity(byte[],int) + */ + public static boolean isParityAdjusted(byte[] kb, int offset) + { + return DES.isParityAdjusted(kb, offset) + && DES.isParityAdjusted(kb, offset + 8) + && DES.isParityAdjusted(kb, offset + 16); + } + + // Methods implementing BaseCipher. + // ----------------------------------------------------------------------- + + public Object clone() + { + return new TripleDES(); + } + + public Iterator blockSizes() + { + return Collections.singleton(new Integer(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + return Collections.singleton(new Integer(KEY_SIZE)).iterator(); + } + + public Object makeKey(byte[] kb, int bs) throws InvalidKeyException + { + if (kb.length != KEY_SIZE) + throw new InvalidKeyException("TripleDES key must be 24 bytes"); + + if (!isParityAdjusted(kb, 0)) + adjustParity(kb, 0); + + byte[] k1 = new byte[DES.KEY_SIZE], k2 = new byte[DES.KEY_SIZE], k3 = new byte[DES.KEY_SIZE]; + System.arraycopy(kb, 0, k1, 0, DES.KEY_SIZE); + System.arraycopy(kb, DES.KEY_SIZE, k2, 0, DES.KEY_SIZE); + System.arraycopy(kb, 2 * DES.KEY_SIZE, k3, 0, DES.KEY_SIZE); + Context ctx = new Context(); + + ctx.k1 = (DES.Context) des.makeKey(k1, bs); + ctx.k2 = (DES.Context) des.makeKey(k2, bs); + ctx.k3 = (DES.Context) des.makeKey(k3, bs); + + return ctx; + } + + public void encrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + byte[] temp = new byte[BLOCK_SIZE]; + des.encrypt(in, i, temp, 0, ((Context) K).k1, bs); + des.decrypt(temp, 0, temp, 0, ((Context) K).k2, bs); + des.encrypt(temp, 0, out, o, ((Context) K).k3, bs); + } + + public void decrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) + { + byte[] temp = new byte[BLOCK_SIZE]; + des.decrypt(in, i, temp, 0, ((Context) K).k3, bs); + des.encrypt(temp, 0, temp, 0, ((Context) K).k2, bs); + des.decrypt(temp, 0, out, o, ((Context) K).k1, bs); + } + + // Inner classes. + // ----------------------------------------------------------------------- + + private final class Context + { + DES.Context k1, k2, k3; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/Twofish.java b/gnu/javax/crypto/cipher/Twofish.java new file mode 100644 index 000000000..bea7f5d2c --- /dev/null +++ b/gnu/javax/crypto/cipher/Twofish.java @@ -0,0 +1,909 @@ +/* Twofish.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +//import java.io.PrintWriter; +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; + +/** + *

Twofish is a balanced 128-bit Feistel cipher, consisting of 16 rounds. In + * each round, a 64-bit S-box value is computed from 64 bits of the block, and + * this value is xored into the other half of the block. The two half-blocks are + * then exchanged, and the next round begins. Before the first round, all input + * bits are xored with key-dependent "whitening" subkeys, and after the final + * round the output bits are xored with other key-dependent whitening subkeys; + * these subkeys are not used anywhere else in the algorithm.

+ * + *

Twofish is designed by Bruce Schneier, Doug Whiting, John Kelsey, Chris + * Hall, David Wagner and Niels Ferguson.

+ * + *

References:

+ * + *
    + *
  1. Twofish: A + * 128-bit Block Cipher.
  2. + *
+ */ +public final class Twofish extends BaseCipher +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + // private static final String NAME = "twofish"; + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + // private static final PrintWriter err = new PrintWriter(System.out, true); + // private static void debug(String s) { + // err.println(">>> "+NAME+": "+s); + // } + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int DEFAULT_BLOCK_SIZE = 16; // in bytes + + private static final int DEFAULT_KEY_SIZE = 16; // in bytes + + private static final int MAX_ROUNDS = 16; // max # rounds (for allocating subkeys) + + private static final int ROUNDS = MAX_ROUNDS; + + // subkey array indices + private static final int INPUT_WHITEN = 0; + + private static final int OUTPUT_WHITEN = INPUT_WHITEN + DEFAULT_BLOCK_SIZE + / 4; + + private static final int ROUND_SUBKEYS = OUTPUT_WHITEN + DEFAULT_BLOCK_SIZE + / 4; + + // private static final int TOTAL_SUBKEYS = ROUND_SUBKEYS + 2*MAX_ROUNDS; + + private static final int SK_STEP = 0x02020202; + + private static final int SK_BUMP = 0x01010101; + + private static final int SK_ROTL = 9; + + private static final String[] Pm = new String[] { + // p0 + "\uA967\uB3E8\u04FD\uA376\u9A92\u8078\uE4DD\uD138" + + "\u0DC6\u3598\u18F7\uEC6C\u4375\u3726\uFA13\u9448" + + "\uF2D0\u8B30\u8454\uDF23\u195B\u3D59\uF3AE\uA282" + + "\u6301\u832E\uD951\u9B7C\uA6EB\uA5BE\u160C\uE361" + + "\uC08C\u3AF5\u732C\u250B\uBB4E\u896B\u536A\uB4F1" + + "\uE1E6\uBD45\uE2F4\uB666\uCC95\u0356\uD41C\u1ED7" + + "\uFBC3\u8EB5\uE9CF\uBFBA\uEA77\u39AF\u33C9\u6271" + + "\u8179\u09AD\u24CD\uF9D8\uE5C5\uB94D\u4408\u86E7" + + "\uA11D\uAAED\u0670\uB2D2\u417B\uA011\u31C2\u2790" + + "\u20F6\u60FF\u965C\uB1AB\u9E9C\u521B\u5F93\u0AEF" + + "\u9185\u49EE\u2D4F\u8F3B\u4787\u6D46\uD63E\u6964" + + "\u2ACE\uCB2F\uFC97\u057A\uAC7F\uD51A\u4B0E\uA75A" + + "\u2814\u3F29\u883C\u4C02\uB8DA\uB017\u551F\u8A7D" + + "\u57C7\u8D74\uB7C4\u9F72\u7E15\u2212\u5807\u9934" + + "\u6E50\uDE68\u65BC\uDBF8\uC8A8\u2B40\uDCFE\u32A4" + + "\uCA10\u21F0\uD35D\u0F00\u6F9D\u3642\u4A5E\uC1E0", + // p1 + "\u75F3\uC6F4\uDB7B\uFBC8\u4AD3\uE66B\u457D\uE84B" + + "\uD632\uD8FD\u3771\uF1E1\u300F\uF81B\u87FA\u063F" + + "\u5EBA\uAE5B\u8A00\uBC9D\u6DC1\uB10E\u805D\uD2D5" + + "\uA084\u0714\uB590\u2CA3\uB273\u4C54\u9274\u3651" + + "\u38B0\uBD5A\uFC60\u6296\u6C42\uF710\u7C28\u278C" + + "\u1395\u9CC7\u2446\u3B70\uCAE3\u85CB\u11D0\u93B8" + + "\uA683\u20FF\u9F77\uC3CC\u036F\u08BF\u40E7\u2BE2" + + "\u790C\uAA82\u413A\uEAB9\uE49A\uA497\u7EDA\u7A17" + + "\u6694\uA11D\u3DF0\uDEB3\u0B72\uA71C\uEFD1\u533E" + + "\u8F33\u265F\uEC76\u2A49\u8188\uEE21\uC41A\uEBD9" + + "\uC539\u99CD\uAD31\u8B01\u1823\uDD1F\u4E2D\uF948" + + "\u4FF2\u658E\u785C\u5819\u8DE5\u9857\u677F\u0564" + + "\uAF63\uB6FE\uF5B7\u3CA5\uCEE9\u6844\uE04D\u4369" + + "\u292E\uAC15\u59A8\u0A9E\u6E47\uDF34\u356A\uCFDC" + + "\u22C9\uC09B\u89D4\uEDAB\u12A2\u0D52\uBB02\u2FA9" + + "\uD761\u1EB4\u5004\uF6C2\u1625\u8656\u5509\uBE91" }; + + /** Fixed 8x8 permutation S-boxes */ + private static final byte[][] P = new byte[2][256]; // blank final + + /** + * Define the fixed p0/p1 permutations used in keyed S-box lookup. By + * changing the following constant definitions, the S-boxes will + * automatically get changed in the Twofish engine. + */ + private static final int P_00 = 1; + + private static final int P_01 = 0; + + private static final int P_02 = 0; + + private static final int P_03 = P_01 ^ 1; + + private static final int P_04 = 1; + + private static final int P_10 = 0; + + private static final int P_11 = 0; + + private static final int P_12 = 1; + + private static final int P_13 = P_11 ^ 1; + + private static final int P_14 = 0; + + private static final int P_20 = 1; + + private static final int P_21 = 1; + + private static final int P_22 = 0; + + private static final int P_23 = P_21 ^ 1; + + private static final int P_24 = 0; + + private static final int P_30 = 0; + + private static final int P_31 = 1; + + private static final int P_32 = 1; + + private static final int P_33 = P_31 ^ 1; + + private static final int P_34 = 1; + + /** Primitive polynomial for GF(256) */ + // private static final int GF256_FDBK = 0x169; + private static final int GF256_FDBK_2 = 0x169 / 2; + + private static final int GF256_FDBK_4 = 0x169 / 4; + + /** MDS matrix */ + private static final int[][] MDS = new int[4][256]; // blank final + + private static final int RS_GF_FDBK = 0x14D; // field generator + + /** + * KAT vector (from ecb_vk): + * I=183 + * KEY=0000000000000000000000000000000000000000000002000000000000000000 + * CT=F51410475B33FBD3DB2117B5C17C82D4 + */ + private static final byte[] KAT_KEY = Util.toBytesFromString("0000000000000000000000000000000000000000000002000000000000000000"); + + private static final byte[] KAT_CT = Util.toBytesFromString("F51410475B33FBD3DB2117B5C17C82D4"); + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + // Static code - to intialise the MDS matrix and lookup tables ------------- + + static + { + long time = System.currentTimeMillis(); + + // expand the P arrays + int i; + char c; + for (i = 0; i < 256; i++) + { + c = Pm[0].charAt(i >>> 1); + P[0][i] = (byte) ((i & 1) == 0 ? c >>> 8 : c); + + c = Pm[1].charAt(i >>> 1); + P[1][i] = (byte) ((i & 1) == 0 ? c >>> 8 : c); + } + + // precompute the MDS matrix + int[] m1 = new int[2]; + int[] mX = new int[2]; + int[] mY = new int[2]; + int j; + for (i = 0; i < 256; i++) + { + j = P[0][i] & 0xFF; // compute all the matrix elements + m1[0] = j; + mX[0] = Mx_X(j) & 0xFF; + mY[0] = Mx_Y(j) & 0xFF; + + j = P[1][i] & 0xFF; + m1[1] = j; + mX[1] = Mx_X(j) & 0xFF; + mY[1] = Mx_Y(j) & 0xFF; + + MDS[0][i] = m1[P_00] << 0 | // fill matrix w/ above elements + mX[P_00] << 8 | mY[P_00] << 16 | mY[P_00] << 24; + MDS[1][i] = mY[P_10] << 0 | mY[P_10] << 8 | mX[P_10] << 16 + | m1[P_10] << 24; + MDS[2][i] = mX[P_20] << 0 | mY[P_20] << 8 | m1[P_20] << 16 + | mY[P_20] << 24; + MDS[3][i] = mX[P_30] << 0 | m1[P_30] << 8 | mY[P_30] << 16 + | mX[P_30] << 24; + } + + time = System.currentTimeMillis() - time; + + if (DEBUG && debuglevel > 8) + { + System.out.println("=========="); + System.out.println(); + System.out.println("Static Data"); + System.out.println(); + System.out.println("MDS[0][]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(MDS[0][i * 4 + j]) + + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("MDS[1][]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(MDS[1][i * 4 + j]) + + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("MDS[2][]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(MDS[2][i * 4 + j]) + + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("MDS[3][]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(MDS[3][i * 4 + j]) + + ", "); + } + System.out.println(); + } + + System.out.println(); + System.out.println("Total initialization time: " + time + " ms."); + System.out.println(); + } + } + + private static final int LFSR1(int x) + { + return (x >> 1) ^ ((x & 0x01) != 0 ? GF256_FDBK_2 : 0); + } + + private static final int LFSR2(int x) + { + return (x >> 2) ^ ((x & 0x02) != 0 ? GF256_FDBK_2 : 0) + ^ ((x & 0x01) != 0 ? GF256_FDBK_4 : 0); + } + + // private static final int Mx_1(int x) { + // return x; + // } + + private static final int Mx_X(int x) + { // 5B + return x ^ LFSR2(x); + } + + private static final int Mx_Y(int x) + { // EF + return x ^ LFSR1(x) ^ LFSR2(x); + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Twofish() + { + super(Registry.TWOFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + // Class methods + // ------------------------------------------------------------------------- + + private static final int b0(int x) + { + return x & 0xFF; + } + + private static final int b1(int x) + { + return (x >>> 8) & 0xFF; + } + + private static final int b2(int x) + { + return (x >>> 16) & 0xFF; + } + + private static final int b3(int x) + { + return (x >>> 24) & 0xFF; + } + + /** + * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box 32-bit + * entity from two key material 32-bit entities. + * + * @param k0 1st 32-bit entity. + * @param k1 2nd 32-bit entity. + * @return remainder polynomial generated using RS code + */ + private static final int RS_MDS_Encode(int k0, int k1) + { + int r = k1; + int i; + for (i = 0; i < 4; i++) + { // shift 1 byte at a time + r = RS_rem(r); + } + r ^= k0; + for (i = 0; i < 4; i++) + { + r = RS_rem(r); + } + return r; + } + + /** + * Reed-Solomon code parameters: (12, 8) reversible code:

+ *

+   *   g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1
+   * 
+ * where a = primitive root of field generator 0x14D + */ + private static final int RS_rem(int x) + { + int b = (x >>> 24) & 0xFF; + int g2 = ((b << 1) ^ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xFF; + int g3 = (b >>> 1) ^ ((b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0) ^ g2; + int result = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; + return result; + } + + private static final int F32(int k64Cnt, int x, int[] k32) + { + int b0 = b0(x); + int b1 = b1(x); + int b2 = b2(x); + int b3 = b3(x); + int k0 = k32[0]; + int k1 = k32[1]; + int k2 = k32[2]; + int k3 = k32[3]; + + int result = 0; + switch (k64Cnt & 3) + { + case 1: + result = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)] + ^ MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)] + ^ MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)] + ^ MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; + break; + case 0: // same as 4 + b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); + b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); + b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); + b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); + case 3: + b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); + b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); + b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); + b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); + case 2: // 128-bit keys (optimize for this case) + result = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) + ^ b0(k0)] + ^ MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) + ^ b1(k0)] + ^ MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) + ^ b2(k0)] + ^ MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) ^ b3(k1)] & 0xFF) + ^ b3(k0)]; + break; + } + return result; + } + + private static final int Fe32(int[] sBox, int x, int R) + { + return sBox[2 * _b(x, R)] ^ sBox[2 * _b(x, R + 1) + 1] + ^ sBox[0x200 + 2 * _b(x, R + 2)] + ^ sBox[0x200 + 2 * _b(x, R + 3) + 1]; + } + + private static final int _b(int x, int N) + { + // int result = 0; + // switch (N%4) { + // case 0: result = b0(x); break; + // case 1: result = b1(x); break; + // case 2: result = b2(x); break; + // case 3: result = b3(x); break; + // } + // return result; + // profiling shows that the code spends too long in this method. + // following constructs seem to improve, albeit marginally, performance + switch (N % 4) + { + case 0: + return x & 0xFF; + case 1: + return (x >>> 8) & 0xFF; + case 2: + return (x >>> 16) & 0xFF; + default: + return x >>> 24; + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + Twofish result = new Twofish(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + // IBlockCipherSpi interface implementation -------------------------------- + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(8)); // 64-bit + al.add(new Integer(16)); // 128-bit + al.add(new Integer(24)); // 192-bit + al.add(new Integer(32)); // 256-bit + + return Collections.unmodifiableList(al).iterator(); + } + + /** + *

Expands a user-supplied key material into a session key for a designated + * block size.

+ * + * @param k the 64/128/192/256-bit user-key to use. + * @param bs the desired block size in bytes. + * @return an Object encapsulating the session key. + * @exception IllegalArgumentException if the block size is not 16 (128-bit). + * @exception InvalidKeyException if the key data is invalid. + */ + public Object makeKey(byte[] k, int bs) throws InvalidKeyException + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + if (k == null) + { + throw new InvalidKeyException("Empty key"); + } + int length = k.length; + if (!(length == 8 || length == 16 || length == 24 || length == 32)) + { + throw new InvalidKeyException("Incorrect key length"); + } + + int k64Cnt = length / 8; + int subkeyCnt = ROUND_SUBKEYS + 2 * ROUNDS; + int[] k32e = new int[4]; // even 32-bit entities + int[] k32o = new int[4]; // odd 32-bit entities + int[] sBoxKey = new int[4]; + // + // split user key material into even and odd 32-bit entities and + // compute S-box keys using (12, 8) Reed-Solomon code over GF(256) + // + int i, j, offset = 0; + for (i = 0, j = k64Cnt - 1; i < 4 && offset < length; i++, j--) + { + k32e[i] = (k[offset++] & 0xFF) | (k[offset++] & 0xFF) << 8 + | (k[offset++] & 0xFF) << 16 | (k[offset++] & 0xFF) << 24; + k32o[i] = (k[offset++] & 0xFF) | (k[offset++] & 0xFF) << 8 + | (k[offset++] & 0xFF) << 16 | (k[offset++] & 0xFF) << 24; + sBoxKey[j] = RS_MDS_Encode(k32e[i], k32o[i]); // reverse order + } + // compute the round decryption subkeys for PHT. these same subkeys + // will be used in encryption but will be applied in reverse order. + int q, A, B; + int[] subKeys = new int[subkeyCnt]; + for (i = q = 0; i < subkeyCnt / 2; i++, q += SK_STEP) + { + A = F32(k64Cnt, q, k32e); // A uses even key entities + B = F32(k64Cnt, q + SK_BUMP, k32o); // B uses odd key entities + B = B << 8 | B >>> 24; + A += B; + subKeys[2 * i] = A; // combine with a PHT + A += B; + subKeys[2 * i + 1] = A << SK_ROTL | A >>> (32 - SK_ROTL); + } + + // fully expand the table for speed + int k0 = sBoxKey[0]; + int k1 = sBoxKey[1]; + int k2 = sBoxKey[2]; + int k3 = sBoxKey[3]; + int b0, b1, b2, b3; + int[] sBox = new int[4 * 256]; + for (i = 0; i < 256; i++) + { + b0 = b1 = b2 = b3 = i; + switch (k64Cnt & 3) + { + case 1: + sBox[2 * i] = MDS[0][(P[P_01][b0] & 0xFF) ^ b0(k0)]; + sBox[2 * i + 1] = MDS[1][(P[P_11][b1] & 0xFF) ^ b1(k0)]; + sBox[0x200 + 2 * i] = MDS[2][(P[P_21][b2] & 0xFF) ^ b2(k0)]; + sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][b3] & 0xFF) ^ b3(k0)]; + break; + case 0: // same as 4 + b0 = (P[P_04][b0] & 0xFF) ^ b0(k3); + b1 = (P[P_14][b1] & 0xFF) ^ b1(k3); + b2 = (P[P_24][b2] & 0xFF) ^ b2(k3); + b3 = (P[P_34][b3] & 0xFF) ^ b3(k3); + case 3: + b0 = (P[P_03][b0] & 0xFF) ^ b0(k2); + b1 = (P[P_13][b1] & 0xFF) ^ b1(k2); + b2 = (P[P_23][b2] & 0xFF) ^ b2(k2); + b3 = (P[P_33][b3] & 0xFF) ^ b3(k2); + case 2: // 128-bit keys + sBox[2 * i] = MDS[0][(P[P_01][(P[P_02][b0] & 0xFF) ^ b0(k1)] & 0xFF) + ^ b0(k0)]; + sBox[2 * i + 1] = MDS[1][(P[P_11][(P[P_12][b1] & 0xFF) ^ b1(k1)] & 0xFF) + ^ b1(k0)]; + sBox[0x200 + 2 * i] = MDS[2][(P[P_21][(P[P_22][b2] & 0xFF) ^ b2(k1)] & 0xFF) + ^ b2(k0)]; + sBox[0x200 + 2 * i + 1] = MDS[3][(P[P_31][(P[P_32][b3] & 0xFF) + ^ b3(k1)] & 0xFF) + ^ b3(k0)]; + } + } + + if (DEBUG && debuglevel > 7) + { + System.out.println("S-box[]:"); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(sBox[i * 4 + j]) + ", "); + } + System.out.println(); + } + System.out.println(); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(sBox[256 + i * 4 + j]) + + ", "); + } + System.out.println(); + } + System.out.println(); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(sBox[512 + i * 4 + j]) + + ", "); + } + System.out.println(); + } + System.out.println(); + for (i = 0; i < 64; i++) + { + for (j = 0; j < 4; j++) + { + System.out.print("0x" + Util.toString(sBox[768 + i * 4 + j]) + + ", "); + } + System.out.println(); + } + System.out.println(); + System.out.println("User (odd, even) keys --> S-Box keys:"); + for (i = 0; i < k64Cnt; i++) + { + System.out.println("0x" + Util.toString(k32o[i]) + " 0x" + + Util.toString(k32e[i]) + " --> 0x" + + Util.toString(sBoxKey[k64Cnt - 1 - i])); + } + System.out.println(); + System.out.println("Round keys:"); + for (i = 0; i < ROUND_SUBKEYS + 2 * ROUNDS; i += 2) + { + System.out.println("0x" + Util.toString(subKeys[i]) + " 0x" + + Util.toString(subKeys[i + 1])); + } + System.out.println(); + } + + return new Object[] { sBox, subKeys }; + } + + public void encrypt(byte[] in, int inOffset, byte[] out, int outOffset, + Object sessionKey, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + + Object[] sk = (Object[]) sessionKey; // extract S-box and session key + int[] sBox = (int[]) sk[0]; + int[] sKey = (int[]) sk[1]; + + if (DEBUG && debuglevel > 6) + { + System.out.println("PT=" + Util.toString(in, inOffset, bs)); + } + + int x0 = (in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24; + int x1 = (in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24; + int x2 = (in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24; + int x3 = (in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24; + + x0 ^= sKey[INPUT_WHITEN]; + x1 ^= sKey[INPUT_WHITEN + 1]; + x2 ^= sKey[INPUT_WHITEN + 2]; + x3 ^= sKey[INPUT_WHITEN + 3]; + if (DEBUG && debuglevel > 6) + { + System.out.println("PTw=" + Util.toString(x0) + Util.toString(x1) + + Util.toString(x2) + Util.toString(x3)); + } + + int t0, t1; + int k = ROUND_SUBKEYS; + for (int R = 0; R < ROUNDS; R += 2) + { + t0 = Fe32(sBox, x0, 0); + t1 = Fe32(sBox, x1, 3); + x2 ^= t0 + t1 + sKey[k++]; + x2 = x2 >>> 1 | x2 << 31; + x3 = x3 << 1 | x3 >>> 31; + x3 ^= t0 + 2 * t1 + sKey[k++]; + if (DEBUG && debuglevel > 6) + { + System.out.println("CT" + (R) + "=" + Util.toString(x0) + + Util.toString(x1) + Util.toString(x2) + + Util.toString(x3)); + } + + t0 = Fe32(sBox, x2, 0); + t1 = Fe32(sBox, x3, 3); + x0 ^= t0 + t1 + sKey[k++]; + x0 = x0 >>> 1 | x0 << 31; + x1 = x1 << 1 | x1 >>> 31; + x1 ^= t0 + 2 * t1 + sKey[k++]; + if (DEBUG && debuglevel > 6) + { + System.out.println("CT" + (R + 1) + "=" + Util.toString(x0) + + Util.toString(x1) + Util.toString(x2) + + Util.toString(x3)); + } + } + x2 ^= sKey[OUTPUT_WHITEN]; + x3 ^= sKey[OUTPUT_WHITEN + 1]; + x0 ^= sKey[OUTPUT_WHITEN + 2]; + x1 ^= sKey[OUTPUT_WHITEN + 3]; + if (DEBUG && debuglevel > 6) + { + System.out.println("CTw=" + Util.toString(x0) + Util.toString(x1) + + Util.toString(x2) + Util.toString(x3)); + } + + out[outOffset++] = (byte) x2; + out[outOffset++] = (byte) (x2 >>> 8); + out[outOffset++] = (byte) (x2 >>> 16); + out[outOffset++] = (byte) (x2 >>> 24); + out[outOffset++] = (byte) x3; + out[outOffset++] = (byte) (x3 >>> 8); + out[outOffset++] = (byte) (x3 >>> 16); + out[outOffset++] = (byte) (x3 >>> 24); + out[outOffset++] = (byte) x0; + out[outOffset++] = (byte) (x0 >>> 8); + out[outOffset++] = (byte) (x0 >>> 16); + out[outOffset++] = (byte) (x0 >>> 24); + out[outOffset++] = (byte) x1; + out[outOffset++] = (byte) (x1 >>> 8); + out[outOffset++] = (byte) (x1 >>> 16); + out[outOffset] = (byte) (x1 >>> 24); + + if (DEBUG && debuglevel > 6) + { + System.out.println("CT=" + Util.toString(out, outOffset - 15, 16)); + System.out.println(); + } + } + + public void decrypt(byte[] in, int inOffset, byte[] out, int outOffset, + Object sessionKey, int bs) + { + if (bs != DEFAULT_BLOCK_SIZE) + { + throw new IllegalArgumentException(); + } + + Object[] sk = (Object[]) sessionKey; // extract S-box and session key + int[] sBox = (int[]) sk[0]; + int[] sKey = (int[]) sk[1]; + + if (DEBUG && debuglevel > 6) + { + System.out.println("CT=" + Util.toString(in, inOffset, bs)); + } + + int x2 = (in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24; + int x3 = (in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24; + int x0 = (in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24; + int x1 = (in[inOffset++] & 0xFF) | (in[inOffset++] & 0xFF) << 8 + | (in[inOffset++] & 0xFF) << 16 | (in[inOffset++] & 0xFF) << 24; + + x2 ^= sKey[OUTPUT_WHITEN]; + x3 ^= sKey[OUTPUT_WHITEN + 1]; + x0 ^= sKey[OUTPUT_WHITEN + 2]; + x1 ^= sKey[OUTPUT_WHITEN + 3]; + if (DEBUG && debuglevel > 6) + { + System.out.println("CTw=" + Util.toString(x2) + Util.toString(x3) + + Util.toString(x0) + Util.toString(x1)); + } + + int k = ROUND_SUBKEYS + 2 * ROUNDS - 1; + int t0, t1; + for (int R = 0; R < ROUNDS; R += 2) + { + t0 = Fe32(sBox, x2, 0); + t1 = Fe32(sBox, x3, 3); + x1 ^= t0 + 2 * t1 + sKey[k--]; + x1 = x1 >>> 1 | x1 << 31; + x0 = x0 << 1 | x0 >>> 31; + x0 ^= t0 + t1 + sKey[k--]; + if (DEBUG && debuglevel > 6) + { + System.out.println("PT" + (ROUNDS - R) + "=" + Util.toString(x2) + + Util.toString(x3) + Util.toString(x0) + + Util.toString(x1)); + } + + t0 = Fe32(sBox, x0, 0); + t1 = Fe32(sBox, x1, 3); + x3 ^= t0 + 2 * t1 + sKey[k--]; + x3 = x3 >>> 1 | x3 << 31; + x2 = x2 << 1 | x2 >>> 31; + x2 ^= t0 + t1 + sKey[k--]; + if (DEBUG && debuglevel > 6) + { + System.out.println("PT" + (ROUNDS - R - 1) + "=" + + Util.toString(x2) + Util.toString(x3) + + Util.toString(x0) + Util.toString(x1)); + } + } + x0 ^= sKey[INPUT_WHITEN]; + x1 ^= sKey[INPUT_WHITEN + 1]; + x2 ^= sKey[INPUT_WHITEN + 2]; + x3 ^= sKey[INPUT_WHITEN + 3]; + if (DEBUG && debuglevel > 6) + { + System.out.println("PTw=" + Util.toString(x2) + Util.toString(x3) + + Util.toString(x0) + Util.toString(x1)); + } + + out[outOffset++] = (byte) x0; + out[outOffset++] = (byte) (x0 >>> 8); + out[outOffset++] = (byte) (x0 >>> 16); + out[outOffset++] = (byte) (x0 >>> 24); + out[outOffset++] = (byte) x1; + out[outOffset++] = (byte) (x1 >>> 8); + out[outOffset++] = (byte) (x1 >>> 16); + out[outOffset++] = (byte) (x1 >>> 24); + out[outOffset++] = (byte) x2; + out[outOffset++] = (byte) (x2 >>> 8); + out[outOffset++] = (byte) (x2 >>> 16); + out[outOffset++] = (byte) (x2 >>> 24); + out[outOffset++] = (byte) x3; + out[outOffset++] = (byte) (x3 >>> 8); + out[outOffset++] = (byte) (x3 >>> 16); + out[outOffset] = (byte) (x3 >>> 24); + + if (DEBUG && debuglevel > 6) + { + System.out.println("PT=" + Util.toString(out, outOffset - 15, 16)); + System.out.println(); + } + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + { + result = testKat(KAT_KEY, KAT_CT); + } + valid = new Boolean(result); + } + return valid.booleanValue(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/cipher/WeakKeyException.java b/gnu/javax/crypto/cipher/WeakKeyException.java new file mode 100644 index 000000000..4454e0e45 --- /dev/null +++ b/gnu/javax/crypto/cipher/WeakKeyException.java @@ -0,0 +1,71 @@ +/* WeakKeyException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.cipher; + +import java.security.InvalidKeyException; + +/** + *

Checked exception thrown to indicate that a weak key has been generated + * and or specified instead of a valid non-weak value.

+ */ +public class WeakKeyException extends InvalidKeyException +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public WeakKeyException() + { + super(); + } + + public WeakKeyException(String msg) + { + super(msg); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/DiffieHellmanImpl.java b/gnu/javax/crypto/jce/DiffieHellmanImpl.java new file mode 100644 index 000000000..02761477a --- /dev/null +++ b/gnu/javax/crypto/jce/DiffieHellmanImpl.java @@ -0,0 +1,155 @@ +/* DiffieHellmanImpl.java -- implementation of the Diffie-Hellman key agreement. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.KeyAgreementSpi; +import javax.crypto.SecretKey; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * The JCE implementation of a 2-party Diffie-Hellman key agreement. + * + * @author Casey Marshall (csm@gnu.org) + */ +public final class DiffieHellmanImpl + extends KeyAgreementSpi +{ + /** The private key being used for this agreement. */ + private DHPrivateKey key; + + /** The current result. */ + private BigInteger result; + + /** True if the caller told us we are done. */ + private boolean last_phase_done; + + /** Trivial default constructor. */ + public DiffieHellmanImpl() + { + super(); + + key = null; + result = null; + last_phase_done = false; + } + + protected Key engineDoPhase(Key incoming, boolean lastPhase) + throws InvalidKeyException + { + if (key == null) + throw new IllegalStateException("Not initialized"); + + if (last_phase_done) + throw new IllegalStateException("Last phase already done"); + + if (! (incoming instanceof DHPublicKey)) + throw new InvalidKeyException("Key MUST be a DHPublicKey"); + + DHPublicKey pub = (DHPublicKey) incoming; + DHParameterSpec s1 = key.getParams(); + DHParameterSpec s2 = pub.getParams(); + if (! s1.getG().equals(s2.getG()) || ! s1.getP().equals(s2.getP()) + || s1.getL() != s2.getL()) + throw new InvalidKeyException("Incompatible key"); + + result = pub.getY().modPow(key.getX(), s1.getP()); + if (! lastPhase) + throw new IllegalArgumentException("This key-agreement MUST be concluded in one step only"); + + last_phase_done = true; + return null; + } + + protected byte[] engineGenerateSecret() + { + if (result == null || ! last_phase_done) + throw new IllegalStateException("Not finished"); + + byte[] buf = result.toByteArray(); + if (buf[0] == 0x00) + { + byte[] buf2 = new byte[buf.length - 1]; + System.arraycopy(buf, 1, buf2, 0, buf2.length); + buf = buf2; + } + + return buf; + } + + protected int engineGenerateSecret(byte[] secret, int offset) + { + byte[] s = engineGenerateSecret(); + System.arraycopy(s, 0, secret, offset, s.length); + return s.length; + } + + protected SecretKey engineGenerateSecret(String algorithm) + throws InvalidKeyException + { + byte[] s = engineGenerateSecret(); + return new SecretKeySpec(s, algorithm); + } + + protected void engineInit(Key key, SecureRandom random) + throws InvalidKeyException + { + if (! (key instanceof DHPrivateKey)) + throw new InvalidKeyException("Key MUST be a DHPrivateKey"); + + this.key = (DHPrivateKey) key; + result = null; + last_phase_done = false; + } + + protected void engineInit(Key key, AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidKeyException + { + engineInit(key, random); + } +} diff --git a/gnu/javax/crypto/jce/GnuCrypto.java b/gnu/javax/crypto/jce/GnuCrypto.java new file mode 100644 index 000000000..b0e73b132 --- /dev/null +++ b/gnu/javax/crypto/jce/GnuCrypto.java @@ -0,0 +1,620 @@ +/* GnuCrypto.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; +import java.util.HashSet; +import java.util.Set; + +/** + *

The GNU Crypto implementation of the Java Cryptographic Extension (JCE) + * Provider.

+ * + * @see java.security.Provider + */ +public final class GnuCrypto extends Provider +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

The GNU Crypto + * Provider.

+ */ + public GnuCrypto() + { + super(Registry.GNU_CRYPTO, 2.1, "GNU Crypto JCE Provider"); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + // Cipher + put("Cipher.ANUBIS", + gnu.javax.crypto.jce.cipher.AnubisSpi.class.getName()); + put("Cipher.ANUBIS ImplementedIn", "Software"); + put("Cipher.ARCFOUR", + gnu.javax.crypto.jce.cipher.ARCFourSpi.class.getName()); + put("Cipher.ARCFOUR ImplementedIn", "Software"); + put("Cipher.BLOWFISH", + gnu.javax.crypto.jce.cipher.BlowfishSpi.class.getName()); + put("Cipher.BLOWFISH ImplementedIn", "Software"); + put("Cipher.DES", gnu.javax.crypto.jce.cipher.DESSpi.class.getName()); + put("Cipher.DES ImplementedIn", "Software"); + put("Cipher.KHAZAD", + gnu.javax.crypto.jce.cipher.KhazadSpi.class.getName()); + put("Cipher.KHAZAD ImplementedIn", "Software"); + put("Cipher.NULL", + gnu.javax.crypto.jce.cipher.NullCipherSpi.class.getName()); + put("Cipher.NULL ImplementedIn", "Software"); + put("Cipher.AES", + gnu.javax.crypto.jce.cipher.RijndaelSpi.class.getName()); + put("Cipher.AES ImplementedIn", "Software"); + put("Cipher.RIJNDAEL", + gnu.javax.crypto.jce.cipher.RijndaelSpi.class.getName()); + put("Cipher.RIJNDAEL ImplementedIn", "Software"); + put("Cipher.SERPENT", + gnu.javax.crypto.jce.cipher.SerpentSpi.class.getName()); + put("Cipher.SERPENT ImplementedIn", "Software"); + put("Cipher.SQUARE", + gnu.javax.crypto.jce.cipher.SquareSpi.class.getName()); + put("Cipher.SQUARE ImplementedIn", "Software"); + put("Cipher.TRIPLEDES", + gnu.javax.crypto.jce.cipher.TripleDESSpi.class.getName()); + put("Cipher.TRIPLEDES ImplementedIn", "Software"); + put("Cipher.TWOFISH", + gnu.javax.crypto.jce.cipher.TwofishSpi.class.getName()); + put("Cipher.TWOFISH ImplementedIn", "Software"); + put("Cipher.CAST5", + gnu.javax.crypto.jce.cipher.Cast5Spi.class.getName()); + put("Cipher.CAST5 ImplementedIn", "Software"); + + // PBES2 ciphers. + put("Cipher.PBEWithHMacHavalAndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.AES.class.getName()); + put("Cipher.PBEWithHMacHavalAndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Anubis.class.getName()); + put( + "Cipher.PBEWithHMacHavalAndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Blowfish.class.getName()); + put("Cipher.PBEWithHMacHavalAndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Cast5.class.getName()); + put("Cipher.PBEWithHMacHavalAndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.DES.class.getName()); + put("Cipher.PBEWithHMacHavalAndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Khazad.class.getName()); + put("Cipher.PBEWithHMacHavalAndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Serpent.class.getName()); + put("Cipher.PBEWithHMacHavalAndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Square.class.getName()); + put( + "Cipher.PBEWithHMacHavalAndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.TripleDES.class.getName()); + put("Cipher.PBEWithHMacHavalAndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacHaval.Twofish.class.getName()); + + put("Cipher.PBEWithHMacMD2AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.AES.class.getName()); + put("Cipher.PBEWithHMacMD2AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Anubis.class.getName()); + put("Cipher.PBEWithHMacMD2AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Blowfish.class.getName()); + put("Cipher.PBEWithHMacMD2AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Cast5.class.getName()); + put("Cipher.PBEWithHMacMD2AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.DES.class.getName()); + put("Cipher.PBEWithHMacMD2AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Khazad.class.getName()); + put("Cipher.PBEWithHMacMD2AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Serpent.class.getName()); + put("Cipher.PBEWithHMacMD2AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Square.class.getName()); + put("Cipher.PBEWithHMacMD2AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.TripleDES.class.getName()); + put("Cipher.PBEWithHMacMD2AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD2.Twofish.class.getName()); + + put("Cipher.PBEWithHMacMD4AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.AES.class.getName()); + put("Cipher.PBEWithHMacMD4AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Anubis.class.getName()); + put("Cipher.PBEWithHMacMD4AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Blowfish.class.getName()); + put("Cipher.PBEWithHMacMD4AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Cast5.class.getName()); + put("Cipher.PBEWithHMacMD4AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.DES.class.getName()); + put("Cipher.PBEWithHMacMD4AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Khazad.class.getName()); + put("Cipher.PBEWithHMacMD4AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Serpent.class.getName()); + put("Cipher.PBEWithHMacMD4AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Square.class.getName()); + put("Cipher.PBEWithHMacMD4AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.TripleDES.class.getName()); + put("Cipher.PBEWithHMacMD4AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD4.Twofish.class.getName()); + + put("Cipher.PBEWithHMacMD5AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.AES.class.getName()); + put("Cipher.PBEWithHMacMD5AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Anubis.class.getName()); + put("Cipher.PBEWithHMacMD5AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Blowfish.class.getName()); + put("Cipher.PBEWithHMacMD5AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Cast5.class.getName()); + put("Cipher.PBEWithHMacMD5AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.DES.class.getName()); + put("Cipher.PBEWithHMacMD5AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Khazad.class.getName()); + put("Cipher.PBEWithHMacMD5AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Serpent.class.getName()); + put("Cipher.PBEWithHMacMD5AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Square.class.getName()); + put("Cipher.PBEWithHMacMD5AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.TripleDES.class.getName()); + put("Cipher.PBEWithHMacMD5AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacMD5.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA1AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.AES.class.getName()); + put("Cipher.PBEWithHMacSHA1AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Anubis.class.getName()); + put("Cipher.PBEWithHMacSHA1AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA1AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA1AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.DES.class.getName()); + put("Cipher.PBEWithHMacSHA1AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Khazad.class.getName()); + put("Cipher.PBEWithHMacSHA1AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA1AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Square.class.getName()); + put( + "Cipher.PBEWithHMacSHA1AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.TripleDES.class.getName()); + put("Cipher.PBEWithHMacSHA1AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA1.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA256AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.AES.class.getName()); + put("Cipher.PBEWithHMacSHA256AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Anubis.class.getName()); + put( + "Cipher.PBEWithHMacSHA256AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA256AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA256AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.DES.class.getName()); + put("Cipher.PBEWithHMacSHA256AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Khazad.class.getName()); + put( + "Cipher.PBEWithHMacSHA256AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA256AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Square.class.getName()); + put( + "Cipher.PBEWithHMacSHA256AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.TripleDES.class.getName()); + put( + "Cipher.PBEWithHMacSHA256AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA256.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA384AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.AES.class.getName()); + put("Cipher.PBEWithHMacSHA384AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Anubis.class.getName()); + put( + "Cipher.PBEWithHMacSHA384AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA384AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA384AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.DES.class.getName()); + put("Cipher.PBEWithHMacSHA384AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Khazad.class.getName()); + put( + "Cipher.PBEWithHMacSHA384AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA384AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Square.class.getName()); + put( + "Cipher.PBEWithHMacSHA384AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.TripleDES.class.getName()); + put( + "Cipher.PBEWithHMacSHA384AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA384.Twofish.class.getName()); + + put("Cipher.PBEWithHMacSHA512AndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.AES.class.getName()); + put("Cipher.PBEWithHMacSHA512AndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Anubis.class.getName()); + put( + "Cipher.PBEWithHMacSHA512AndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Blowfish.class.getName()); + put("Cipher.PBEWithHMacSHA512AndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Cast5.class.getName()); + put("Cipher.PBEWithHMacSHA512AndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.DES.class.getName()); + put("Cipher.PBEWithHMacSHA512AndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Khazad.class.getName()); + put( + "Cipher.PBEWithHMacSHA512AndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Serpent.class.getName()); + put("Cipher.PBEWithHMacSHA512AndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Square.class.getName()); + put( + "Cipher.PBEWithHMacSHA512AndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.TripleDES.class.getName()); + put( + "Cipher.PBEWithHMacSHA512AndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacSHA512.Twofish.class.getName()); + + put("Cipher.PBEWithHMacTigerAndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.AES.class.getName()); + put("Cipher.PBEWithHMacTigerAndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Anubis.class.getName()); + put( + "Cipher.PBEWithHMacTigerAndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Blowfish.class.getName()); + put("Cipher.PBEWithHMacTigerAndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Cast5.class.getName()); + put("Cipher.PBEWithHMacTigerAndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.DES.class.getName()); + put("Cipher.PBEWithHMacTigerAndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Khazad.class.getName()); + put("Cipher.PBEWithHMacTigerAndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Serpent.class.getName()); + put("Cipher.PBEWithHMacTigerAndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Square.class.getName()); + put( + "Cipher.PBEWithHMacTigerAndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.TripleDES.class.getName()); + put("Cipher.PBEWithHMacTigerAndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacTiger.Twofish.class.getName()); + + put("Cipher.PBEWithHMacWhirlpoolAndAES", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.AES.class.getName()); + put( + "Cipher.PBEWithHMacWhirlpoolAndAnubis", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Anubis.class.getName()); + put( + "Cipher.PBEWithHMacWhirlpoolAndBlowfish", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Blowfish.class.getName()); + put( + "Cipher.PBEWithHMacWhirlpoolAndCast5", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Cast5.class.getName()); + put("Cipher.PBEWithHMacWhirlpoolAndDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.DES.class.getName()); + put( + "Cipher.PBEWithHMacWhirlpoolAndKhazad", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Khazad.class.getName()); + put( + "Cipher.PBEWithHMacWhirlpoolAndSerpent", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Serpent.class.getName()); + put( + "Cipher.PBEWithHMacWhirlpoolAndSquare", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Square.class.getName()); + put( + "Cipher.PBEWithHMacWhirlpoolAndTripleDES", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.TripleDES.class.getName()); + put( + "Cipher.PBEWithHMacWhirlpoolAndTwofish", + gnu.javax.crypto.jce.cipher.PBES2.HMacWhirlpool.Twofish.class.getName()); + + // SecretKeyFactory interface to PBKDF2. + put( + "SecretKeyFactory.PBKDF2WithHMacHaval", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacHaval.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacMD2", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD2.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacMD4", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD4.class.getName()); + put("SecretKeyFactory.PBKDF2WithHMacMD5", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacMD5.class.getName()); + put( + "SecretKeyFactory.PBKDF2WithHMacSHA1", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA1.class.getName()); + put( + "SecretKeyFactory.PBKDF2WithHMacSHA256", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA256.class.getName()); + put( + "SecretKeyFactory.PBKDF2WithHMacSHA384", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA384.class.getName()); + put( + "SecretKeyFactory.PBKDF2WithHMacSHA512", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacSHA512.class.getName()); + put( + "SecretKeyFactory.PBKDF2WithHMacTiger", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacTiger.class.getName()); + put( + "SecretKeyFactory.PBKDF2WithHMacWhirlpool", + gnu.javax.crypto.jce.PBKDF2SecretKeyFactory.HMacWhirlpool.class.getName()); + + // Simple SecretKeyFactory implementations. + put("SecretKeyFactory.Anubis", + gnu.javax.crypto.jce.key.AnubisSecretKeyFactoryImpl.class.getName()); + put( + "SecretKeyFactory.Blowfish", + gnu.javax.crypto.jce.key.BlowfishSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Cast5", + gnu.javax.crypto.jce.key.Cast5SecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.DES", + gnu.javax.crypto.jce.key.DESSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Khazad", + gnu.javax.crypto.jce.key.KhazadSecretKeyFactoryImpl.class.getName()); + put( + "SecretKeyFactory.Rijndael", + gnu.javax.crypto.jce.key.RijndaelSecretKeyFactoryImpl.class.getName()); + put( + "SecretKeyFactory.Serpent", + gnu.javax.crypto.jce.key.SerpentSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.Square", + gnu.javax.crypto.jce.key.SquareSecretKeyFactoryImpl.class.getName()); + put("SecretKeyFactory.TripleDES", + gnu.javax.crypto.jce.key.DESedeSecretKeyFactoryImpl.class.getName()); + put("Alg.Alias.SecretKeyFactory.AES", "Rijndael"); + put("Alg.Alias.SecretKeyFactory.DESede", "TripleDES"); + put("Alg.Alias.SecretKeyFactory.3-DES", "TripleDES"); + put("Alg.Alias.SecretKeyFactory.3DES", "TripleDES"); + + put("AlgorithmParameters.BlockCipherParameters", + gnu.javax.crypto.jce.params.BlockCipherParameters.class.getName()); + + + // KeyGenerator Adapter implementations + put("KeyGenerator.Anubis", + gnu.javax.crypto.jce.key.AnubisKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Blowfish", + gnu.javax.crypto.jce.key.BlowfishKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Cast5", + gnu.javax.crypto.jce.key.Cast5KeyGeneratorImpl.class.getName()); + put("KeyGenerator.DES", + gnu.javax.crypto.jce.key.DESKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Khazad", + gnu.javax.crypto.jce.key.KhazadKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Rijndael", + gnu.javax.crypto.jce.key.RijndaelKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Serpent", + gnu.javax.crypto.jce.key.SerpentKeyGeneratorImpl.class.getName()); + put("KeyGenerator.Square", + gnu.javax.crypto.jce.key.SquareKeyGeneratorImpl.class.getName()); + put("KeyGenerator.TripleDES", + gnu.javax.crypto.jce.key.TripleDESKeyGeneratorImpl.class.getName()); + put("Alg.Alias.KeyGenerator.AES", "Rijndael"); + put("Alg.Alias.KeyGenerator.DESede", "TripleDES"); + put("Alg.Alias.KeyGenerator.3-DES", "TripleDES"); + put("Alg.Alias.KeyGenerator.3DES", "TripleDES"); + + // MAC + put("Mac.HMAC-MD2", gnu.javax.crypto.jce.mac.HMacMD2Spi.class.getName()); + put("Mac.HMAC-MD4", gnu.javax.crypto.jce.mac.HMacMD4Spi.class.getName()); + put("Mac.HMAC-MD5", gnu.javax.crypto.jce.mac.HMacMD5Spi.class.getName()); + put("Mac.HMAC-RIPEMD128", + gnu.javax.crypto.jce.mac.HMacRipeMD128Spi.class.getName()); + put("Mac.HMAC-RIPEMD160", + gnu.javax.crypto.jce.mac.HMacRipeMD160Spi.class.getName()); + put("Mac.HMAC-SHA160", + gnu.javax.crypto.jce.mac.HMacSHA160Spi.class.getName()); + put("Mac.HMAC-SHA256", + gnu.javax.crypto.jce.mac.HMacSHA256Spi.class.getName()); + put("Mac.HMAC-SHA384", + gnu.javax.crypto.jce.mac.HMacSHA384Spi.class.getName()); + put("Mac.HMAC-SHA512", + gnu.javax.crypto.jce.mac.HMacSHA512Spi.class.getName()); + put("Mac.HMAC-TIGER", + gnu.javax.crypto.jce.mac.HMacTigerSpi.class.getName()); + put("Mac.HMAC-HAVAL", + gnu.javax.crypto.jce.mac.HMacHavalSpi.class.getName()); + put("Mac.HMAC-WHIRLPOOL", + gnu.javax.crypto.jce.mac.HMacWhirlpoolSpi.class.getName()); + put("Mac.TMMH16", gnu.javax.crypto.jce.mac.TMMH16Spi.class.getName()); + put("Mac.UHASH32", gnu.javax.crypto.jce.mac.UHash32Spi.class.getName()); + put("Mac.UMAC32", gnu.javax.crypto.jce.mac.UMac32Spi.class.getName()); + + put("Mac.OMAC-ANUBIS", + gnu.javax.crypto.jce.mac.OMacAnubisImpl.class.getName()); + put("Mac.OMAC-BLOWFISH", + gnu.javax.crypto.jce.mac.OMacBlowfishImpl.class.getName()); + put("Mac.OMAC-CAST5", + gnu.javax.crypto.jce.mac.OMacCast5Impl.class.getName()); + put("Mac.OMAC-DES", + gnu.javax.crypto.jce.mac.OMacDESImpl.class.getName()); + put("Mac.OMAC-KHAZAD", + gnu.javax.crypto.jce.mac.OMacKhazadImpl.class.getName()); + put("Mac.OMAC-RIJNDAEL", + gnu.javax.crypto.jce.mac.OMacRijndaelImpl.class.getName()); + put("Mac.OMAC-SERPENT", + gnu.javax.crypto.jce.mac.OMacSerpentImpl.class.getName()); + put("Mac.OMAC-SQUARE", + gnu.javax.crypto.jce.mac.OMacSquareImpl.class.getName()); + put("Mac.OMAC-TRIPLEDES", + gnu.javax.crypto.jce.mac.OMacTripleDESImpl.class.getName()); + put("Mac.OMAC-TWOFISH", + gnu.javax.crypto.jce.mac.OMacTwofishImpl.class.getName()); + + // Aliases + put("Alg.Alias.AlgorithmParameters.AES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.BLOWFISH", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.ANUBIS", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.KHAZAD", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.NULL", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.RIJNDAEL", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.SERPENT", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.SQUARE", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.TWOFISH", "BlockCipherParameters"); + put("Alg.Alias.Cipher.RC4", "ARCFOUR"); + put("Alg.Alias.Cipher.3-DES", "TRIPLEDES"); + put("Alg.Alias.Cipher.3DES", "TRIPLEDES"); + put("Alg.Alias.Cipher.DES-EDE", "TRIPLEDES"); + put("Alg.Alias.Cipher.DESede", "TRIPLEDES"); + put("Alg.Alias.Cipher.CAST128", "CAST5"); + put("Alg.Alias.Cipher.CAST-128", "CAST5"); + put("Alg.Alias.Mac.HMAC-SHS", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA1", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA-160", "HMAC-SHA160"); + put("Alg.Alias.Mac.HMAC-SHA-256", "HMAC-SHA256"); + put("Alg.Alias.Mac.HMAC-SHA-384", "HMAC-SHA384"); + put("Alg.Alias.Mac.HMAC-SHA-512", "HMAC-SHA512"); + put("Alg.Alias.Mac.HMAC-RIPEMD-160", "HMAC-RIPEMD160"); + put("Alg.Alias.Mac.HMAC-RIPEMD-128", "HMAC-RIPEMD128"); + put("Alg.Alias.Mac.OMAC-AES", "OMAC-RIJNDAEL"); + put("Alg.Alias.Mac.OMAC-3DES", "OMAC-3DES"); + put("Alg.Alias.Mac.HmacMD4", "HMAC-MD4"); + put("Alg.Alias.Mac.HmacMD5", "HMAC-MD5"); + put("Alg.Alias.Mac.HmacSHA-1", "HMAC-SHA-1"); + put("Alg.Alias.Mac.HmacSHA1", "HMAC-SHA1"); + put("Alg.Alias.Mac.HmacSHA-160", "HMAC-SHA-160"); + put("Alg.Alias.Mac.HmacSHA160", "HMAC-SHA-160"); + put("Alg.Alias.Mac.HmacSHA-256", "HMAC-SHA-256"); + put("Alg.Alias.Mac.HmacSHA256", "HMAC-SHA-256"); + put("Alg.Alias.Mac.HmacSHA-384", "HMAC-SHA-384"); + put("Alg.Alias.Mac.HmacSHA384", "HMAC-SHA-384"); + put("Alg.Alias.Mac.HmacSHA-512", "HMAC-SHA-512"); + put("Alg.Alias.Mac.HmacSHA512", "HMAC-SHA-512"); + put("Alg.Alias.Mac.HmacRIPEMD128", "HMAC-RIPEMD128"); + put("Alg.Alias.Mac.HmacRIPEMD-128", "HMAC-RIPEMD128"); + put("Alg.Alias.Mac.HmacRIPEMD160", "HMAC-RIPEMD160"); + put("Alg.Alias.Mac.HmacRIPEMD-160", "HMAC-RIPEMD160"); + put("Alg.Alias.Mac.HmacTiger", "HMAC-TIGER"); + put("Alg.Alias.Mac.HmacHaval", "HMAC-HAVAL"); + put("Alg.Alias.Mac.HmacWhirlpool", "HMAC-WHIRLPOOL"); + + // KeyAgreement + put("KeyAgreement.DH", + gnu.javax.crypto.jce.DiffieHellmanImpl.class.getName()); + put("Alg.Alias.KeyAgreement.DiffieHellman", "DH"); + + // Cipher + put("Cipher.RSAES-PKCS1-v1_5", + gnu.javax.crypto.RSACipherImpl.class.getName()); + put("Alg.Alias.Cipher.RSA", "RSAES-PKCS1-v1_5"); + + // SecureRandom + put("SecureRandom.ARCFOUR", gnu.javax.crypto.jce.prng.ARCFourRandomSpi.class.getName()); + put("SecureRandom.ARCFOUR ImplementedIn", "Software"); + put("SecureRandom.CSPRNG", gnu.javax.crypto.jce.prng.CSPRNGSpi.class.getName()); + put("SecureRandom.CSPRNG ImplementedIn", "Software"); + put("SecureRandom.ICM", gnu.javax.crypto.jce.prng.ICMRandomSpi.class.getName()); + put("SecureRandom.ICM ImplementedIn", "Software"); + put("SecureRandom.UMAC-KDF", gnu.javax.crypto.jce.prng.UMacRandomSpi.class.getName()); + put("SecureRandom.UMAC-KDF ImplementedIn", "Software"); + put("SecureRandom.Fortuna", gnu.javax.crypto.jce.prng.FortunaImpl.class.getName ()); + put("SecureRandom.Fortuna ImplementedIn", "Software"); + + // KeyStore + put("KeyStore.GKR", gnu.javax.crypto.jce.keyring.GnuKeyring.class.getName()); + put("Alg.Alias.KeyStore.GnuKeyring", "GKR"); + + // KeyPairGenerator --------------------------------------------------- + put("KeyPairGenerator.DH", + gnu.javax.crypto.jce.sig.DHKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.DH KeySize", "512"); + put("KeyPairGenerator.DH ImplementedIn", "Software"); + + put("Alg.Alias.KeyPairGenerator.DiffieHellman", "DH"); + + // KeyFactory --------------------------------------------------------- + put("KeyFactory.DH", + gnu.javax.crypto.jce.sig.DHKeyFactory.class.getName()); + + put("Alg.Alias,KeyFactory.DiffieHellman", "DH"); + + // Algorithm Parameters ----------------------------------------------- + put("AlgorithmParameters.DH", + gnu.javax.crypto.jce.sig.DHParameters.class.getName()); + + put("Alg.Alias.AlgorithmParameters.DiffieHellman", "DH"); + + // Algorithm Parameters Generator ------------------------------------- + put("AlgorithmParameterGenerator.DH", + gnu.javax.crypto.jce.sig.DHParametersGenerator.class.getName()); + + put("Alg.Alias.AlgorithmParameterGenerator.DiffieHellman", "DH"); + + return null; + } + }); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns a {@link Set} of names of symmetric key block cipher algorithms + * available from this {@link Provider}.

+ * + * @return a {@link Set} of cipher names (Strings). + */ + public static final Set getCipherNames() + { + HashSet s = new HashSet(); + s.addAll(CipherFactory.getNames()); + s.add(Registry.ARCFOUR_PRNG); + return s; + } + + /** + *

Returns a {@link Set} of names of MAC algorithms available from + * this {@link Provider}.

+ * + * @return a {@link Set} of MAC names (Strings). + */ + public static final Set getMacNames() + { + return MacFactory.getNames(); + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/javax/crypto/jce/GnuSasl.java b/gnu/javax/crypto/jce/GnuSasl.java new file mode 100644 index 000000000..6ee86ae19 --- /dev/null +++ b/gnu/javax/crypto/jce/GnuSasl.java @@ -0,0 +1,114 @@ +/* GnuSasl.java -- javax.security.sasl algorithms. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ClientFactory; +import gnu.javax.crypto.sasl.ServerFactory; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; +import java.util.Set; + +public final class GnuSasl extends Provider +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public GnuSasl() + { + super (Registry.GNU_SASL, 2.1, "GNU Crypto SASL Provider"); + + AccessController.doPrivileged (new PrivilegedAction() + { + public Object run() + { + // SASL Client and Server mechanisms + put("SaslClientFactory.ANONYMOUS", gnu.javax.crypto.sasl.ClientFactory.class.getName()); + put("SaslClientFactory.PLAIN", gnu.javax.crypto.sasl.ClientFactory.class.getName()); + put("SaslClientFactory.CRAM-MD5", gnu.javax.crypto.sasl.ClientFactory.class.getName()); + put("SaslClientFactory.SRP", gnu.javax.crypto.sasl.ClientFactory.class.getName()); + + put("SaslServerFactory.ANONYMOUS", gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.PLAIN", gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.CRAM-MD5", gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-MD5", gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-SHA-160", gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-RIPEMD128", gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-RIPEMD160", gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-TIGER", gnu.javax.crypto.sasl.ServerFactory.class.getName()); + put("SaslServerFactory.SRP-WHIRLPOOL", gnu.javax.crypto.sasl.ServerFactory.class.getName()); + + put("Alg.Alias.SaslServerFactory.SRP-SHS", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA1", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA-1", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-SHA160", "SRP-SHA-160"); + put("Alg.Alias.SaslServerFactory.SRP-RIPEMD-128", "SRP-RIPEMD128"); + put("Alg.Alias.SaslServerFactory.SRP-RIPEMD-160", "SRP-RIPEMD160"); + + return null; + } + }); + } + + /** + *

Returns a {@link Set} of names of SASL Client mechanisms available from + * this {@link Provider}.

+ * + * @return a {@link Set} of SASL Client mechanisms (Strings). + */ + public static final Set getSaslClientMechanismNames() + { + return ClientFactory.getNames(); + } + + /** + *

Returns a {@link Set} of names of SASL Server mechanisms available from + * this {@link Provider}.

+ * + * @return a {@link Set} of SASL Server mechanisms (Strings). + */ + public static final Set getSaslServerMechanismNames() + { + return ServerFactory.getNames(); + } +} diff --git a/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java b/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java new file mode 100644 index 000000000..59231c6c7 --- /dev/null +++ b/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java @@ -0,0 +1,229 @@ +/* PBKDF2SecretKeyFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce; + +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import java.util.HashMap; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +import gnu.javax.crypto.prng.IPBE; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.PRNGFactory; + +public abstract class PBKDF2SecretKeyFactory extends SecretKeyFactorySpi +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + protected String macName; + + private static final int DEFAULT_ITERATION_COUNT = 1000; + + private static final int DEFAULT_KEY_LEN = 32; + + // Constructor. + // ------------------------------------------------------------------------ + + protected PBKDF2SecretKeyFactory(String macName) + { + this.macName = macName; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + protected SecretKey engineGenerateSecret(KeySpec spec) + throws InvalidKeySpecException + { + if (!(spec instanceof PBEKeySpec)) + { + throw new InvalidKeySpecException("not a PBEKeySpec"); + } + IRandom kdf = PRNGFactory.getInstance("PBKDF2-" + macName); + HashMap attr = new HashMap(); + attr.put(IPBE.PASSWORD, ((PBEKeySpec) spec).getPassword()); + byte[] salt = ((PBEKeySpec) spec).getSalt(); + if (salt == null) + { + salt = new byte[0]; + } + attr.put(IPBE.SALT, salt); + int ic = ((PBEKeySpec) spec).getIterationCount(); + if (ic <= 0) + { + ic = DEFAULT_ITERATION_COUNT; + } + attr.put(IPBE.ITERATION_COUNT, new Integer(ic)); + kdf.init(attr); + int len = ((PBEKeySpec) spec).getKeyLength(); + if (len <= 0) + { + len = DEFAULT_KEY_LEN; + } + byte[] dk = new byte[len]; + try + { + kdf.nextBytes(dk, 0, len); + } + catch (LimitReachedException lre) + { + throw new IllegalArgumentException(lre.toString()); + } + + return new SecretKeySpec(dk, "PBKDF2"); + } + + protected KeySpec engineGetKeySpec(SecretKey key, Class clazz) + throws InvalidKeySpecException + { + throw new InvalidKeySpecException("not supported"); + } + + protected SecretKey engineTranslateKey(SecretKey key) + { + return new SecretKeySpec(key.getEncoded(), key.getAlgorithm()); + } + + // Inner classes. + // ------------------------------------------------------------------------ + + public static class HMacHaval extends PBKDF2SecretKeyFactory + { + public HMacHaval() + { + super("HMAC-HAVAL"); + } + } + + public static class HMacMD2 extends PBKDF2SecretKeyFactory + { + public HMacMD2() + { + super("HMAC-MD2"); + } + } + + public static class HMacMD4 extends PBKDF2SecretKeyFactory + { + public HMacMD4() + { + super("HMAC-MD4"); + } + } + + public static class HMacMD5 extends PBKDF2SecretKeyFactory + { + public HMacMD5() + { + super("HMAC-MD5"); + } + } + + public static class HMacRipeMD128 extends PBKDF2SecretKeyFactory + { + public HMacRipeMD128() + { + super("HMAC-RIPEMD128"); + } + } + + public static class HMacRipeMD160 extends PBKDF2SecretKeyFactory + { + public HMacRipeMD160() + { + super("HMAC-RIPEMD160"); + } + } + + public static class HMacSHA1 extends PBKDF2SecretKeyFactory + { + public HMacSHA1() + { + super("HMAC-SHA1"); + } + } + + public static class HMacSHA256 extends PBKDF2SecretKeyFactory + { + public HMacSHA256() + { + super("HMAC-SHA256"); + } + } + + public static class HMacSHA384 extends PBKDF2SecretKeyFactory + { + public HMacSHA384() + { + super("HMAC-SHA384"); + } + } + + public static class HMacSHA512 extends PBKDF2SecretKeyFactory + { + public HMacSHA512() + { + super("HMAC-SHA512"); + } + } + + public static class HMacTiger extends PBKDF2SecretKeyFactory + { + public HMacTiger() + { + super("HMAC-TIGER"); + } + } + + public static class HMacWhirlpool extends PBKDF2SecretKeyFactory + { + public HMacWhirlpool() + { + super("HMAC-WHIRLPOOL"); + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/AESSpi.java b/gnu/javax/crypto/jce/cipher/AESSpi.java new file mode 100644 index 000000000..541868c50 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/AESSpi.java @@ -0,0 +1,104 @@ +/* AESSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +/** + * The implementation of the AES Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class AESSpi extends CipherAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public AESSpi() + { + super(Registry.AES_CIPHER, 16); + } + + // Methods from CipherAdapter + // ----------------------------------------------------------------------- + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (params instanceof BlockCipherParameterSpec) + { + if (((BlockCipherParameterSpec) params).getBlockSize() != 16) + { + throw new InvalidAlgorithmParameterException( + "AES block size must be 16 bytes"); + } + } + super.engineInit(opmode, key, params, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + AlgorithmParameterSpec spec = null; + try + { + if (params != null) + { + spec = params.getParameterSpec(BlockCipherParameterSpec.class); + } + } + catch (InvalidParameterSpecException ipse) + { + } + engineInit(opmode, key, spec, random); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/ARCFourSpi.java b/gnu/javax/crypto/jce/cipher/ARCFourSpi.java new file mode 100644 index 000000000..7f2c9aeee --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/ARCFourSpi.java @@ -0,0 +1,208 @@ +/* ARCFourSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; +import gnu.javax.crypto.prng.ARCFour; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import java.util.HashMap; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; + +/** + * The Service Provider Interface (SPI) for the ARCFOUR + * stream cipher. + * + * @version $Revision: 1.1.4.1 $ + */ +public class ARCFourSpi extends CipherSpi +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + private IRandom keystream; + + // Constructors. + // ----------------------------------------------------------------------- + + public ARCFourSpi() + { + super(); + keystream = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG); + } + + // Methods implementing CipherSpi. + // ----------------------------------------------------------------------- + + protected int engineGetBlockSize() + { + return 0; // stream cipher. + } + + protected void engineSetMode(String s) throws NoSuchAlgorithmException + { + // ignored. + } + + protected void engineSetPadding(String s) throws NoSuchPaddingException + { + // ignored. + } + + protected byte[] engineGetIV() + { + return null; + } + + protected int engineGetOutputSize(int in) + { + return in; + } + + protected AlgorithmParameters engineGetParameters() + { + return null; + } + + protected void engineInit(int mode, Key key, SecureRandom r) + throws InvalidKeyException + { + if (mode != Cipher.ENCRYPT_MODE && mode != Cipher.DECRYPT_MODE) + { + throw new IllegalArgumentException( + "arcfour is for encryption or decryption only"); + } + if (key == null || !key.getFormat().equalsIgnoreCase("RAW")) + { + throw new InvalidKeyException("key must be non-null raw bytes"); + } + HashMap attrib = new HashMap(); + attrib.put(ARCFour.ARCFOUR_KEY_MATERIAL, key.getEncoded()); + keystream.init(attrib); + } + + protected void engineInit(int mode, Key key, AlgorithmParameterSpec p, + SecureRandom r) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + engineInit(mode, key, r); + } + + protected void engineInit(int mode, Key key, AlgorithmParameters p, + SecureRandom r) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + engineInit(mode, key, r); + } + + protected byte[] engineUpdate(byte[] in, int offset, int length) + { + if (length < 0 || offset < 0 || length + offset > in.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + byte[] result = new byte[length]; + try + { + for (int i = 0; i < length; i++) + { + result[i] = (byte) (in[i + offset] ^ keystream.nextByte()); + } + } + catch (LimitReachedException wontHappen) + { + } + return result; + } + + protected int engineUpdate(byte[] in, int inOffset, int length, byte[] out, + int outOffset) throws ShortBufferException + { + if (length < 0 || inOffset < 0 || length + inOffset > in.length + || outOffset < 0) + { + throw new ArrayIndexOutOfBoundsException(); + } + if (outOffset + length > out.length) + { + throw new ShortBufferException(); + } + try + { + for (int i = 0; i < length; i++) + { + out[i + outOffset] = (byte) (in[i + inOffset] ^ keystream.nextByte()); + } + } + catch (LimitReachedException wontHappen) + { + } + return length; + } + + protected byte[] engineDoFinal(byte[] in, int offset, int length) + throws IllegalBlockSizeException, BadPaddingException + { + return engineUpdate(in, offset, length); + } + + protected int engineDoFinal(byte[] in, int inOffset, int length, byte[] out, + int outOffset) throws ShortBufferException, + IllegalBlockSizeException, BadPaddingException + { + return engineUpdate(in, inOffset, length, out, outOffset); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/AnubisSpi.java b/gnu/javax/crypto/jce/cipher/AnubisSpi.java new file mode 100644 index 000000000..732993736 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/AnubisSpi.java @@ -0,0 +1,59 @@ +/* AnubisSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Anubis Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class AnubisSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public AnubisSpi() + { + super(Registry.ANUBIS_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/BlowfishSpi.java b/gnu/javax/crypto/jce/cipher/BlowfishSpi.java new file mode 100644 index 000000000..9c8ef0547 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/BlowfishSpi.java @@ -0,0 +1,59 @@ +/* BlowfishSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Blowfish Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class BlowfishSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public BlowfishSpi() + { + super(Registry.BLOWFISH_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/Cast5Spi.java b/gnu/javax/crypto/jce/cipher/Cast5Spi.java new file mode 100644 index 000000000..b1d4cf703 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/Cast5Spi.java @@ -0,0 +1,68 @@ +/* Cast5Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the CAST5 (a.k.a. CAST-128) Service + * Provider Interface (SPI) Adapter. + * + * @version Revision: $ + */ +public class Cast5Spi extends CipherAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public Cast5Spi() + { + super(Registry.CAST5_CIPHER); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/CipherAdapter.java b/gnu/javax/crypto/jce/cipher/CipherAdapter.java new file mode 100644 index 000000000..96d7741dd --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/CipherAdapter.java @@ -0,0 +1,507 @@ +/* CipherAdapter.java -- + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; + +/** + *

The implementation of a generic {@link Cipher} Adapter class to + * wrap GNU Crypto cipher instances.

+ * + *

This class defines the Service Provider Interface (SPI) for + * the {@link Cipher} class, which provides the functionality of symmetric-key + * block ciphers, such as the AES.

+ * + *

This base class defines all of the abstract methods in {@link CipherSpi}, + * but does not define the (non-abstract) key wrapping functions that extended + * the base cipher SPI, and these methods thus immediately throw an + * {@link UnsupportedOperationException}. If a cipher implementation provides + * this functionality, or if it in fact accepts parameters other than the key + * and the initialization vector, the subclass should override those methods. + * Otherwise a subclass need only call the {@link #CipherAdapter(String)} + * constructor with the name of the cipher.

+ * + * @version $Revision: 1.1.4.1 $ + */ +class CipherAdapter extends CipherSpi +{ + + // Constants and variables. + // ------------------------------------------------------------------------- + + /** Our cipher instance. */ + protected IBlockCipher cipher; + + /** Our mode instance. */ + protected IMode mode; + + /** Our padding instance. */ + protected IPad pad; + + /** The current key size. */ + protected int keyLen; + + /** Our attributes map. */ + protected Map attributes; + + /** An incomplete block. */ + protected byte[] partBlock; + + /** The number of bytes in {@link #partBlock}. */ + protected int partLen; + + /** The length of blocks we are processing. */ + protected int blockLen; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Protected constructor to be called by subclasses. The cipher name + * argument should be the appropriate one listed in {@link gnu.crypto.Registry}. + * The basic cipher instance is created, along with an instance of the + * {@link gnu.crypto.mode.ECB} mode and no padding.

+ * + * @param cipherName The cipher to instantiate. + * @param blockLen The block length to use. + */ + protected CipherAdapter(String cipherName, int blockLen) + { + cipher = CipherFactory.getInstance(cipherName); + attributes = new HashMap(); + this.blockLen = blockLen; + mode = ModeFactory.getInstance("ECB", cipher, blockLen); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(blockLen)); + } + + /** + *

Creates a new cipher adapter with the default block size.

+ * + * @param cipherName The cipher to instantiate. + */ + protected CipherAdapter(String cipherName) + { + cipher = CipherFactory.getInstance(cipherName); + blockLen = cipher.defaultBlockSize(); + attributes = new HashMap(); + mode = ModeFactory.getInstance("ECB", cipher, blockLen); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(blockLen)); + } + + // Instance methods implementing javax.crypto.CipherSpi. + // ------------------------------------------------------------------------- + + protected void engineSetMode(String modeName) throws NoSuchAlgorithmException + { + if (modeName.length() >= 3 + && modeName.substring(0, 3).equalsIgnoreCase("CFB")) + { + if (modeName.length() > 3) + { + try + { + int bs = Integer.parseInt(modeName.substring(3)); + attributes.put(IMode.MODE_BLOCK_SIZE, new Integer(bs / 8)); + } + catch (NumberFormatException nfe) + { + throw new NoSuchAlgorithmException(modeName); + } + modeName = "CFB"; + } + } + else + { + attributes.remove(IMode.MODE_BLOCK_SIZE); + } + mode = ModeFactory.getInstance(modeName, cipher, blockLen); + if (mode == null) + { + throw new NoSuchAlgorithmException(modeName); + } + } + + protected void engineSetPadding(String padName) throws NoSuchPaddingException + { + if (padName.equalsIgnoreCase("NoPadding")) + { + pad = null; + return; + } + pad = PadFactory.getInstance(padName); + if (pad == null) + { + throw new NoSuchPaddingException(padName); + } + } + + protected int engineGetBlockSize() + { + if (cipher != null) + { + return blockLen; + } + return 0; + } + + protected int engineGetOutputSize(int inputLen) + { + final int blockSize = mode.currentBlockSize(); + return ((inputLen + partLen) / blockSize) * blockSize; + } + + protected byte[] engineGetIV() + { + byte[] iv = (byte[]) attributes.get(IMode.IV); + if (iv == null) + { + return null; + } + return (byte[]) iv.clone(); + } + + protected AlgorithmParameters engineGetParameters() + { + BlockCipherParameterSpec spec = new BlockCipherParameterSpec( + (byte[]) attributes.get(IMode.IV), + cipher.currentBlockSize(), + keyLen); + AlgorithmParameters params; + try + { + params = AlgorithmParameters.getInstance("BlockCipherParameters"); + params.init(spec); + } + catch (NoSuchAlgorithmException nsae) + { + return null; + } + catch (InvalidParameterSpecException ipse) + { + return null; + } + return params; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + switch (opmode) + { + case Cipher.ENCRYPT_MODE: + attributes.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + break; + case Cipher.DECRYPT_MODE: + attributes.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + break; + } + if (!key.getFormat().equalsIgnoreCase("RAW")) + { + throw new InvalidKeyException("bad key format " + key.getFormat()); + } + byte[] kb = key.getEncoded(); + if (keyLen == 0) + { + keyLen = kb.length; + } + else if (keyLen < kb.length) + { + byte[] kbb = kb; + kb = new byte[keyLen]; + System.arraycopy(kbb, 0, kb, 0, keyLen); + } + attributes.put(IBlockCipher.KEY_MATERIAL, kb); + reset(); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (params == null) + { + byte[] iv = new byte[blockLen]; + random.nextBytes(iv); + attributes.put(IMode.IV, iv); + blockLen = cipher.defaultBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(blockLen)); + keyLen = 0; + } + else if (params instanceof BlockCipherParameterSpec) + { + attributes.put( + IBlockCipher.CIPHER_BLOCK_SIZE, + new Integer( + ((BlockCipherParameterSpec) params).getBlockSize())); + attributes.put(IMode.IV, ((BlockCipherParameterSpec) params).getIV()); + keyLen = ((BlockCipherParameterSpec) params).getKeySize(); + blockLen = ((BlockCipherParameterSpec) params).getBlockSize(); + } + else if (params instanceof IvParameterSpec) + { + attributes.put(IMode.IV, ((IvParameterSpec) params).getIV()); + blockLen = cipher.defaultBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(blockLen)); + keyLen = 0; + } + engineInit(opmode, key, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + AlgorithmParameterSpec spec = null; + try + { + if (params != null) + { + spec = params.getParameterSpec(BlockCipherParameterSpec.class); + } + } + catch (InvalidParameterSpecException ignored) + { + } + engineInit(opmode, key, spec, random); + } + + protected byte[] engineUpdate(byte[] input, int off, int len) + { + final int blockSize = mode.currentBlockSize(); + final int count = (partLen + len) / blockSize; + final byte[] out = new byte[count * blockSize]; + try + { + engineUpdate(input, off, len, out, 0); + } + catch (ShortBufferException x) + { // should not happen + x.printStackTrace(System.err); + } + return out; + } + + // protected int + // engineUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff) + // throws ShortBufferException + // { + // int blockSize = mode.currentBlockSize(); + // int count = (partLen + inLen) / blockSize; + // if (count * blockSize > out.length - outOff) { + // throw new ShortBufferException(); + // } + // byte[] buf; + // if (partLen > 0 && count > 0) { + // buf = new byte[partLen + inLen]; + // System.arraycopy(partBlock, 0, buf, 0, partLen); + // if (in != null && inLen > 0) { + // System.arraycopy(in, inOff, buf, partLen, inLen); + // } + // partLen = 0; + // inOff = 0; + // } else { + // buf = in; + // } + // for (int i = 0; i < count; i++) { + // mode.update(buf, i * blockSize + inOff, out, i * blockSize + outOff); + // } + // if (inOff + inLen > count * blockSize) { + // partLen = (inOff + inLen) - (count * blockSize); + // System.arraycopy(in, count * blockSize, partBlock, 0, partLen); + // } + // return count * blockSize; + // } + + protected int engineUpdate(byte[] in, int inOff, int inLen, byte[] out, + int outOff) throws ShortBufferException + { + if (inLen == 0) + { // nothing to process + return 0; + } + final int blockSize = mode.currentBlockSize(); + final int blockCount = (partLen + inLen) / blockSize; + final int result = blockCount * blockSize; + if (result > out.length - outOff) + { + throw new ShortBufferException(); + } + if (blockCount == 0) + { // not enough bytes for even 1 block + System.arraycopy(in, inOff, partBlock, partLen, inLen); + partLen += inLen; + return 0; + } + final byte[] buf; + // we have enough bytes for at least 1 block + if (partLen == 0) + { // if no cached bytes use input + buf = in; + } + else + { // prefix input with cached bytes + buf = new byte[partLen + inLen]; + System.arraycopy(partBlock, 0, buf, 0, partLen); + if (in != null && inLen > 0) + { + System.arraycopy(in, inOff, buf, partLen, inLen); + } + inOff = 0; + } + for (int i = 0; i < blockCount; i++) + { // update blockCount * blockSize + mode.update(buf, inOff, out, outOff); + inOff += blockSize; + outOff += blockSize; + } + partLen += inLen - result; + if (partLen > 0) + { // cache remaining bytes from buf + System.arraycopy(buf, inOff, partBlock, 0, partLen); + } + return result; + } + + protected byte[] engineDoFinal(byte[] input, int off, int len) + throws IllegalBlockSizeException, BadPaddingException + { + final byte[] result; + final byte[] buf = engineUpdate(input, off, len); + if (pad != null) + { + switch (((Integer) attributes.get(IMode.STATE)).intValue()) + { + case IMode.ENCRYPTION: + byte[] padding = pad.pad(partBlock, 0, partLen); + byte[] buf2 = engineUpdate(padding, 0, padding.length); + result = new byte[buf.length + buf2.length]; + System.arraycopy(buf, 0, result, 0, buf.length); + System.arraycopy(buf2, 0, result, buf.length, buf2.length); + break; + case IMode.DECRYPTION: + int padLen; + try + { + padLen = pad.unpad(buf, 0, buf.length); + } + catch (WrongPaddingException wpe) + { + throw new BadPaddingException(wpe.getMessage()); + } + result = new byte[buf.length - padLen]; + System.arraycopy(buf, 0, result, 0, result.length); + break; + default: + throw new IllegalStateException(); + } + } + else + { + if (partLen > 0) + { + throw new IllegalBlockSizeException(partLen + " trailing bytes"); + } + result = buf; + } + + try + { + reset(); + } + catch (InvalidKeyException ike) + { + // Should not happen; if we initialized it with the current + // parameters before, we should be able to do it again. + throw new Error(ike); + } + return result; + } + + protected int engineDoFinal(byte[] in, int inOff, int inLen, byte[] out, + int outOff) throws BadPaddingException, + IllegalBlockSizeException, ShortBufferException + { + byte[] buf = engineDoFinal(in, inOff, inLen); + if (out.length + outOff < buf.length) + { + throw new ShortBufferException(); + } + System.arraycopy(buf, 0, out, outOff, buf.length); + return buf.length; + } + + private void reset() throws InvalidKeyException + { + mode.reset(); + mode.init(attributes); + if (pad != null) + { + pad.reset(); + pad.init(blockLen); + } + partBlock = new byte[blockLen]; + partLen = 0; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/DESSpi.java b/gnu/javax/crypto/jce/cipher/DESSpi.java new file mode 100644 index 000000000..801b2f138 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/DESSpi.java @@ -0,0 +1,59 @@ +/* DESSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the DES Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class DESSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public DESSpi() + { + super(Registry.DES_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/KhazadSpi.java b/gnu/javax/crypto/jce/cipher/KhazadSpi.java new file mode 100644 index 000000000..93c4ce37b --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/KhazadSpi.java @@ -0,0 +1,59 @@ +/* KhazadSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Khazad Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class KhazadSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public KhazadSpi() + { + super(Registry.KHAZAD_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/NullCipherSpi.java b/gnu/javax/crypto/jce/cipher/NullCipherSpi.java new file mode 100644 index 000000000..596edee63 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/NullCipherSpi.java @@ -0,0 +1,59 @@ +/* NullCipherSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Null cipher Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class NullCipherSpi extends CipherAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public NullCipherSpi() + { + super(Registry.NULL_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/PBES2.java b/gnu/javax/crypto/jce/cipher/PBES2.java new file mode 100644 index 000000000..0efb61e45 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/PBES2.java @@ -0,0 +1,1352 @@ +/* PBES2.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.javax.crypto.prng.IPBE; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; + +import javax.crypto.interfaces.PBEKey; +import javax.crypto.spec.SecretKeySpec; + +/** + *

.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public abstract class PBES2 extends CipherAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The HMac (PRF) algorithm name. */ + protected String macName; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected PBES2(String cipherName, int blockLen, String macName) + { + super(cipherName, blockLen); + this.macName = macName; + } + + protected PBES2(String cipherName, String macName) + { + super(cipherName); + this.macName = macName; + } + + // Instance methods + // ------------------------------------------------------------------------- + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + if (!(key instanceof PBEKey)) + throw new InvalidKeyException("not a PBE key"); + + super.engineInit(opmode, genkey((PBEKey) key), random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (!(key instanceof PBEKey)) + throw new InvalidKeyException("not a PBE key"); + + super.engineInit(opmode, genkey((PBEKey) key), params, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException + { + if (!(key instanceof PBEKey)) + throw new InvalidKeyException("not a PBE key"); + + super.engineInit(opmode, genkey((PBEKey) key), params, random); + } + + private SecretKeySpec genkey(PBEKey key) throws InvalidKeyException + { + IRandom kdf = PRNGFactory.getInstance("PBKDF2-" + macName); + if (kdf == null) + { + throw new IllegalArgumentException("no such KDF: PBKDF2-" + macName); + } + HashMap attrib = new HashMap(); + attrib.put(IPBE.ITERATION_COUNT, new Integer(key.getIterationCount())); + attrib.put(IPBE.PASSWORD, key.getPassword()); + attrib.put(IPBE.SALT, key.getSalt()); + try + { + kdf.init(attrib); + } + catch (IllegalArgumentException iae) + { + throw new InvalidKeyException(iae.toString()); + } + byte[] dk = new byte[mode.defaultKeySize()]; + try + { + kdf.nextBytes(dk, 0, dk.length); + } + catch (LimitReachedException shouldNotHappen) + { + // throw new Error(shouldNotHappen); + throw new Error(String.valueOf(shouldNotHappen)); + } + return new SecretKeySpec(dk, cipher.name()); + } + + // Inner classe(s) + // ========================================================================= + + public static class HMacSHA1 extends PBES2 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacSHA1(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA1"); + } + + public HMacSHA1(String cipher) + { + super(cipher, "HMAC-SHA1"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacSHA1 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacSHA1 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacSHA1 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacSHA1 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacSHA1 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacSHA1 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacSHA1 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacSHA1 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacSHA1 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacSHA1 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacMD5 extends PBES2 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacMD5(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD5"); + } + + public HMacMD5(String cipher) + { + super(cipher, "HMAC-MD5"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacMD5 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacMD5 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacMD5 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacMD5 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacMD5 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacMD5 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacMD5 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacMD5 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacMD5 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacMD5 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacMD2 extends PBES2 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacMD2(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD2"); + } + + public HMacMD2(String cipher) + { + super(cipher, "HMAC-MD2"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacMD2 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacMD2 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacMD2 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacMD2 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacMD2 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacMD2 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacMD2 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacMD2 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacMD2 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacMD2 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacMD4 extends PBES2 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacMD4(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD4"); + } + + public HMacMD4(String cipher) + { + super(cipher, "HMAC-MD4"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacMD4 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacMD4 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacMD4 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacMD4 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacMD4 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacMD4 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacMD4 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacMD4 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacMD4 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacMD4 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacHaval extends PBES2 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacHaval(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-HAVAL"); + } + + public HMacHaval(String cipher) + { + super(cipher, "HMAC-HAVAL"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacHaval + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacHaval + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacHaval + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacHaval + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacHaval + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacHaval + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacHaval + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacHaval + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacHaval + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacHaval + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacRipeMD128 extends PBES2 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacRipeMD128(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-RIPEMD128"); + } + + public HMacRipeMD128(String cipher) + { + super(cipher, "HMAC-RIPEMD128"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacRipeMD128 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacRipeMD128 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacRipeMD128 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacRipeMD128 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacRipeMD128 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacRipeMD128 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacRipeMD128 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacRipeMD128 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacRipeMD128 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacRipeMD128 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacRipeMD160 extends PBES2 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacRipeMD160(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-RIPEMD160"); + } + + public HMacRipeMD160(String cipher) + { + super(cipher, "HMAC-RIPEMD160"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacRipeMD160 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacRipeMD160 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacRipeMD160 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacRipeMD160 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacRipeMD160 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacRipeMD160 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacRipeMD160 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacRipeMD160 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacRipeMD160 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacRipeMD160 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacSHA256 extends PBES2 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacSHA256(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-256"); + } + + public HMacSHA256(String cipher) + { + super(cipher, "HMAC-SHA-256"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacSHA256 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacSHA256 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacSHA256 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacSHA256 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacSHA256 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacSHA256 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacSHA256 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacSHA256 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacSHA256 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacSHA256 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacSHA384 extends PBES2 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacSHA384(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-384"); + } + + public HMacSHA384(String cipher) + { + super(cipher, "HMAC-SHA-384"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacSHA384 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacSHA384 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacSHA384 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacSHA384 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacSHA384 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacSHA384 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacSHA384 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacSHA384 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacSHA384 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacSHA384 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacSHA512 extends PBES2 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacSHA512(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-512"); + } + + public HMacSHA512(String cipher) + { + super(cipher, "HMAC-SHA-512"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacSHA512 + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacSHA512 + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacSHA512 + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacSHA512 + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacSHA512 + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacSHA512 + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacSHA512 + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacSHA512 + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacSHA512 + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacSHA512 + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacTiger extends PBES2 + { + + // Constructor(s) + // --------------------------------------------------------------------- + + public HMacTiger(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-TIGER"); + } + + public HMacTiger(String cipher) + { + super(cipher, "HMAC-TIGER"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacTiger + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacTiger + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacTiger + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacTiger + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacTiger + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacTiger + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacTiger + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacTiger + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacTiger + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacTiger + { + public Twofish() + { + super("Twofish"); + } + } + } + + public static class HMacWhirlpool extends PBES2 + { + + // Constructor(s) + // ---------------------------------------------------------------------- + + public HMacWhirlpool(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-WHIRLPOOL"); + } + + public HMacWhirlpool(String cipher) + { + super(cipher, "HMAC-WHIRLPOOL"); + } + + // Inner classe(s) + // ====================================================================== + + public static class AES extends HMacWhirlpool + { + public AES() + { + super("AES"); + } + } + + public static class Anubis extends HMacWhirlpool + { + public Anubis() + { + super("Anubis"); + } + } + + public static class Blowfish extends HMacWhirlpool + { + public Blowfish() + { + super("Blowfish"); + } + } + + public static class Cast5 extends HMacWhirlpool + { + public Cast5() + { + super("Cast5"); + } + } + + public static class DES extends HMacWhirlpool + { + public DES() + { + super("DES"); + } + } + + public static class Khazad extends HMacWhirlpool + { + public Khazad() + { + super("Khazad"); + } + } + + public static class Serpent extends HMacWhirlpool + { + public Serpent() + { + super("Serpent"); + } + } + + public static class Square extends HMacWhirlpool + { + public Square() + { + super("Square"); + } + } + + public static class TripleDES extends HMacWhirlpool + { + public TripleDES() + { + super("TripleDES"); + } + } + + public static class Twofish extends HMacWhirlpool + { + public Twofish() + { + super("Twofish"); + } + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/RijndaelSpi.java b/gnu/javax/crypto/jce/cipher/RijndaelSpi.java new file mode 100644 index 000000000..0094b2a73 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/RijndaelSpi.java @@ -0,0 +1,59 @@ +/* RijndaelSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Rijndael Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class RijndaelSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public RijndaelSpi() + { + super(Registry.RIJNDAEL_CIPHER, 16); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/SerpentSpi.java b/gnu/javax/crypto/jce/cipher/SerpentSpi.java new file mode 100644 index 000000000..ec2e591fe --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/SerpentSpi.java @@ -0,0 +1,59 @@ +/* SerpentSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Serpent Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class SerpentSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public SerpentSpi() + { + super(Registry.SERPENT_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/SquareSpi.java b/gnu/javax/crypto/jce/cipher/SquareSpi.java new file mode 100644 index 000000000..c162d1616 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/SquareSpi.java @@ -0,0 +1,59 @@ +/* SquareSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Square Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class SquareSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public SquareSpi() + { + super(Registry.SQUARE_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/TripleDESSpi.java b/gnu/javax/crypto/jce/cipher/TripleDESSpi.java new file mode 100644 index 000000000..9ff9df97e --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/TripleDESSpi.java @@ -0,0 +1,59 @@ +/* TripleDESSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Triple-DES Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class TripleDESSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public TripleDESSpi() + { + super(Registry.TRIPLEDES_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/cipher/TwofishSpi.java b/gnu/javax/crypto/jce/cipher/TwofishSpi.java new file mode 100644 index 000000000..3a75a9858 --- /dev/null +++ b/gnu/javax/crypto/jce/cipher/TwofishSpi.java @@ -0,0 +1,59 @@ +/* TwofishSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.cipher; + +import gnu.java.security.Registry; + +/** + * The implementation of the Twofish Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class TwofishSpi extends CipherAdapter +{ + + // Constructors. + // -------------------------------------------------------------------- + + public TwofishSpi() + { + super(Registry.TWOFISH_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java new file mode 100644 index 000000000..e8d7788e8 --- /dev/null +++ b/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java @@ -0,0 +1,53 @@ +/* AnubisKeyGeneratorImpl.java -- Anubis key generator. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class AnubisKeyGeneratorImpl extends SecretKeyGeneratorImpl +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public AnubisKeyGeneratorImpl () + { + super (Registry.ANUBIS_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f9725eae0 --- /dev/null +++ b/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java @@ -0,0 +1,53 @@ +/* AnubisSecretKeyFactoryImpl.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class AnubisSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public AnubisSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java new file mode 100644 index 000000000..a0e687acd --- /dev/null +++ b/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java @@ -0,0 +1,53 @@ +/* BlowfishKeyGeneratorImpl.java -- Blowfish key generator. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class BlowfishKeyGeneratorImpl extends SecretKeyGeneratorImpl +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public BlowfishKeyGeneratorImpl () + { + super (Registry.BLOWFISH_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java new file mode 100644 index 000000000..4b3620bc1 --- /dev/null +++ b/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java @@ -0,0 +1,53 @@ +/* BlowfishSecretKeyFactoryImpl.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class BlowfishSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public BlowfishSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java new file mode 100644 index 000000000..18d26e67f --- /dev/null +++ b/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java @@ -0,0 +1,53 @@ +/* Cast5KeyGeneratorImpl.java -- CAST-5 key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class Cast5KeyGeneratorImpl extends SecretKeyGeneratorImpl +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public Cast5KeyGeneratorImpl () + { + super (Registry.CAST5_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java new file mode 100644 index 000000000..4bd31711e --- /dev/null +++ b/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java @@ -0,0 +1,53 @@ +/* Cast5SecretKeyFactoryImpl.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class Cast5SecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public Cast5SecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java new file mode 100644 index 000000000..19c54653a --- /dev/null +++ b/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java @@ -0,0 +1,73 @@ +/* DESKeyGeneratorImpl.java -- DES key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.DES; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +public class DESKeyGeneratorImpl extends SecretKeyGeneratorImpl +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public DESKeyGeneratorImpl () + { + super (Registry.DES_CIPHER); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected SecretKey engineGenerateKey () + { + if (!init) + throw new IllegalStateException ("not initialized"); + byte[] buf = new byte [currentKeySize]; + do + { + random.nextBytes (buf); + } + while (DES.isWeak (buf) || DES.isSemiWeak (buf)); + DES.adjustParity (buf, 0); + return new SecretKeySpec (buf, algorithm); + } +} diff --git a/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java new file mode 100644 index 000000000..e0f1c5860 --- /dev/null +++ b/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java @@ -0,0 +1,80 @@ +/* DESSecretKeyFactoryImpl.java -- DES key factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.SecretKeySpec; + +public class DESSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + + public DESSecretKeyFactoryImpl() + { + } + + protected SecretKey engineGenerateSecret (KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof DESKeySpec) + return new SecretKeySpec (((DESKeySpec) spec).getKey(), "DES"); + return super.engineGenerateSecret (spec); + } + + protected KeySpec engineGetKeySpec (SecretKey key, Class spec) + throws InvalidKeySpecException + { + if (spec.isAssignableFrom (DESKeySpec.class)) + try + { + return new DESKeySpec (key.getEncoded()); + } + catch (InvalidKeyException ike) + { + InvalidKeySpecException ikse = new InvalidKeySpecException + ("can't create DES key spec"); + ikse.initCause (ike); + throw ikse; + } + return super.engineGetKeySpec (key, spec); + } +} diff --git a/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java new file mode 100644 index 000000000..15e109940 --- /dev/null +++ b/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java @@ -0,0 +1,80 @@ +/* DESedeSecretKeyFactoryImpl.java -- DESede key factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; +import javax.crypto.spec.DESedeKeySpec; +import javax.crypto.spec.SecretKeySpec; + +public class DESedeSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + + public DESedeSecretKeyFactoryImpl() + { + } + + protected SecretKey engineGenerateSecret (KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof DESedeKeySpec) + return new SecretKeySpec (((DESedeKeySpec) spec).getKey(), "DESede"); + return super.engineGenerateSecret (spec); + } + + protected KeySpec engineGetKeySpec (SecretKey key, Class spec) + throws InvalidKeySpecException + { + if (spec.equals (DESedeKeySpec.class)) + try + { + return new DESedeKeySpec (key.getEncoded()); + } + catch (InvalidKeyException ike) + { + InvalidKeySpecException ikse = new InvalidKeySpecException + ("can't create DESede key spec"); + ikse.initCause (ike); + throw ikse; + } + return super.engineGetKeySpec (key, spec); + } +} diff --git a/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java new file mode 100644 index 000000000..c01391e44 --- /dev/null +++ b/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* KhazadKeyGeneratorImpl.java -- Khazad key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class KhazadKeyGeneratorImpl extends SecretKeyGeneratorImpl +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public KhazadKeyGeneratorImpl () + { + super (Registry.KHAZAD_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java new file mode 100644 index 000000000..c86e01110 --- /dev/null +++ b/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java @@ -0,0 +1,52 @@ +/* KhazadSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class KhazadSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public KhazadSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java new file mode 100644 index 000000000..535e573ad --- /dev/null +++ b/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* RijndaelKeyGeneratorImpl.java -- Rijndael key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class RijndaelKeyGeneratorImpl extends SecretKeyGeneratorImpl +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public RijndaelKeyGeneratorImpl () + { + super (Registry.RIJNDAEL_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java new file mode 100644 index 000000000..4aab584a2 --- /dev/null +++ b/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java @@ -0,0 +1,52 @@ +/* RijndaelSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class RijndaelSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public RijndaelSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java new file mode 100644 index 000000000..72defe1d7 --- /dev/null +++ b/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java @@ -0,0 +1,87 @@ +/* SecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public abstract class SecretKeyFactoryImpl extends SecretKeyFactorySpi +{ + + protected SecretKeyFactoryImpl() + { + } + + protected SecretKey engineGenerateSecret (KeySpec spec) + throws InvalidKeySpecException + { + if (spec instanceof SecretKeySpec) + return (SecretKey) spec; + throw new InvalidKeySpecException ("unknown key spec: " + + spec.getClass().getName()); + } + + protected KeySpec engineGetKeySpec (SecretKey key, Class spec) + throws InvalidKeySpecException + { + if (spec.equals (SecretKeySpec.class)) + { + if (key instanceof SecretKeySpec) + return (KeySpec) key; + else + return new SecretKeySpec (key.getEncoded(), key.getAlgorithm()); + } + throw new InvalidKeySpecException ("unsupported key spec: " + + spec.getName()); + } + + protected SecretKey engineTranslateKey (SecretKey key) + throws InvalidKeyException + { + if (!"RAW".equals (key.getFormat())) + throw new InvalidKeyException ("only raw keys are supported"); + + // SecretKeySpec is good enough for our purposes. + return new SecretKeySpec (key.getEncoded(), key.getAlgorithm()); + } +} diff --git a/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java new file mode 100644 index 000000000..0a6265573 --- /dev/null +++ b/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java @@ -0,0 +1,120 @@ +/* SecretKeyGeneratorImpl.java -- symmetric key pair generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.crypto.KeyGeneratorSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +public class SecretKeyGeneratorImpl extends KeyGeneratorSpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected final int defaultKeySize; + protected final List keySizes; + protected final String algorithm; + protected boolean init; + protected int currentKeySize; + protected SecureRandom random; + + // Constructors. + // ------------------------------------------------------------------------- + + protected SecretKeyGeneratorImpl (final String algorithm) + { + this.algorithm = algorithm; + IBlockCipher cipher = CipherFactory.getInstance (algorithm); + if (cipher == null) + throw new IllegalArgumentException ("no such cipher: "+algorithm); + defaultKeySize = cipher.defaultKeySize (); + keySizes = new LinkedList(); + for (Iterator it = cipher.keySizes (); it.hasNext (); ) + { + keySizes.add (it.next ()); + } + init = false; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected SecretKey engineGenerateKey () + { + if (!init) + throw new IllegalStateException ("not initialized"); + byte[] buf = new byte [currentKeySize]; + random.nextBytes (buf); + return new SecretKeySpec (buf, algorithm); + } + + protected void engineInit (AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + throw new InvalidAlgorithmParameterException (algorithm + + " does not support algorithm paramaters"); + } + + protected void engineInit (int keySize, SecureRandom random) + { + keySize >>>= 3; // Use bytes. + if (!keySizes.contains (new Integer (keySize))) + throw new InvalidParameterException ("unsupported key size: " + keySize); + currentKeySize = keySize; + this.random = random; + init = true; + } + + protected void engineInit (SecureRandom random) + { + engineInit (defaultKeySize << 3, random); + } +} diff --git a/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java new file mode 100644 index 000000000..766860a96 --- /dev/null +++ b/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* SerpentKeyGeneratorImpl.java -- Serpent key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class SerpentKeyGeneratorImpl extends SecretKeyGeneratorImpl +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public SerpentKeyGeneratorImpl () + { + super (Registry.SERPENT_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java new file mode 100644 index 000000000..6e80671fa --- /dev/null +++ b/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java @@ -0,0 +1,52 @@ +/* SerpentSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class SerpentSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public SerpentSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java new file mode 100644 index 000000000..4bfbeb668 --- /dev/null +++ b/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* SquareKeyGeneratorImpl.java -- Square key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class SquareKeyGeneratorImpl extends SecretKeyGeneratorImpl +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public SquareKeyGeneratorImpl () + { + super (Registry.SQUARE_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java new file mode 100644 index 000000000..d1d5d5514 --- /dev/null +++ b/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java @@ -0,0 +1,52 @@ +/* SquareSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class SquareSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public SquareSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java new file mode 100644 index 000000000..eb423fcd1 --- /dev/null +++ b/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* TripleDESKeyGeneratorImpl.java -- TripleDES key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class TripleDESKeyGeneratorImpl extends SecretKeyGeneratorImpl +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public TripleDESKeyGeneratorImpl () + { + super (Registry.TRIPLEDES_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java b/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java new file mode 100644 index 000000000..ae7e22fee --- /dev/null +++ b/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java @@ -0,0 +1,52 @@ +/* TwofishKeyGeneratorImpl.java -- Twofish key generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import gnu.java.security.Registry; + +public class TwofishKeyGeneratorImpl extends SecretKeyGeneratorImpl +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public TwofishKeyGeneratorImpl () + { + super (Registry.TWOFISH_CIPHER); + } +} diff --git a/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java b/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java new file mode 100644 index 000000000..e6ca80b63 --- /dev/null +++ b/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java @@ -0,0 +1,52 @@ +/* TwofishSecretKeyFactoryImpl.java -- simple byte array-wrapping factory. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.crypto.jce.key; + +import java.security.InvalidKeyException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactorySpi; +import javax.crypto.spec.SecretKeySpec; + +public class TwofishSecretKeyFactoryImpl extends SecretKeyFactoryImpl +{ + public TwofishSecretKeyFactoryImpl() + { + } +} diff --git a/gnu/javax/crypto/jce/keyring/GnuKeyring.java b/gnu/javax/crypto/jce/keyring/GnuKeyring.java new file mode 100644 index 000000000..d74d386b4 --- /dev/null +++ b/gnu/javax/crypto/jce/keyring/GnuKeyring.java @@ -0,0 +1,413 @@ +/* GnuKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.keyring; + +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.security.Key; +import java.security.KeyStoreSpi; +import java.security.KeyStoreException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +import java.util.Arrays; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import javax.crypto.SecretKey; + +import gnu.java.security.Registry; +import gnu.javax.crypto.keyring.IKeyring; +import gnu.javax.crypto.keyring.IPrivateKeyring; +import gnu.javax.crypto.keyring.IPublicKeyring; +import gnu.javax.crypto.keyring.GnuPrivateKeyring; +import gnu.javax.crypto.keyring.GnuPublicKeyring; +import gnu.javax.crypto.keyring.MalformedKeyringException; +import gnu.javax.crypto.keyring.PrimitiveEntry; + +public class GnuKeyring extends KeyStoreSpi +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + private boolean loaded; + + private IKeyring keyring; + + // Constructor. + // ------------------------------------------------------------------------ + + public GnuKeyring() + { + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public Enumeration engineAliases() + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return new Enumeration() + { + public boolean hasMoreElements() + { + return false; + } + + public Object nextElement() + { + throw new NoSuchElementException(); + } + }; + } + return keyring.aliases(); + } + + public boolean engineContainsAlias(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return false; + } + return keyring.containsAlias(alias); + } + + public void engineDeleteEntry(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring != null) + { + keyring.remove(alias); + } + } + + public Certificate engineGetCertificate(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return null; + } + if (!(keyring instanceof IPublicKeyring)) + { + throw new IllegalStateException("not a public keyring"); + } + return ((IPublicKeyring) keyring).getCertificate(alias); + } + + public String engineGetCertificateAlias(Certificate cert) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return null; + } + if (!(keyring instanceof IPublicKeyring)) + { + throw new IllegalStateException("not a public keyring"); + } + Enumeration aliases = keyring.aliases(); + while (aliases.hasMoreElements()) + { + String alias = (String) aliases.nextElement(); + Certificate cert2 = ((IPublicKeyring) keyring).getCertificate(alias); + if (cert.equals(cert2)) + { + return alias; + } + } + return null; + } + + public void engineSetCertificateEntry(String alias, Certificate cert) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + keyring = new GnuPublicKeyring("HMAC-SHA-1", 20); + } + if (!(keyring instanceof IPublicKeyring)) + { + throw new IllegalStateException("not a public keyring"); + } + ((IPublicKeyring) keyring).putCertificate(alias, cert); + } + + public Certificate[] engineGetCertificateChain(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return null; + } + if (!(keyring instanceof IPrivateKeyring)) + { + throw new IllegalStateException("not a private keyring"); + } + return ((IPrivateKeyring) keyring).getCertPath(alias); + } + + public Date engineGetCreationDate(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return null; + } + List entries = keyring.get(alias); + if (entries.size() == 0) + { + return null; + } + for (Iterator it = entries.iterator(); it.hasNext();) + { + Object o = it.next(); + if (o instanceof PrimitiveEntry) + { + return ((PrimitiveEntry) o).getCreationDate(); + } + } + return null; + } + + public Key engineGetKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return null; + } + if (!(keyring instanceof IPrivateKeyring)) + { + throw new IllegalStateException("not a private keyring"); + } + if (password == null) + { + if (((IPrivateKeyring) keyring).containsPublicKey(alias)) + { + return ((IPrivateKeyring) keyring).getPublicKey(alias); + } + } + if (((IPrivateKeyring) keyring).containsPrivateKey(alias)) + { + return ((IPrivateKeyring) keyring).getPrivateKey(alias, password); + } + return null; + } + + public void engineSetKeyEntry(String alias, Key key, char[] password, + Certificate[] chain) throws KeyStoreException + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + keyring = new GnuPrivateKeyring("HMAC-SHA-1", 20, "AES", "OFB", 16); + } + if (!(keyring instanceof IPrivateKeyring)) + { + throw new IllegalStateException("not a private keyring"); + } + if (key instanceof PublicKey) + { + ((IPrivateKeyring) keyring).putPublicKey(alias, (PublicKey) key); + return; + } + if (!(key instanceof PrivateKey) && !(key instanceof SecretKey)) + { + throw new KeyStoreException("cannot store keys of type " + + key.getClass().getName()); + } + try + { + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + ((IPrivateKeyring) keyring).putCertPath(alias, chain); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce.toString()); + } + ((IPrivateKeyring) keyring).putPrivateKey(alias, key, password); + } + + public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) + throws KeyStoreException + { + throw new KeyStoreException("method not supported"); + } + + public boolean engineIsCertificateEntry(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return false; + } + if (!(keyring instanceof IPublicKeyring)) + { + return false; + } + return ((IPublicKeyring) keyring).containsCertificate(alias); + } + + public boolean engineIsKeyEntry(String alias) + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return false; + } + if (!(keyring instanceof IPrivateKeyring)) + { + return false; + } + return ((IPrivateKeyring) keyring).containsPublicKey(alias) + || ((IPrivateKeyring) keyring).containsPrivateKey(alias); + } + + public void engineLoad(InputStream in, char[] password) throws IOException + { + if (in != null) + { + if (!in.markSupported()) + { + in = new BufferedInputStream(in); + } + in.mark(5); + for (int i = 0; i < 4; i++) + if (in.read() != Registry.GKR_MAGIC[i]) + throw new MalformedKeyringException("incorrect magic"); + int usage = in.read(); + in.reset(); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_IN, in); + attr.put(IKeyring.KEYRING_PASSWORD, password); + switch (usage) + { + case GnuPublicKeyring.USAGE: + keyring = new GnuPublicKeyring(); + break; + case GnuPrivateKeyring.USAGE: + keyring = new GnuPrivateKeyring(); + break; + default: + throw new MalformedKeyringException("unsupported ring usage: " + + Integer.toBinaryString(usage)); + } + keyring.load(attr); + } + loaded = true; + } + + public void engineStore(OutputStream out, char[] password) throws IOException + { + if (!loaded || keyring == null) + { + throw new IllegalStateException ("not loaded"); + } + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_OUT, out); + attr.put(IKeyring.KEYRING_PASSWORD, password); + keyring.store(attr); + } + + public int engineSize() + { + if (!loaded) + { + throw new IllegalStateException ("not loaded"); + } + if (keyring == null) + { + return 0; + } + return keyring.size(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacHavalSpi.java b/gnu/javax/crypto/jce/mac/HMacHavalSpi.java new file mode 100644 index 000000000..df1319cbf --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacHavalSpi.java @@ -0,0 +1,67 @@ +/* HMacHavalSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-HAVAL Service Provider Interface + * (SPI) Adapter. + * + * @version Revision: $ + */ +public class HMacHavalSpi extends MacAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public HMacHavalSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.HAVAL_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacMD2Spi.java b/gnu/javax/crypto/jce/mac/HMacMD2Spi.java new file mode 100644 index 000000000..343556db4 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacMD2Spi.java @@ -0,0 +1,59 @@ +/* HMacMD2Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-MD2 Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class HMacMD2Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacMD2Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD2_HASH); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacMD4Spi.java b/gnu/javax/crypto/jce/mac/HMacMD4Spi.java new file mode 100644 index 000000000..d00e257d4 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacMD4Spi.java @@ -0,0 +1,59 @@ +/* HMacMD4Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-MD4 Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class HMacMD4Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacMD4Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD4_HASH); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacMD5Spi.java b/gnu/javax/crypto/jce/mac/HMacMD5Spi.java new file mode 100644 index 000000000..fdf2ebf69 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacMD5Spi.java @@ -0,0 +1,59 @@ +/* HMacMD5Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-MD5 Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class HMacMD5Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacMD5Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD5_HASH); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java b/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java new file mode 100644 index 000000000..1fcd0f2bc --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java @@ -0,0 +1,59 @@ +/* HMacRipeMD128Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-RIPEMD-128 Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class HMacRipeMD128Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacRipeMD128Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD128_HASH); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java b/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java new file mode 100644 index 000000000..56854c214 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java @@ -0,0 +1,59 @@ +/* HMacRipeMD160Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-RIPEMD-160 Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class HMacRipeMD160Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacRipeMD160Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD160_HASH); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java b/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java new file mode 100644 index 000000000..8594e03f4 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java @@ -0,0 +1,59 @@ +/* HMacSHA160Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-SHA-160 Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class HMacSHA160Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacSHA160Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA160_HASH); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java b/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java new file mode 100644 index 000000000..4e147407d --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java @@ -0,0 +1,67 @@ +/* HMacSHA256Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; +import gnu.java.security.Registry; + +/** + *

The implementation of the HMAC-SHA-256 Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public final class HMacSHA256Spi extends MacAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ----------------------------------------------------------------------- + + public HMacSHA256Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA256_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java b/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java new file mode 100644 index 000000000..e909e9896 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java @@ -0,0 +1,67 @@ +/* HMacSHA384Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; +import gnu.java.security.Registry; + +/** + *

The implementation of the HMAC-SHA-384 Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class HMacSHA384Spi extends MacAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ----------------------------------------------------------------------- + + public HMacSHA384Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA384_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java b/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java new file mode 100644 index 000000000..8c4c041bb --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java @@ -0,0 +1,67 @@ +/* HMacSHA512Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; +import gnu.java.security.Registry; + +/** + *

The implementation of the HMAC-SHA-512 Service Provider Interface + * (SPI) adapter.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class HMacSHA512Spi extends MacAdapter +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ----------------------------------------------------------------------- + + public HMacSHA512Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA512_HASH); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacTigerSpi.java b/gnu/javax/crypto/jce/mac/HMacTigerSpi.java new file mode 100644 index 000000000..a42af05b7 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacTigerSpi.java @@ -0,0 +1,59 @@ +/* HMacTigerSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the Tiger Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class HMacTigerSpi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacTigerSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.TIGER_HASH); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java b/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java new file mode 100644 index 000000000..06ca3445c --- /dev/null +++ b/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java @@ -0,0 +1,59 @@ +/* HMacWhirlpoolSpi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the HMAC-Whirlpool Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class HMacWhirlpoolSpi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public HMacWhirlpoolSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.WHIRLPOOL_HASH); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/MacAdapter.java b/gnu/javax/crypto/jce/mac/MacAdapter.java new file mode 100644 index 000000000..073959a4e --- /dev/null +++ b/gnu/javax/crypto/jce/mac/MacAdapter.java @@ -0,0 +1,156 @@ +/* MacAdapter.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.Map; +import javax.crypto.MacSpi; + +/** + *

The implementation of a generic {@link javax.crypto.Mac} adapter class + * to wrap GNU Crypto MAC instances.

+ * + *

This class defines the Service Provider Interface (SPI) for + * the {@link javax.crypto.Mac} class, which provides the functionality of a + * message authentication code algorithm, such as the Hashed Message + * Authentication Code (HMAC) algorithms.

+ * + * @version $Revision: 1.2.4.1 $ + */ +class MacAdapter extends MacSpi implements Cloneable +{ + + // Constants and variables + // ----------------------------------------------------------------------- + + /** Our MAC instance. */ + protected IMac mac; + + /** Our MAC attributes. */ + protected Map attributes; + + // Constructor(s) + // ----------------------------------------------------------------------- + + /** + *

Creates a new Mac instance for the given name.

+ * + * @param name The name of the mac to create. + */ + protected MacAdapter(String name) + { + mac = MacFactory.getInstance(name); + attributes = new HashMap(); + } + + /** + * Private constructor for cloning purposes. + * + * @param mac a clone of the internal {@link IMac} instance. + * @param attributes a clone of the current {@link Map} of attributes. + */ + private MacAdapter(IMac mac, Map attributes) + { + super(); + + this.mac = mac; + this.attributes = attributes; + } + + // Class methods + // ----------------------------------------------------------------------- + + // Instance methods + // ----------------------------------------------------------------------- + + // Cloneable interface implementation ------------------------------------ + + public Object clone() throws CloneNotSupportedException + { + return new MacAdapter((IMac) mac.clone(), new HashMap(attributes)); + } + + // Instance methods implementing javax.crypto.MacSpi --------------------- + + protected byte[] engineDoFinal() + { + byte[] result = mac.digest(); + engineReset(); + return result; + } + + protected int engineGetMacLength() + { + return mac.macSize(); + } + + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (!key.getFormat().equalsIgnoreCase("RAW")) + { + throw new InvalidKeyException("unknown key format " + key.getFormat()); + } + attributes.put(IMac.MAC_KEY_MATERIAL, key.getEncoded()); + mac.reset(); + mac.init(attributes); + } + + protected void engineReset() + { + mac.reset(); + } + + protected void engineUpdate(byte b) + { + mac.update(b); + } + + protected void engineUpdate(byte[] in, int off, int len) + { + mac.update(in, off, len); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java b/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java new file mode 100644 index 000000000..4bfda4fd6 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java @@ -0,0 +1,53 @@ +/* OMacAnubisImpl.java -- OMAC-ANUBIS adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacAnubisImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacAnubisImpl() + { + super(Registry.OMAC_PREFIX + Registry.ANUBIS_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java b/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java new file mode 100644 index 000000000..8d168e57b --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java @@ -0,0 +1,53 @@ +/* OMacBlowfishImpl.java -- OMAC-BLOWFISH adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacBlowfishImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacBlowfishImpl() + { + super(Registry.OMAC_PREFIX + Registry.BLOWFISH_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacCast5Impl.java b/gnu/javax/crypto/jce/mac/OMacCast5Impl.java new file mode 100644 index 000000000..3385d116b --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacCast5Impl.java @@ -0,0 +1,53 @@ +/* OMacCast5Impl.java -- OMAC-CAST5 adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacCast5Impl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacCast5Impl() + { + super(Registry.OMAC_PREFIX + Registry.CAST5_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacDESImpl.java b/gnu/javax/crypto/jce/mac/OMacDESImpl.java new file mode 100644 index 000000000..3fb23bdef --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacDESImpl.java @@ -0,0 +1,53 @@ +/* OMacDESImpl.java -- OMAC-DES adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacDESImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacDESImpl() + { + super(Registry.OMAC_PREFIX + Registry.DES_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacImpl.java b/gnu/javax/crypto/jce/mac/OMacImpl.java new file mode 100644 index 000000000..f91902ae5 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacImpl.java @@ -0,0 +1,137 @@ +/* OMacImpl.java -- OMAC adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; +import javax.crypto.MacSpi; + +public abstract class OMacImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + protected OMacImpl(String name) + { + super(Registry.OMAC_PREFIX + name); + } + + // Inner classes. + // ------------------------------------------------------------------------- + + public class Anubis extends OMacImpl + { + public Anubis() + { + super(Registry.ANUBIS_CIPHER); + } + } + + public class Blowfish extends OMacImpl + { + public Blowfish() + { + super(Registry.BLOWFISH_CIPHER); + } + } + + public class Cast5 extends OMacImpl + { + public Cast5() + { + super(Registry.CAST5_CIPHER); + } + } + + public class DES extends OMacImpl + { + public DES() + { + super(Registry.DES_CIPHER); + } + } + + public class Khazad extends OMacImpl + { + public Khazad() + { + super(Registry.KHAZAD_CIPHER); + } + } + + public class Rijndael extends OMacImpl + { + public Rijndael() + { + super(Registry.RIJNDAEL_CIPHER); + } + } + + public class Serpent extends OMacImpl + { + public Serpent() + { + super(Registry.SERPENT_CIPHER); + } + } + + public class Square extends OMacImpl + { + public Square() + { + super(Registry.SQUARE_CIPHER); + } + } + + public class TripleDES extends OMacImpl + { + public TripleDES() + { + super(Registry.TRIPLEDES_CIPHER); + } + } + + public class Twofish extends OMacImpl + { + public Twofish() + { + super(Registry.TWOFISH_CIPHER); + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java b/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java new file mode 100644 index 000000000..82c047c25 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java @@ -0,0 +1,53 @@ +/* OMacKhazadImpl.java -- OMAC-KHAZAD adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacKhazadImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacKhazadImpl() + { + super(Registry.OMAC_PREFIX + Registry.KHAZAD_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java b/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java new file mode 100644 index 000000000..47d3f6aae --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java @@ -0,0 +1,53 @@ +/* OMacRijndaelImpl.java -- OMAC-RIJNDAEL adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacRijndaelImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacRijndaelImpl() + { + super(Registry.OMAC_PREFIX + Registry.RIJNDAEL_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java b/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java new file mode 100644 index 000000000..bec2c1f5c --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java @@ -0,0 +1,53 @@ +/* OMacSerpentImpl.java -- OMAC-SERPENT adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacSerpentImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacSerpentImpl() + { + super(Registry.OMAC_PREFIX + Registry.SERPENT_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacSquareImpl.java b/gnu/javax/crypto/jce/mac/OMacSquareImpl.java new file mode 100644 index 000000000..0442b7caf --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacSquareImpl.java @@ -0,0 +1,53 @@ +/* OMacSquareImpl.java -- OMAC-SQUARE adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacSquareImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacSquareImpl() + { + super(Registry.OMAC_PREFIX + Registry.SQUARE_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java b/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java new file mode 100644 index 000000000..0defdd1fd --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java @@ -0,0 +1,53 @@ +/* OMacTripleDESImpl.java -- OMAC-TRIPLEDES adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacTripleDESImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacTripleDESImpl() + { + super(Registry.OMAC_PREFIX + Registry.TRIPLEDES_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java b/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java new file mode 100644 index 000000000..a12f9f30e --- /dev/null +++ b/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java @@ -0,0 +1,53 @@ +/* OMacTwofishImpl.java -- OMAC-TWOFISH adapter. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +public class OMacTwofishImpl extends MacAdapter +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public OMacTwofishImpl() + { + super(Registry.OMAC_PREFIX + Registry.TWOFISH_CIPHER); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/TMMH16Spi.java b/gnu/javax/crypto/jce/mac/TMMH16Spi.java new file mode 100644 index 000000000..defd70c67 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/TMMH16Spi.java @@ -0,0 +1,91 @@ +/* TMMH16Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.TMMH16; +import gnu.javax.crypto.jce.spec.TMMHParameterSpec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; + +/** + * The implementation of the TMMH16 Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class TMMH16Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public TMMH16Spi() + { + super(Registry.TMMH16); + } + + // Instance methods overriding MacAdapter. + // ----------------------------------------------------------------------- + + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (!(params instanceof TMMHParameterSpec)) + { + throw new InvalidAlgorithmParameterException(); + } + TMMHParameterSpec spec = (TMMHParameterSpec) params; + attributes.put(TMMH16.TAG_LENGTH, spec.getTagLength()); + attributes.put(TMMH16.KEYSTREAM, spec.getKeystream()); + attributes.put(TMMH16.PREFIX, spec.getPrefix()); + try + { + mac.reset(); + mac.init(attributes); + } + catch (IllegalArgumentException iae) + { + throw new InvalidAlgorithmParameterException(iae.getMessage()); + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/UHash32Spi.java b/gnu/javax/crypto/jce/mac/UHash32Spi.java new file mode 100644 index 000000000..bd68c5291 --- /dev/null +++ b/gnu/javax/crypto/jce/mac/UHash32Spi.java @@ -0,0 +1,59 @@ +/* UHash32Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; + +/** + * The implementation of the UHash-32 Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class UHash32Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public UHash32Spi() + { + super(Registry.UHASH32); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/mac/UMac32Spi.java b/gnu/javax/crypto/jce/mac/UMac32Spi.java new file mode 100644 index 000000000..77de29b9c --- /dev/null +++ b/gnu/javax/crypto/jce/mac/UMac32Spi.java @@ -0,0 +1,91 @@ +/* UMac32Spi.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.mac; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.UMac32; +import gnu.javax.crypto.jce.spec.UMac32ParameterSpec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; + +/** + * The implementation of the UMAC-32 Service Provider Interface + * (SPI) adapter. + * + * @version $Revision: 1.1.4.1 $ + */ +public final class UMac32Spi extends MacAdapter +{ + + // Constructors. + // ----------------------------------------------------------------------- + + public UMac32Spi() + { + super(Registry.UMAC32); + } + + // Instance methods overriding MacAdapter. + // ----------------------------------------------------------------------- + + protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (!(params instanceof UMac32ParameterSpec)) + { + throw new InvalidAlgorithmParameterException(); + } + if (params != null) + { + attributes.put(UMac32.NONCE_MATERIAL, + ((UMac32ParameterSpec) params).getNonce()); + } + try + { + super.engineInit(key, null); + } + catch (IllegalArgumentException iae) + { + throw new InvalidAlgorithmParameterException(iae.getMessage()); + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/params/BlockCipherParameters.java b/gnu/javax/crypto/jce/params/BlockCipherParameters.java new file mode 100644 index 000000000..bae7cbf88 --- /dev/null +++ b/gnu/javax/crypto/jce/params/BlockCipherParameters.java @@ -0,0 +1,209 @@ +/* BlockCipherParameters.java -- + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.params; + +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; + +import java.io.IOException; +import java.math.BigInteger; + +import java.security.AlgorithmParametersSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +/** + * An implementation of algorithm parameters for the GNU Crypto block + * ciphers. This encompasses the cipher's block size, its key size, and + * an optional initialization vector (IV). + */ +public class BlockCipherParameters extends AlgorithmParametersSpi +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** + * The underlying block cipher specification. + */ + protected BlockCipherParameterSpec cipherSpec; + + private static final String DEFAULT_FORMAT = "ASN.1"; + + // Instance methods implementing AlgorithmParametersSpi. + // ----------------------------------------------------------------------- + + /** + * Return these parameters encoded in ASN.1 (DER). + * + *

For GNU Crypto block ciphers we will define these parameters as + * + *

+ *
BlockCipherParameters ::= SEQUENCE {
+   *   blockSize            INTEGER,
+   *   keySize              INTEGER,
+   *   initializationVector OCTET STRING OPTIONAL }
+ *
+ * + * @return The parameters, encoded an an ASN.1 DER sequence. + * @throws java.io.IOException If encoding these parameters fails. + */ + protected byte[] engineGetEncoded() throws IOException + { + return engineGetEncoded(DEFAULT_FORMAT); + } + + protected byte[] engineGetEncoded(String format) throws IOException + { + if (!format.equalsIgnoreCase(DEFAULT_FORMAT) + && !format.equalsIgnoreCase("asn1")) + { + throw new IOException("unknown format \"" + format + "\""); + } + // This is probably a bad idea. + /* + int len = 12 + ((cipherSpec.getIV() != null) + ? cipherSpec.getIV().length + 2 : 0); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(0x30); + out.write(len); + out.write(0x02); + out.write(4); + out.write(cipherSpec.getBlockSize() >>> 24 & 0xff); + out.write(cipherSpec.getBlockSize() >>> 16 & 0xff); + out.write(cipherSpec.getBlockSize() >>> 8 & 0xff); + out.write(cipherSpec.getBlockSize() & 0xff); + out.write(0x02); + out.write(4); + out.write(cipherSpec.getKeySize() >>> 24 & 0xff); + out.write(cipherSpec.getKeySize() >>> 16 & 0xff); + out.write(cipherSpec.getKeySize() >>> 8 & 0xff); + out.write(cipherSpec.getKeySize() & 0xff); + if (cipherSpec.getIV() != null) { + out.write(0x04); + len = cipherSpec.getIV().length; + out.write(len & 0xff); + out.write(cipherSpec.getIV()); + } + out.write(0); out.write(0); + return out.toByteArray();*/ + DERWriter writer = new DERWriter(); + return writer.joinarrays( + writer.writeBigInteger(BigInteger.valueOf(cipherSpec.getBlockSize())), + writer.writeBigInteger(BigInteger.valueOf(cipherSpec.getKeySize())), + (cipherSpec.getIV() != null) ? writer.writeBigInteger(new BigInteger( + cipherSpec.getIV())) + : new byte[0]); + } + + protected void engineInit(AlgorithmParameterSpec spec) + throws InvalidParameterSpecException + { + if (spec instanceof BlockCipherParameterSpec) + { + cipherSpec = (BlockCipherParameterSpec) spec; + } + else + { + throw new InvalidParameterSpecException(); + } + } + + protected void engineInit(byte[] encoded, String format) throws IOException + { + if (!format.equalsIgnoreCase(DEFAULT_FORMAT) + && !format.equalsIgnoreCase("ASN1")) + { + throw new IOException("invalid format: only accepts ASN.1"); + } + engineInit(encoded); + } + + protected void engineInit(byte[] encoded) throws IOException + { + // This is probably an equally bad idea. + /*if (encoded[0] != 0x30) { + throw new IOException("malformed ASN.1 sequence"); + } + if (encoded[2] != 0x02 || encoded[3] != 4) { + throw new IOException("malformed ASN.1 sequence"); + } + int blockSize = encoded[4] << 24 | encoded[5] << 16 + | encoded[6] << 8 | encoded[7]; + if (encoded[8] != 0x02 || encoded[9] != 4) { + throw new IOException("malformed ASN.1 sequence"); + } + int keySize = encoded[10] << 24 | encoded[11] << 16 + | encoded[12] << 8 | encoded[13]; + if (encoded[14] == 0x04) { + int len = encoded[15] & 0xff; + byte[] iv = new byte[len]; + System.arraycopy(encoded, 16, iv, 0, len); + cipherSpec = new BlockCipherParameterSpec(iv, blockSize, keySize); + } else if (encoded[14] == 0) { + cipherSpec = new BlockCipherParameterSpec(blockSize, keySize); + } else { + throw new IOException("malformed ASN.1 sequence"); + }*/ + DERReader reader = new DERReader(encoded); + int bs = reader.getBigInteger().intValue(); + int ks = reader.getBigInteger().intValue(); + byte[] iv = null; + if (reader.hasMorePrimitives()) + { + iv = reader.getBigInteger().toByteArray(); + } + cipherSpec = new BlockCipherParameterSpec(iv, bs, ks); + System.out.println(cipherSpec); + } + + protected AlgorithmParameterSpec engineGetParameterSpec(Class c) + throws InvalidParameterSpecException + { + if (c.isInstance(cipherSpec)) + { + return cipherSpec; + } + throw new InvalidParameterSpecException(); + } + + protected String engineToString() + { + return cipherSpec.toString(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/params/DEREncodingException.java b/gnu/javax/crypto/jce/params/DEREncodingException.java new file mode 100644 index 000000000..ddfa6e1de --- /dev/null +++ b/gnu/javax/crypto/jce/params/DEREncodingException.java @@ -0,0 +1,53 @@ +/* DEREncodingException.java -- + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.params; + +class DEREncodingException extends java.io.IOException +{ + + public DEREncodingException() + { + super(); + } + + public DEREncodingException(String msg) + { + super(msg); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/params/DERReader.java b/gnu/javax/crypto/jce/params/DERReader.java new file mode 100644 index 000000000..f61423255 --- /dev/null +++ b/gnu/javax/crypto/jce/params/DERReader.java @@ -0,0 +1,160 @@ +/* DERReader.java -- + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.params; + +import java.math.BigInteger; + +class DERReader +{ + byte source[]; + + int pos; + + static final int UNIVERSAL = 1; + + static final int APPLICATION = 2; + + static final int CONTEXT_SPECIFIC = 3; + + static final int PRIVATE = 4; + + public DERReader() + { + source = null; + pos = 0; + } + + public DERReader(byte source[]) + { + init(source); + } + + public void init(String source) + { + init(source.getBytes()); + } + + public void init(byte source[]) + { + this.source = source; + pos = 0; + } + + public boolean hasMorePrimitives() + { + return pos < source.length; + } + + public BigInteger getBigInteger() throws DEREncodingException + { + return new BigInteger(getPrimitive()); + } + + //Reads Primitive, definite-length method + private byte[] getPrimitive() throws DEREncodingException + { + int tmp = pos; + + //Read Identifier + byte identifier = source[tmp++]; + if ((0x20 & identifier) != 0) + throw new DEREncodingException(); + int type = translateLeadIdentifierByte(identifier); + //System.out.println("Type: " + type); + + //get tag + int tag = (0x1f & identifier); + //if( tag == 0x1f) + // tag = getIdentifier(tmp); + //System.out.println("Tag: " + tag); + + //get length + byte len = source[tmp]; //may be length of length parameter + long length = 0x7f & len; + int i; + if ((0x80 & len) != 0) + { + //System.out.println("Extra Long Length"); + len &= 0x7f; + //System.out.println("Length of Length: " + len); + //get length here + length = 0; + for (i = 0; i < len; i++) + { + tmp++; + length <<= 8; + length += (source[tmp] < 0) ? (256 + source[tmp]) : source[tmp]; + //System.out.println("Length of Length: " + length); + } + tmp++; + } + else + tmp++; + + /*System.out.println("Position: " + tmp); + System.out.println("Length: " + length); + for( i = 0; i < 10; i++) + System.out.print(source[tmp + i] + " "); + System.out.println();*/ + + byte tmpb[] = new byte[(int) length]; + System.arraycopy(source, tmp, tmpb, 0, (int) length); + pos = (int) (tmp + length); + return tmpb; + } + + private int translateLeadIdentifierByte(byte b) + { + if ((0x3f & b) == b) + return UNIVERSAL; + else if ((0x7f & b) == b) + return APPLICATION; + else if ((0xbf & b) == b) + return CONTEXT_SPECIFIC; + else + return PRIVATE; + } + + private int getIdentifier(int tpos) + { + while ((0x80 & source[tpos]) != 0) + tpos++; + return tpos; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/params/DERWriter.java b/gnu/javax/crypto/jce/params/DERWriter.java new file mode 100644 index 000000000..876c2cd6c --- /dev/null +++ b/gnu/javax/crypto/jce/params/DERWriter.java @@ -0,0 +1,154 @@ +/* DERWriter.java -- + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.params; + +import java.math.BigInteger; + +class DERWriter +{ + static final int UNIVERSAL = 1; + + static final int APPLICATION = 2; + + static final int CONTEXT_SPECIFIC = 3; + + static final int PRIVATE = 4; + + public DERWriter() + { + } + + public byte[] writeBigInteger(BigInteger i) + { + return writePrimitive(0x02, UNIVERSAL, + (int) Math.ceil((double) i.bitLength() / 8), + i.toByteArray()); + } + + private byte[] writePrimitive(int identifier, int identifierencoding, + int length, byte contents[]) + { + return joinarrays(generateIdentifier(identifier, identifierencoding), + generateLength(length), contents); + } + + public byte[] joinarrays(byte a[], byte b[]) + { + byte d[] = new byte[a.length + b.length]; + System.arraycopy(a, 0, d, 0, a.length); + System.arraycopy(b, 0, d, a.length, b.length); + return d; + } + + public byte[] joinarrays(byte a[], byte b[], byte c[]) + { + byte d[] = new byte[a.length + b.length + c.length]; + System.arraycopy(a, 0, d, 0, a.length); + System.arraycopy(b, 0, d, a.length, b.length); + System.arraycopy(c, 0, d, a.length + b.length, c.length); + return d; + } + + private byte[] generateIdentifier(int identifier, int identifierencoding) + { + byte b[]; + if (identifier > 31) + { + int count = (int) (Math.log(identifier) / Math.log(256)); + b = new byte[count + 1]; + b[0] = (byte) (translateLeadIdentifierByte(identifierencoding) | 0x1f); + int i; + for (i = 1; i < (count + 1); i++) + { + b[i] = (byte) (0x7f & (identifier >> (7 * (count - i)))); + b[i] |= 0x80; + } + b[i - 1] ^= 0x80; + //System.out.println("Identifier1: " + b[0]); + return b; + } + else + { + b = new byte[1]; + b[0] = (byte) ((translateLeadIdentifierByte(identifierencoding) | (byte) (identifier & 0x1f)) & 0xdf); + //System.out.println("Identifier2: " + b[0]); + return b; + } + } + + private byte translateLeadIdentifierByte(int b) + { + if (b == UNIVERSAL) + return (byte) 0x3f; + else if (b == APPLICATION) + return (byte) 0x7f; + else if (b == CONTEXT_SPECIFIC) + return (byte) 0xbf; + else + return (byte) 0xC0; + } + + private byte[] generateLength(int length) + { + byte b[]; + if (length > 127) + { + int count = (int) Math.ceil(Math.log(length) / Math.log(256)); + //System.out.println("Length byte count: " + count); + b = new byte[count + 1]; + b[0] = (byte) ((count & 0x7f) | 0x80); + for (int i = 1; i < (count + 1); i++) + { + b[i] = (byte) (length >>> (8 * (count - i))); + //System.out.println("Length1 byte1: " + (length >>> (8 * ( count - i) ))); + //System.out.println("Length1 byte2: " + b[i]); + } + + //System.out.println("Length1: " + length); + return b; + } + else + { + b = new byte[1]; + b[0] = (byte) (length & 0x7f); + //System.out.println("Length2: " + length); + return b; + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java b/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java new file mode 100644 index 000000000..0c071561b --- /dev/null +++ b/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java @@ -0,0 +1,120 @@ +/* ARCFourRandomSpi.java -- + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.prng; + +import gnu.java.security.Registry; +import gnu.javax.crypto.prng.ARCFour; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.security.SecureRandomSpi; +import java.util.HashMap; + +/** + * Implementation of the Service Provider Interface (SPI) + * for the ARCFOUR keystream generator. + */ +public class ARCFourRandomSpi extends SecureRandomSpi +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Our underlying prng instance. */ + private IRandom adaptee; + + /** Have we been initialized? */ + private boolean virgin; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Default 0-arguments constructor. + */ + public ARCFourRandomSpi() + { + super(); + adaptee = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG); + virgin = true; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.SecureRandomSpi interface implementation ------------------ + + public byte[] engineGenerateSeed(int numBytes) + { + if (numBytes < 1) + { + return new byte[0]; + } + byte[] result = new byte[numBytes]; + this.engineNextBytes(result); + return result; + } + + public void engineNextBytes(byte[] bytes) + { + if (virgin) + { + this.engineSetSeed(new byte[0]); + } + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + } + catch (LimitReachedException ignored) + { + } + } + + public void engineSetSeed(byte[] seed) + { + HashMap attributes = new HashMap(); + attributes.put(ARCFour.ARCFOUR_KEY_MATERIAL, seed); + adaptee.init(attributes); + virgin = false; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/prng/CSPRNGSpi.java b/gnu/javax/crypto/jce/prng/CSPRNGSpi.java new file mode 100644 index 000000000..c0aa015b0 --- /dev/null +++ b/gnu/javax/crypto/jce/prng/CSPRNGSpi.java @@ -0,0 +1,114 @@ +/* CSPRNGSpi.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.prng; + +import gnu.java.security.Registry; +import gnu.javax.crypto.prng.CSPRNG; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +import java.net.MalformedURLException; +import java.security.SecureRandomSpi; + +/** + * The implementation of the continuously-seeded SecureRandom + * Service Provider Interface (SPI) adapter.

+ */ +public class CSPRNGSpi extends SecureRandomSpi +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private final IRandom adaptee; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public CSPRNGSpi() throws ClassNotFoundException, MalformedURLException, + NumberFormatException + { + super(); + + adaptee = CSPRNG.getSystemInstance(); + } + + // Instance methods + // ------------------------------------------------------------------------- + + protected byte[] engineGenerateSeed(final int count) + { + if (count < 0) + { + throw new IllegalArgumentException("count must be nonnegative"); + } + byte[] buf = new byte[count]; + if (count == 0) + { + return buf; + } + engineNextBytes(buf); + return buf; + } + + protected void engineNextBytes(final byte[] buffer) + { + if (buffer == null) + { + throw new NullPointerException(); + } + try + { + adaptee.nextBytes(buffer, 0, buffer.length); + } + catch (LimitReachedException lre) + { + throw new RuntimeException("random-number generator has been exhausted"); + } + } + + protected void engineSetSeed(final byte[] seed) + { + if (seed == null) + { + throw new NullPointerException(); + } + adaptee.addRandomBytes(seed, 0, seed.length); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/prng/FortunaImpl.java b/gnu/javax/crypto/jce/prng/FortunaImpl.java new file mode 100644 index 000000000..7006bbbad --- /dev/null +++ b/gnu/javax/crypto/jce/prng/FortunaImpl.java @@ -0,0 +1,85 @@ +/* FortunaImpl.java -- Fortuna SecureRandom adapter. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.prng; + +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.Fortuna; +import java.security.SecureRandomSpi; +import java.util.Collections; + +public final class FortunaImpl extends SecureRandomSpi +{ + private final Fortuna adaptee; + + public FortunaImpl () + { + adaptee = new Fortuna (); + adaptee.init (Collections.singletonMap (Fortuna.SEED, new byte[0])); + } + + protected void engineSetSeed (byte[] seed) + { + synchronized (adaptee) + { + adaptee.addRandomBytes (seed); + } + } + + protected void engineNextBytes(byte[] buffer) + { + synchronized (adaptee) + { + try + { + adaptee.nextBytes (buffer); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error (shouldNotHappen); + } + } + } + + protected byte[] engineGenerateSeed (int numbytes) + { + byte[] seed = new byte[numbytes]; + engineNextBytes (seed); + return seed; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/prng/ICMRandomSpi.java b/gnu/javax/crypto/jce/prng/ICMRandomSpi.java new file mode 100644 index 000000000..d04b782f9 --- /dev/null +++ b/gnu/javax/crypto/jce/prng/ICMRandomSpi.java @@ -0,0 +1,260 @@ +/* ICMRandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.prng; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.ICMGenerator; +import gnu.java.security.prng.LimitReachedException; + +import java.io.PrintWriter; +import java.math.BigInteger; +import java.security.SecureRandomSpi; +import java.util.HashMap; +import java.util.Random; + +/** + *

An Adapter class around {@link ICMGenerator} to allow using this + * algorithm as a JCE {@link java.security.SecureRandom}.

+ */ +public class ICMRandomSpi extends SecureRandomSpi +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "ICMRandomSpi"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 0; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Class-wide prng to generate random material for the underlying prng.*/ + private static final ICMGenerator prng; // blank final + static + { + prng = new ICMGenerator(); + resetLocalPRNG(); + } + + // error messages + private static final String MSG = "Exception while setting up an " + + Registry.ICM_PRNG + " SPI: "; + + private static final String RETRY = "Retry..."; + + private static final String LIMIT_REACHED_MSG = "Limit reached: "; + + private static final String RESEED = "Re-seed..."; + + /** Our underlying prng instance. */ + private ICMGenerator adaptee = new ICMGenerator(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + private static void resetLocalPRNG() + { + if (DEBUG && debuglevel > 8) + debug(">>> resetLocalPRNG()"); + HashMap attributes = new HashMap(); + attributes.put(ICMGenerator.CIPHER, Registry.AES_CIPHER); + byte[] key = new byte[128 / 8]; // AES default key size + Random rand = new Random(System.currentTimeMillis()); + rand.nextBytes(key); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + int aesBlockSize = 128 / 8; // AES block size in bytes + byte[] offset = new byte[aesBlockSize]; + rand.nextBytes(offset); + attributes.put(ICMGenerator.OFFSET, offset); + int ndxLen = 0; // the segment length + // choose a random value between 1 and aesBlockSize / 2 + int limit = aesBlockSize / 2; + while (ndxLen < 1 || ndxLen > limit) + { + ndxLen = rand.nextInt(limit + 1); + } + attributes.put(ICMGenerator.SEGMENT_INDEX_LENGTH, new Integer(ndxLen)); + byte[] index = new byte[ndxLen]; + rand.nextBytes(index); + attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index)); + + prng.setup(attributes); + if (DEBUG && debuglevel > 8) + debug("<<< resetLocalPRNG()"); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.SecureRandomSpi interface implementation ------------------ + + public byte[] engineGenerateSeed(int numBytes) + { + if (DEBUG && debuglevel > 8) + debug(">>> engineGenerateSeed()"); + if (numBytes < 1) + { + if (DEBUG && debuglevel > 8) + debug("<<< engineGenerateSeed()"); + return new byte[0]; + } + byte[] result = new byte[numBytes]; + this.engineNextBytes(result); + if (DEBUG && debuglevel > 8) + debug("<<< engineGenerateSeed()"); + return result; + } + + public void engineNextBytes(byte[] bytes) + { + if (DEBUG && debuglevel > 8) + debug(">>> engineNextBytes()"); + if (!adaptee.isInitialised()) + { + this.engineSetSeed(new byte[0]); + } + + while (true) + { + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + break; + } + catch (LimitReachedException x) + { // reseed the generator + if (DEBUG) + { + debug(LIMIT_REACHED_MSG + String.valueOf(x)); + x.printStackTrace(err); + debug(RESEED); + } + resetLocalPRNG(); + } + } + if (DEBUG && debuglevel > 8) + debug("<<< engineNextBytes()"); + } + + public void engineSetSeed(byte[] seed) + { + if (DEBUG && debuglevel > 8) + debug(">>> engineSetSeed()"); + // compute the total number of random bytes required to setup adaptee + int materialLength = 0; + materialLength += 16; // key material size + materialLength += 16; // offset size + materialLength += 8; // index size == half of an AES block + byte[] material = new byte[materialLength]; + + // use as much as possible bytes from the seed + int materialOffset = 0; + int materialLeft = material.length; + if (seed.length > 0) + { // copy some bytes into key and update indices + int lenToCopy = Math.min(materialLength, seed.length); + System.arraycopy(seed, 0, material, 0, lenToCopy); + materialOffset += lenToCopy; + materialLeft -= lenToCopy; + } + if (materialOffset > 0) + { // generate the rest + while (true) + { + try + { + prng.nextBytes(material, materialOffset, materialLeft); + break; + } + catch (IllegalStateException x) + { // should not happen + throw new InternalError(MSG + String.valueOf(x)); + } + catch (LimitReachedException x) + { + if (DEBUG) + { + debug(MSG + String.valueOf(x)); + debug(RETRY); + } + } + } + } + + // setup the underlying adaptee instance + HashMap attributes = new HashMap(); + + // use AES cipher with 128-bit block size + attributes.put(ICMGenerator.CIPHER, Registry.AES_CIPHER); + // use an index the size of quarter of an AES block + attributes.put(ICMGenerator.SEGMENT_INDEX_LENGTH, new Integer(4)); + // specify the key + byte[] key = new byte[16]; + System.arraycopy(material, 0, key, 0, 16); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + // specify the offset + byte[] offset = new byte[16]; + System.arraycopy(material, 16, offset, 0, 16); + attributes.put(ICMGenerator.OFFSET, offset); + // specify the index + byte[] index = new byte[8]; + System.arraycopy(material, 32, index, 0, 8); + attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index)); + + adaptee.init(attributes); + if (DEBUG && debuglevel > 8) + debug("<<< engineSetSeed()"); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/prng/UMacRandomSpi.java b/gnu/javax/crypto/jce/prng/UMacRandomSpi.java new file mode 100644 index 000000000..7dad68b2f --- /dev/null +++ b/gnu/javax/crypto/jce/prng/UMacRandomSpi.java @@ -0,0 +1,207 @@ +/* UMacRandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.prng; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.io.PrintWriter; +import java.security.SecureRandomSpi; +import java.util.HashMap; +import java.util.Random; + +/** + *

An Adapter class around {@link UMacGenerator} to allow using this + * algorithm as a JCE {@link java.security.SecureRandom}.

+ */ +public class UMacRandomSpi extends SecureRandomSpi +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "UMacRandomSpi"; + + private static final boolean DEBUG = false; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Class-wide prng to generate random material for the underlying prng.*/ + private static final UMacGenerator prng; // blank final + static + { + prng = new UMacGenerator(); + resetLocalPRNG(); + } + + // error messages + private static final String MSG = "Exception while setting up a " + + Registry.UMAC_PRNG + " SPI: "; + + private static final String RETRY = "Retry..."; + + /** Our underlying prng instance. */ + private UMacGenerator adaptee = new UMacGenerator(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + private static void resetLocalPRNG() + { + HashMap attributes = new HashMap(); + attributes.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + byte[] key = new byte[128 / 8]; // AES default key size + Random rand = new Random(System.currentTimeMillis()); + rand.nextBytes(key); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + int index = rand.nextInt() & 0xFF; + attributes.put(UMacGenerator.INDEX, new Integer(index)); + + prng.setup(attributes); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.SecureRandomSpi interface implementation ------------------ + + public byte[] engineGenerateSeed(int numBytes) + { + if (numBytes < 1) + { + return new byte[0]; + } + byte[] result = new byte[numBytes]; + this.engineNextBytes(result); + return result; + } + + public void engineNextBytes(byte[] bytes) + { + if (!adaptee.isInitialised()) + { + this.engineSetSeed(new byte[0]); + } + + while (true) + { + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + break; + } + catch (LimitReachedException x) + { // reseed the generator + resetLocalPRNG(); + } + } + } + + public void engineSetSeed(byte[] seed) + { + // compute the total number of random bytes required to setup adaptee + int materialLength = 0; + materialLength += 16; // key material size + materialLength++; // index size + byte[] material = new byte[materialLength]; + + // use as much as possible bytes from the seed + int materialOffset = 0; + int materialLeft = material.length; + if (seed.length > 0) + { // copy some bytes into key and update indices + int lenToCopy = Math.min(materialLength, seed.length); + System.arraycopy(seed, 0, material, 0, lenToCopy); + materialOffset += lenToCopy; + materialLeft -= lenToCopy; + } + if (materialOffset > 0) + { // generate the rest + while (true) + { + try + { + prng.nextBytes(material, materialOffset, materialLeft); + break; + } + catch (IllegalStateException x) + { // should not happen + throw new InternalError(MSG + String.valueOf(x)); + } + catch (LimitReachedException x) + { + if (DEBUG) + { + debug(MSG + String.valueOf(x)); + debug(RETRY); + } + } + } + } + + // setup the underlying adaptee instance + HashMap attributes = new HashMap(); + + // use AES cipher with 128-bit block size + attributes.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + // specify the key + byte[] key = new byte[16]; + System.arraycopy(material, 0, key, 0, 16); + attributes.put(IBlockCipher.KEY_MATERIAL, key); + // use a 1-byte index + attributes.put(UMacGenerator.INDEX, new Integer(material[16] & 0xFF)); + + adaptee.init(attributes); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/sig/DHKeyFactory.java b/gnu/javax/crypto/jce/sig/DHKeyFactory.java new file mode 100644 index 000000000..701191adc --- /dev/null +++ b/gnu/javax/crypto/jce/sig/DHKeyFactory.java @@ -0,0 +1,232 @@ +/* DHKeyFactory.java -- DH key-factory JCE Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import gnu.java.security.Registry; +import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec; +import gnu.javax.crypto.key.dh.DHKeyPairX509Codec; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHPrivateKeySpec; +import javax.crypto.spec.DHPublicKeySpec; + +/** + * Implementation of a JCE Adapter for DH a key-factory. + */ +public class DHKeyFactory + extends KeyFactorySpi +{ + // implicit 0-arguments constructor + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DHPublicKeySpec) + { + DHPublicKeySpec spec = (DHPublicKeySpec) keySpec; + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + BigInteger y = spec.getY(); + return new GnuDHPublicKey(Registry.X509_ENCODING_ID, null, p, g, y); + } + + if (keySpec instanceof X509EncodedKeySpec) + { + X509EncodedKeySpec spec = (X509EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PublicKey result; + try + { + result = new DHKeyPairX509Codec().decodePublicKey(encoded); + return result; + } + catch (RuntimeException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DHPrivateKeySpec) + { + DHPrivateKeySpec spec = (DHPrivateKeySpec) keySpec; + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + BigInteger x = spec.getX(); + return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, null, p, g, x); + } + + if (keySpec instanceof PKCS8EncodedKeySpec) + { + PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PrivateKey result; + try + { + result = new DHKeyPairPKCS8Codec().decodePrivateKey(encoded); + return result; + } + catch (RuntimeException x) + { + InvalidKeySpecException y = new InvalidKeySpecException(); + y.initCause(x); + throw y; + } + } + + throw new InvalidKeySpecException("Unsupported (private) key specification"); + } + + protected KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof DHPublicKey) + { + if (keySpec.isAssignableFrom(DHPublicKeySpec.class)) + { + DHPublicKey dssKey = (DHPublicKey) key; + BigInteger p = dssKey.getParams().getP(); + BigInteger g = dssKey.getParams().getG(); + BigInteger y = dssKey.getY(); + return new DHPublicKeySpec(y, p, g); + } + + if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) + { + if (key instanceof GnuDHPublicKey) + { + GnuDHPublicKey dhKey = (GnuDHPublicKey) key; + byte[] encoded = dhKey.getEncoded(Registry.X509_ENCODING_ID); + return new X509EncodedKeySpec(encoded); + } + + if (Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new X509EncodedKeySpec(encoded); + } + + throw new InvalidKeySpecException("Wrong key type or unsupported (public) key specification"); + } + + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + + if (key instanceof DHPrivateKey) + { + if (keySpec.isAssignableFrom(DHPrivateKeySpec.class)) + { + DHPrivateKey dhKey = (DHPrivateKey) key; + BigInteger p = dhKey.getParams().getP(); + BigInteger g = dhKey.getParams().getG(); + BigInteger x = dhKey.getX(); + return new DHPrivateKeySpec(x, p, g); + } + + if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) + { + if (key instanceof GnuDHPrivateKey) + { + GnuDHPrivateKey dhKey = (GnuDHPrivateKey) key; + byte[] encoded = dhKey.getEncoded(Registry.PKCS8_ENCODING_ID); + return new PKCS8EncodedKeySpec(encoded); + } + + if (Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new PKCS8EncodedKeySpec(encoded); + } + + throw new InvalidKeySpecException("Wrong key type or unsupported (private) key specification"); + } + + throw new InvalidKeySpecException("Unsupported (private) key specification"); + } + + throw new InvalidKeySpecException("Wrong key type or unsupported key specification"); + } + + protected Key engineTranslateKey(Key key) throws InvalidKeyException + { + if ((key instanceof GnuDHPublicKey) || (key instanceof GnuDHPrivateKey)) + return key; + + if (key instanceof DHPublicKey) + { + DHPublicKey dsaKey = (DHPublicKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger y = dsaKey.getY(); + return new GnuDHPublicKey(Registry.X509_ENCODING_ID, null, p, g, y); + } + + if (key instanceof DHPrivateKey) + { + DHPrivateKey dsaKey = (DHPrivateKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger x = dsaKey.getX(); + return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, null, p, g, x); + } + + throw new InvalidKeyException("Wrong key type"); + } +} diff --git a/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java b/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java new file mode 100644 index 000000000..5b3badc8d --- /dev/null +++ b/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java @@ -0,0 +1,91 @@ +/* DHKeyPairGeneratorSpi.java -- DH key-pair generator JCE Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import java.security.InvalidAlgorithmParameterException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; + +import javax.crypto.spec.DHGenParameterSpec; + +import gnu.java.security.Registry; +import gnu.java.security.jce.sig.KeyPairGeneratorAdapter; +import gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator; + +public class DHKeyPairGeneratorSpi + extends KeyPairGeneratorAdapter +{ + public DHKeyPairGeneratorSpi() + { + super(Registry.DH_KPG); + } + + public void initialize(int keysize, SecureRandom random) + { + HashMap attributes = new HashMap(); + attributes.put(GnuDHKeyPairGenerator.PRIME_SIZE, new Integer(keysize)); + if (random != null) + attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + new Integer(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } + + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + HashMap attributes = new HashMap(); + if (params != null) + { + if (! (params instanceof DHGenParameterSpec)) + throw new InvalidAlgorithmParameterException("params"); + + attributes.put(GnuDHKeyPairGenerator.DH_PARAMETERS, params); + } + + if (random != null) + attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + new Integer(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } +} diff --git a/gnu/javax/crypto/jce/sig/DHParameters.java b/gnu/javax/crypto/jce/sig/DHParameters.java new file mode 100644 index 000000000..0357c163d --- /dev/null +++ b/gnu/javax/crypto/jce/sig/DHParameters.java @@ -0,0 +1,220 @@ +/* DHParameters.java -- DH parameters DAO + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.AlgorithmParametersSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.ArrayList; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +/** + * A JCE-specific Data Access Object (DAO) for DH parameters. + */ +public class DHParameters + extends AlgorithmParametersSpi +{ + /** The prime public modulus. */ + private BigInteger p; + + /** The generator. */ + private BigInteger g; + + /** A prime factor of p-1. */ + private BigInteger q; + + /** The (private) random exponent's size (in bits). */ + private int l; + + // default 0-arguments constructor + + protected void engineInit(AlgorithmParameterSpec spec) + throws InvalidParameterSpecException + { + if (! (spec instanceof DHParameterSpec)) + throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: " + + spec.getClass().getName()); + DHParameterSpec dhSpec = (DHParameterSpec) spec; + p = dhSpec.getP(); + g = dhSpec.getG(); + l = dhSpec.getL(); + } + + /** + * Decodes the set of DH parameters as per RFC-2459; i.e. the DER-encoded + * form of the following ASN.1 construct: + * + *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * 
+ */ + protected void engineInit(byte[] params) throws IOException + { + DERReader der = new DERReader(params); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + l = q.bitLength(); + } + + protected void engineInit(byte[] params, String format) throws IOException + { + if (format != null) + { + format = format.trim(); + if (format.length() == 0) + throw new IOException("Format MUST NOT be an empty string"); + + if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME)) + throw new IOException("Unknown or unsupported format: " + format); + } + + engineInit(params); + } + + protected AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec.isAssignableFrom(DHParameterSpec.class)) + return new DHParameterSpec(p, g, l); + + if (paramSpec.isAssignableFrom(DHGenParameterSpec.class)) + return new DHGenParameterSpec(p.bitLength(), l); + + throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: " + + paramSpec.getName()); + } + + /** + * Encodes the set of DH parameters as per RFC-2459; i.e. as the DER-encoded + * form of the following ASN.1 construct: + * + *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * 
+ */ + protected byte[] engineGetEncoded() throws IOException + { + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derG = new DERValue(DER.INTEGER, g); + DERValue derQ = new DERValue(DER.INTEGER, q); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derG); + params.add(derQ); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DERWriter.write(baos, derParams); + byte[] result = baos.toByteArray(); + + return result; + } + + protected byte[] engineGetEncoded(String format) throws IOException + { + if (format != null) + { + format = format.trim(); + if (format.length() == 0) + throw new IOException("Format MUST NOT be an empty string"); + + if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME)) + throw new IOException("Unknown or unsupported format: " + format); + } + + return engineGetEncoded(); + } + + protected String engineToString() + { + StringBuffer sb = new StringBuffer("p="); + if (p == null) + sb.append("???"); + else + sb.append("0x").append(p.toString(16)); + + sb.append(", g="); + if (g == null) + sb.append("???"); + else + sb.append("0x").append(g.toString(16)); + + sb.append(", q="); + if (q == null) + sb.append("???"); + else + sb.append("0x").append(q.toString(16)); + + sb.append(", l=").append(l); + + return sb.toString(); + } +} diff --git a/gnu/javax/crypto/jce/sig/DHParametersGenerator.java b/gnu/javax/crypto/jce/sig/DHParametersGenerator.java new file mode 100644 index 000000000..3687ac3ca --- /dev/null +++ b/gnu/javax/crypto/jce/sig/DHParametersGenerator.java @@ -0,0 +1,152 @@ +/* DHParametersGenerator.java -- JCE Adapter for a generator of DH parameters + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.sig; + +import gnu.java.security.Registry; +import gnu.javax.crypto.jce.GnuCrypto; +import gnu.javax.crypto.key.dh.GnuDHKeyPairGenerator; +import gnu.javax.crypto.key.dh.RFC2631; + +import java.math.BigInteger; +import java.security.AlgorithmParameterGeneratorSpi; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +/** + * A JCE Adapter for a generator of DH parameters. + */ +public class DHParametersGenerator + extends AlgorithmParameterGeneratorSpi +{ + private static final Provider GNU_CRYPTO = new GnuCrypto(); + + /** Size of the prime (public) modulus in bits. */ + private int modulusSize = -1; + + /** Size of the prime (private) modulus in bits. */ + private int exponentSize = -1; + + /** User specified source of randomness. */ + private SecureRandom rnd; + + /** Our concrete DH parameters generator. */ + private RFC2631 rfc2631; + + + protected void engineInit(int size, SecureRandom random) + { + if ((size % 256) != 0 || size < GnuDHKeyPairGenerator.DEFAULT_PRIME_SIZE) + throw new InvalidParameterException("Prime modulus (p) size (in bits) " + + "MUST be a multiple of 256, and " + + "greater than or equal to 1024"); + this.modulusSize = size; + this.rnd = random; + } + + protected void engineInit(AlgorithmParameterSpec spec, SecureRandom random) + throws InvalidAlgorithmParameterException + { + if (spec instanceof DHParameterSpec) + { + DHParameterSpec dhSpec = (DHParameterSpec) spec; + BigInteger p = dhSpec.getP(); + int size = p.bitLength(); + this.engineInit(size, random); + } + else if (spec instanceof DHGenParameterSpec) + { + DHGenParameterSpec dhSpec = (DHGenParameterSpec) spec; + int size = dhSpec.getPrimeSize(); + this.engineInit(size, random); + exponentSize = dhSpec.getExponentSize(); + + if ((exponentSize % 8) != 0 + || exponentSize < GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE) + throw new InvalidParameterException("Random exponent size (in bits) " + + "MUST be a multiple of 8, and " + + "greater than or equal to " + + GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE); + if (exponentSize > modulusSize) + throw new InvalidParameterException("Random exponent size (in bits) " + + "MUST be less than that of the " + + "public prime modulus (p)"); + } + + throw new InvalidAlgorithmParameterException("Wrong AlgorithmParameterSpec type: " + + spec.getClass().getName()); + } + + protected AlgorithmParameters engineGenerateParameters() + { + if (modulusSize < 1) + modulusSize = GnuDHKeyPairGenerator.DEFAULT_PRIME_SIZE; + + if (exponentSize < 1) + exponentSize = GnuDHKeyPairGenerator.DEFAULT_EXPONENT_SIZE; + + rfc2631 = new RFC2631(exponentSize, modulusSize, rnd); + BigInteger[] params = rfc2631.generateParameters(); + BigInteger p = params[RFC2631.DH_PARAMS_P]; + BigInteger g = params[RFC2631.DH_PARAMS_G]; + int l = params[RFC2631.DH_PARAMS_Q].bitLength(); + DHParameterSpec spec = new DHParameterSpec(p, g, l); + AlgorithmParameters result = null; + try + { + result = AlgorithmParameters.getInstance(Registry.DH_KPG, GNU_CRYPTO); + result.init(spec); + } + catch (NoSuchAlgorithmException ignore) + { + } + catch (InvalidParameterSpecException ignore) + { + } + return result; + } +} diff --git a/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java b/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java new file mode 100644 index 000000000..63e7740ec --- /dev/null +++ b/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java @@ -0,0 +1,139 @@ +/* BlockCipherParameterSpec.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.spec; + +import gnu.java.security.util.Util; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * Block cipher parameters in GNU Crypto are the cipher's name, its block + * and key sizes, and an optional initialization vector. + */ +public class BlockCipherParameterSpec implements AlgorithmParameterSpec +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** + * The initialization vector. + */ + protected byte[] iv; + + /** + * The cipher's block size, in bytes. + */ + protected int blockSize; + + /** + * The cipher's key size, in bytes. + */ + protected int keySize; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * Create a new parameter specification. + * + * @param iv The initialization vector, or null if + * there is no IV. + * @param blockSize The cipher's block size, in bytes. + * @param keySize The cipher's key size, in bytes. + */ + public BlockCipherParameterSpec(byte[] iv, int blockSize, int keySize) + { + this.iv = (iv != null) ? (byte[]) iv.clone() : null; + this.blockSize = blockSize; + this.keySize = keySize; + } + + /** + * Create a new parameter specification with no IV. + * + * @param blockSize The cipher's block size, in bytes. + * @param keySize The cipher's key size, in bytes. + */ + public BlockCipherParameterSpec(int blockSize, int keySize) + { + this(null, blockSize, keySize); + } + + // Instance methods. + // ----------------------------------------------------------------------- + + /** + * Get the initialization vector for the cipher, or null + * if there is no IV. + * + * @return The IV. + */ + public byte[] getIV() + { + return iv; + } + + /** + * Get the block size of the cipher these parameters are for. + * + * @return The block size. + */ + public int getBlockSize() + { + return blockSize; + } + + /** + * Get the key size of the cipher these parameters are for. + * + * @return The block size. + */ + public int getKeySize() + { + return keySize; + } + + public String toString() + { + return getClass().getName() + " { " + + ((iv != null) ? ("IV=" + Util.toString(iv)) + ", " : "") + "BS=" + + blockSize + ", KS=" + keySize + " }"; + } +} diff --git a/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java b/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java new file mode 100644 index 000000000..0ebec0991 --- /dev/null +++ b/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java @@ -0,0 +1,129 @@ +/* TMMHParameterSpec.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.spec; + +import gnu.java.security.prng.IRandom; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class represents the algorithm parameters for the Truncated + * Multi-Modular Hash function for use with JCE-derived instances of + * {@link gnu.crypto.mac.TMMH16}. + * + *

This class is little more than a container for the key stream, tag + * length, and prefix parameters for the TMMH algorithm. + */ +public class TMMHParameterSpec implements AlgorithmParameterSpec +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** The keystream. */ + protected IRandom keystream; + + /** The tag length. */ + protected Integer tagLength; + + /** The prefix. */ + protected byte[] prefix; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * Create a new parameter specification. + * + * @param keystream The (PRNG) key stream. + * @param tagLength The tag length. + * @param prefix The prefix. + */ + public TMMHParameterSpec(IRandom keystream, Integer tagLength, byte[] prefix) + { + this.keystream = keystream; + this.tagLength = tagLength; + this.prefix = prefix; + } + + /** + * Create a new parameter specification with no prefix. + * + * @param keystream The (PRNG) key stream. + * @param tagLength The tag length. + */ + public TMMHParameterSpec(IRandom keystream, Integer tagLength) + { + this(keystream, tagLength, null); + } + + // Instance methods. + // ----------------------------------------------------------------------- + + /** + * Return the key stream this specification was initialized with. + * + * @return The key stream. + */ + public IRandom getKeystream() + { + return keystream; + } + + /** + * Return the tag length this specification was initialized with. + * + * @return The tag length. + */ + public Integer getTagLength() + { + return tagLength; + } + + /** + * Return the prefix, or null if no prefix was + * specified. + * + * @return The prefix. + */ + public byte[] getPrefix() + { + return prefix; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java b/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java new file mode 100644 index 000000000..47d807d49 --- /dev/null +++ b/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java @@ -0,0 +1,82 @@ +/* UMac32ParameterSpec.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.jce.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class represents the parameters for the UMAC-32 message + * authentication code algorithm. In practice this means the + * Nonce material used to initialize the algorithm. + */ +public class UMac32ParameterSpec implements AlgorithmParameterSpec +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** The Nonce material. */ + protected byte[] nonce; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * Create a new parameter instance. + * + * @param nonce The nonce material. + */ + public UMac32ParameterSpec(byte[] nonce) + { + this.nonce = nonce; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + /** + * Return the nonce material. + * + * @return The nonce material. + */ + public byte[] getNonce() + { + return nonce; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/key/BaseKeyAgreementParty.java b/gnu/javax/crypto/key/BaseKeyAgreementParty.java new file mode 100644 index 000000000..bfd9378d2 --- /dev/null +++ b/gnu/javax/crypto/key/BaseKeyAgreementParty.java @@ -0,0 +1,208 @@ +/* BaseKeyAgreementParty.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +/** + *

A base abstract class to facilitate implementations of concrete key + * agreement protocol handlers.

+ */ +public abstract class BaseKeyAgreementParty implements IKeyAgreementParty +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + protected static final BigInteger TWO = BigInteger.valueOf(2L); + + /** The canonical name of the protocol. */ + protected String name; + + /** Whether the instance is initialised or not. */ + protected boolean initialised = false; + + /** The current step index of the protocol exchange. */ + protected int step = -1; + + /** Whether the exchange has concluded or not. */ + protected boolean complete = false; + + /** The optional {@link SecureRandom} instance to use. */ + protected SecureRandom rnd = null; + + /** The optional {@link IRandom} instance to use. */ + protected IRandom irnd = null; + + /** Our default source of randomness. */ + private PRNG prng = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected BaseKeyAgreementParty(String name) + { + super(); + + this.name = name; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public String name() + { + return name; + } + + public void init(Map attributes) throws KeyAgreementException + { + if (initialised) + { + throw new IllegalStateException("already initialised"); + } + + this.engineInit(attributes); + + initialised = true; + this.step = -1; + this.complete = false; + } + + public OutgoingMessage processMessage(IncomingMessage in) + throws KeyAgreementException + { + if (!initialised) + { + throw new IllegalStateException("not initialised"); + } + if (complete) + { + throw new IllegalStateException("exchange has already concluded"); + } + + step++; + return this.engineProcessMessage(in); + } + + public boolean isComplete() + { + return complete; + } + + public byte[] getSharedSecret() throws KeyAgreementException + { + if (!initialised) + { + throw new KeyAgreementException("not yet initialised"); + } + if (!isComplete()) + { + throw new KeyAgreementException("not yet computed"); + } + return engineSharedSecret(); + } + + public void reset() + { + if (initialised) + { + this.engineReset(); + initialised = false; + } + } + + // abstract methods to be implemented by concrete subclasses --------------- + + protected abstract void engineInit(Map attributes) + throws KeyAgreementException; + + protected abstract OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException; + + protected abstract byte[] engineSharedSecret() throws KeyAgreementException; + + protected abstract void engineReset(); + + // helper methods ---------------------------------------------------------- + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + protected void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else if (irnd != null) + { + try + { + irnd.nextBytes(buffer, 0, buffer.length); + } + catch (LimitReachedException lre) + { + irnd = null; + getDefaultPRNG().nextBytes(buffer); + } + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/key/GnuSecretKey.java b/gnu/javax/crypto/key/GnuSecretKey.java new file mode 100644 index 000000000..93b21a67c --- /dev/null +++ b/gnu/javax/crypto/key/GnuSecretKey.java @@ -0,0 +1,149 @@ +/* GnuSecretKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.security.util.Util; +import java.security.Key; + +/** + * A secret key composed of a sequence of raw, unformatted octets. This class + * is analogous to the {@link javax.crypto.spec.SecretKeySpec} class, but is + * provided for platforms that do not or cannot contain that class. + */ +public class GnuSecretKey implements Key +{ + + // Field. + // ------------------------------------------------------------------------ + + private final byte[] key; + + private final String algorithm; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Creates a new secret key. The supplied byte array is copied by this + * constructor. + * + * @param key The raw, secret key. + * @param algorithm The algorithm name, which can be null or empty. + */ + public GnuSecretKey(byte[] key, String algorithm) + { + this(key, 0, key.length, algorithm); + } + + /** + * Creates a new secret key from a portion of a byte array. + * + * @param key The raw, secret key. + * @param offset The offset at which the key begins. + * @param length The number of bytes that comprise the key. + * @param algorithm The algorithm name, which can be null or empty. + */ + public GnuSecretKey(byte[] key, int offset, int length, String algorithm) + { + this.key = new byte[length]; + System.arraycopy(key, offset, this.key, 0, length); + this.algorithm = algorithm; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the algorithm name, if any. + * + * @return The algorithm name. + */ + public String getAlgorithm() + { + return null; + } + + /** + * Returns the encoded key, which is merely the byte array this class was + * created with. A reference to the internal byte array is returned, so the + * caller can delete this key from memory by modifying the returned array. + * + * @return The raw key. + */ + public byte[] getEncoded() + { + return key; + } + + /** + * Returns the string "RAW". + * + * @return The string "RAW". + */ + public String getFormat() + { + return "RAW"; + } + + public boolean equals(Object o) + { + if (!(o instanceof GnuSecretKey)) + { + return false; + } + if (key.length != ((GnuSecretKey) o).key.length) + { + return false; + } + byte[] key2 = ((GnuSecretKey) o).key; + for (int i = 0; i < key.length; i++) + { + if (key[i] != key2[i]) + { + return false; + } + } + return true; + } + + public String toString() + { + return "GnuSecretKey [ " + algorithm + " " + Util.toString(key) + " ]"; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/key/IKeyAgreementParty.java b/gnu/javax/crypto/key/IKeyAgreementParty.java new file mode 100644 index 000000000..05aef5e51 --- /dev/null +++ b/gnu/javax/crypto/key/IKeyAgreementParty.java @@ -0,0 +1,105 @@ +/* IKeyAgreementParty.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import java.util.Map; + +/** + *

The visible methods of an key agreement protocol participating party.

+ */ +public interface IKeyAgreementParty +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + *

Returns the canonical name of the key agreement protocol.

+ * + * @return the canonical name of the key agreement protocol. + */ + String name(); + + /** + *

Sets up the instance to operate with specific attributes.

+ * + * @param attributes a map of name-values used by concrete implementations. + * @throws KeyAgreementException if an exception occurs during the setup. + */ + void init(Map attributes) throws KeyAgreementException; + + /** + *

Processes an incoming message at one end, generating a message that + * will be processed by the other party(ies).

+ * + * @param in the incoming message. + * @return an outgoing message, or null if this is an + * intermediary step that does not cause any output. + * @throws KeyAgreementException if an exception occurs during the processing + * of the incoming message, or during the generation of the outgoing message. + */ + OutgoingMessage processMessage(IncomingMessage in) + throws KeyAgreementException; + + /** + *

Returns true if the party in the key agreement protocol + * exchange has completed its part of the exchange. If this is the case an + * {@link IllegalStateException} is thrown for any method invocation except + * init() or reset(). + * @return true if this party has completed its part of the key + * agreement protocol exchange; false otherwise. + */ + boolean isComplete(); + + /** + *

Returns the byte array containing the shared secret as generated by + * this party.

+ * + * @return the generated shared secret. + * @throws KeyAgreementException if the key agreement is not yet initialised, + * or is initialised but the exchange is still in progress. + */ + byte[] getSharedSecret() throws KeyAgreementException; + + /** Resets this instance for re-use with another set of attributes. */ + void reset(); +} \ No newline at end of file diff --git a/gnu/javax/crypto/key/IncomingMessage.java b/gnu/javax/crypto/key/IncomingMessage.java new file mode 100644 index 000000000..e04c85399 --- /dev/null +++ b/gnu/javax/crypto/key/IncomingMessage.java @@ -0,0 +1,356 @@ +/* IncomingMessage.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec; +import gnu.java.security.key.dss.DSSKeyPairRawCodec; +import gnu.java.security.key.dss.DSSKeyPairX509Codec; +import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec; +import gnu.java.security.key.rsa.RSAKeyPairRawCodec; +import gnu.java.security.key.rsa.RSAKeyPairX509Codec; +import gnu.javax.crypto.key.dh.DHKeyPairPKCS8Codec; +import gnu.javax.crypto.key.dh.DHKeyPairRawCodec; +import gnu.javax.crypto.key.dh.DHKeyPairX509Codec; +import gnu.javax.crypto.key.srp6.SRPKeyPairRawCodec; + +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + *

An implementation of an incoming message for use with key agreement + * protocols.

+ */ +public class IncomingMessage +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The internal buffer stream containing the message's contents. */ + protected ByteArrayInputStream in; + + /** The length of the message contents, according to its 4-byte header. */ + protected int length; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Constructs an incoming message given the message's encoded form, + * including its header bytes.

+ * + * @param b the encoded form, including the header bytes, of an incoming + * message. + * @throws KeyAgreementException if the buffer is malformed. + */ + public IncomingMessage(byte[] b) throws KeyAgreementException + { + this(); + + if (b.length < 4) + { + throw new KeyAgreementException("message header too short"); + } + length = b[0] << 24 | (b[1] & 0xFF) << 16 | (b[2] & 0xFF) << 8 + | (b[3] & 0xFF); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + { + throw new KeyAgreementException("message size limit exceeded"); + } + in = new ByteArrayInputStream(b, 4, length); + } + + /** Trivial private constructor for use by the class method. */ + private IncomingMessage() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a message given its encoded contents, excluding + * the message's header bytes.

+ * + *

Calls the method with the same name and three arguments as: + * getInstance(raw, 0, raw.length). + * + * @param raw the encoded form, excluding the header bytes. + * @return a new instance of IncomingMessage. + */ + public static IncomingMessage getInstance(byte[] raw) + { + return getInstance(raw, 0, raw.length); + } + + /** + *

Returns an instance of a message given its encoded contents, excluding + * the message's header bytes.

+ * + * @param raw the encoded form, excluding the header bytes. + * @param offset offset where to start using raw bytes from. + * @param len number of bytes to use. + * @return a new instance of IncomingMessage. + */ + public static IncomingMessage getInstance(byte[] raw, int offset, int len) + { + IncomingMessage result = new IncomingMessage(); + result.in = new ByteArrayInputStream(raw, offset, len); + return result; + } + + /** + *

Converts two octets into the number that they represent.

+ * + * @param b the two octets. + * @return the length. + */ + public static int twoBytesToLength(byte[] b) throws KeyAgreementException + { + int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF); + if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT) + { + throw new KeyAgreementException("encoded MPI size limit exceeded"); + } + return result; + } + + /** + *

Converts four octets into the number that they represent.

+ * + * @param b the four octets. + * @return the length. + */ + public static int fourBytesToLength(byte[] b) throws KeyAgreementException + { + int result = b[0] << 24 | (b[1] & 0xFF) << 16 | (b[2] & 0xFF) << 8 + | (b[3] & 0xFF); + if (result > Registry.SASL_FOUR_BYTE_MAX_LIMIT || result < 0) + { + throw new KeyAgreementException("encoded entity size limit exceeded"); + } + return result; + } + + // Instance methods + // ------------------------------------------------------------------------- + + public boolean hasMoreElements() + { + return (in.available() > 0); + } + + /** + * Decodes a public key from the message. + *

+ * See {@link OutgoingMessage#writePublicKey(java.security.PublicKey)} for + * more details on the internal format. + * + * @throws KeyAgreementException if an encoding size constraint is violated or + * a mismatch was detected in the encoding. + */ + public PublicKey readPublicKey() throws KeyAgreementException + { + if (in.available() < 5) + throw new KeyAgreementException("not enough bytes for a public key in message"); + + byte[] elementLengthBytes = new byte[4]; + in.read(elementLengthBytes, 0, 4); + int elementLength = fourBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new KeyAgreementException("illegal public key encoding"); + + int keyTypeAndFormatID = in.read() & 0xFF; + elementLength--; + byte[] kb = new byte[elementLength]; + in.read(kb, 0, elementLength); + + // instantiate the right codec and decode + IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID); + return kpc.decodePublicKey(kb); + } + + /** + * Decodes a private key from the message. + *

+ * See {@link OutgoingMessage#writePrivateKey(java.security.PrivateKey)} for + * more details. + * + * @throws KeyAgreementException if an encoding size constraint is violated or + * a mismatch was detected in the encoding. + */ + public PrivateKey readPrivateKey() throws KeyAgreementException + { + if (in.available() < 5) + throw new KeyAgreementException("not enough bytes for a private key in message"); + + byte[] elementLengthBytes = new byte[4]; + in.read(elementLengthBytes, 0, 4); + int elementLength = fourBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + throw new KeyAgreementException("illegal private key encoding"); + + int keyTypeAndFormatID = in.read() & 0xFF; + elementLength--; + byte[] kb = new byte[elementLength]; + in.read(kb, 0, elementLength); + + // instantiate the right codec and decode + IKeyPairCodec kpc = getKeyPairCodec(keyTypeAndFormatID); + return kpc.decodePrivateKey(kb); + } + + /** + *

Decodes an MPI from the current message's contents.

+ * + * @return a native representation of an MPI. + * @throws KeyAgreementException if an encoding exception occurs during the + * operation. + */ + public BigInteger readMPI() throws KeyAgreementException + { + if (in.available() < 2) + { + throw new KeyAgreementException( + "not enough bytes for an MPI in message"); + } + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes, 0, 2); + int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + { + throw new KeyAgreementException("illegal MPI encoding"); + } + + byte[] element = new byte[elementLength]; + in.read(element, 0, element.length); + + return new BigInteger(1, element); + } + + public String readString() throws KeyAgreementException + { + if (in.available() < 2) + { + throw new KeyAgreementException( + "not enough bytes for a text in message"); + } + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes, 0, 2); + int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + { + throw new KeyAgreementException("illegal text encoding"); + } + + byte[] element = new byte[elementLength]; + in.read(element, 0, element.length); + String result = null; + try + { + result = new String(element, "UTF8"); + } + catch (UnsupportedEncodingException x) + { + throw new KeyAgreementException("unxupported UTF8 encoding", x); + } + + return result; + } + + private IKeyPairCodec getKeyPairCodec(int keyTypeAndFormatID) + throws KeyAgreementException + { + int keyType = (keyTypeAndFormatID >>> 4) & 0x0F; + int formatID = keyTypeAndFormatID & 0x0F; + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + switch (keyType) + { + case 0: + return new DSSKeyPairRawCodec(); + case 1: + return new RSAKeyPairRawCodec(); + case 2: + return new DHKeyPairRawCodec(); + case 3: + return new SRPKeyPairRawCodec(); + default: + throw new KeyAgreementException("Unknown key-type for Raw format: " + + keyType); + } + case Registry.X509_ENCODING_ID: + switch (keyType) + { + case 0: + return new DSSKeyPairX509Codec(); + case 1: + return new RSAKeyPairX509Codec(); + case 2: + return new DHKeyPairX509Codec(); + default: + throw new KeyAgreementException("Unknown key-type for X.509 format: " + + keyType); + } + case Registry.PKCS8_ENCODING_ID: + switch (keyType) + { + case 0: + return new DSSKeyPairPKCS8Codec(); + case 1: + return new RSAKeyPairPKCS8Codec(); + case 2: + return new DHKeyPairPKCS8Codec(); + default: + throw new KeyAgreementException("Unknown key-type for PKCS#8 format: " + + keyType); + } + default: + throw new KeyAgreementException("Unknown format identifier: " + + formatID); + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/key/KeyAgreementException.java b/gnu/javax/crypto/key/KeyAgreementException.java new file mode 100644 index 000000000..c2fa434a2 --- /dev/null +++ b/gnu/javax/crypto/key/KeyAgreementException.java @@ -0,0 +1,187 @@ +/* KeyAgreementException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.security.KeyManagementException; + +/** + * A generic exception indicating that an unexpected condition has + * been detected during the setup and/or processing of a key agreement + * protocol exchange. + */ +public class KeyAgreementException extends KeyManagementException implements + Serializable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** @serial The possibly null root cause exception. */ + private Throwable cause = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Constructs a new instance of KeyAgreementException. The + * root exception and the detailed message are null.

+ */ + public KeyAgreementException() + { + super(); + } + + /** + *

Constructs a new instance of KeyAgreementException with a + * detailed message. The root exception is null.

+ * + * @param detail a possibly null string containing details of + * the exception. + * @see Throwable#getMessage() + */ + public KeyAgreementException(String detail) + { + super(detail); + } + + /** + *

Constructs a new instance of KeyAgreementException with a + * detailed message and a root exception.

+ * + * @param detail a possibly null string containing details of + * the exception. + * @param cause a possibly null root exception that caused this + * exception. + * @see Throwable#getMessage() + * @see #getCause() + */ + public KeyAgreementException(String detail, Throwable cause) + { + super(detail); + this.cause = cause; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns the cause of this throwable or null if the cause + * is nonexistent or unknown. The cause is the throwable that caused + * this exception to be thrown.

+ * + * @return the possibly null exception that caused this one. + */ + public Throwable getCause() + { + return cause; + } + + /** + *

Prints this exception's stack trace to System.err. If this + * exception has a root exception; the stack trace of the root + * exception is also printed to System.err.

+ */ + public void printStackTrace() + { + super.printStackTrace(); + if (cause != null) + { + cause.printStackTrace(); + } + } + + /** + *

Prints this exception's stack trace to a print stream. If this + * exception has a root exception; the stack trace of the root + * exception is also printed to the print stream.

+ * + * @param ps the non-null print stream to which to print. + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if (cause != null) + { + cause.printStackTrace(ps); + } + } + + /** + *

Prints this exception's stack trace to a print writer. If this + * exception has a root exception; the stack trace of the root + * exception is also printed to the print writer.

+ * + * @param pw the non-null print writer to use for output. + */ + public void printStackTrace(PrintWriter pw) + { + super.printStackTrace(pw); + if (cause != null) + { + cause.printStackTrace(pw); + } + } + + /** + *

Returns the string representation of this exception. The string + * representation contains this exception's class name, its detailed + * messsage, and if it has a root exception, the string representation + * of the root exception. This string representation is meant for debugging + * and is not meant to be interpreted programmatically.

+ * + * @return the non-null string representation of this exception. + * @see Throwable#getMessage() + */ + public String toString() + { + StringBuffer sb = new StringBuffer(this.getClass().getName()).append(": ").append( + super.toString()); + if (cause != null) + { + sb.append("; caused by: ").append(cause.toString()); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/key/KeyAgreementFactory.java b/gnu/javax/crypto/key/KeyAgreementFactory.java new file mode 100644 index 000000000..e2a7faba1 --- /dev/null +++ b/gnu/javax/crypto/key/KeyAgreementFactory.java @@ -0,0 +1,181 @@ +/* KeyAgreementFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.security.Registry; + +import gnu.javax.crypto.key.dh.DiffieHellmanSender; +import gnu.javax.crypto.key.dh.DiffieHellmanReceiver; +import gnu.javax.crypto.key.dh.ElGamalSender; +import gnu.javax.crypto.key.dh.ElGamalReceiver; +import gnu.javax.crypto.key.srp6.SRP6Host; +import gnu.javax.crypto.key.srp6.SRP6User; +import gnu.javax.crypto.key.srp6.SRP6SaslClient; +import gnu.javax.crypto.key.srp6.SRP6SaslServer; +import gnu.javax.crypto.key.srp6.SRP6TLSClient; +import gnu.javax.crypto.key.srp6.SRP6TLSServer; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + *

A Factory class to generate key agreement protocol handlers.

+ */ +public class KeyAgreementFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private KeyAgreementFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a key agreeent protocol handler, for party + * A in a two-party A..B exchange, given the + * canonical name of this protocol. Party A is usually the + * initiator of the exchange.

+ * + * @param name the case-insensitive key agreement protocol name. + * @return an instance of the key agreement protocol handler for party + * A, or null if none found. + */ + public static IKeyAgreementParty getPartyAInstance(String name) + { + if (name == null) + { + return null; + } + + name = name.trim(); + IKeyAgreementParty result = null; + if (name.equalsIgnoreCase(Registry.DH_KA)) + { + result = new DiffieHellmanSender(); + } + else if (name.equalsIgnoreCase(Registry.ELGAMAL_KA)) + { + result = new ElGamalSender(); + } + else if (name.equalsIgnoreCase(Registry.SRP6_KA)) + { + result = new SRP6User(); + } + else if (name.equalsIgnoreCase(Registry.SRP_SASL_KA)) + { + result = new SRP6SaslClient(); + } + else if (name.equalsIgnoreCase(Registry.SRP_TLS_KA)) + { + result = new SRP6TLSClient(); + } + + return result; + } + + /** + *

Returns an instance of a key agreeent protocol handler, for party + * B in a two-party A..B exchange, given the + * canonical name of this protocol.

+ * + * @param name the case-insensitive key agreement protocol name. + * @return an instance of the key agreement protocol handler for party + * B, or null if none found. + */ + public static IKeyAgreementParty getPartyBInstance(String name) + { + if (name == null) + { + return null; + } + + name = name.trim(); + IKeyAgreementParty result = null; + if (name.equalsIgnoreCase(Registry.DH_KA)) + { + result = new DiffieHellmanReceiver(); + } + else if (name.equalsIgnoreCase(Registry.ELGAMAL_KA)) + { + result = new ElGamalReceiver(); + } + else if (name.equalsIgnoreCase(Registry.SRP6_KA)) + { + result = new SRP6Host(); + } + else if (name.equalsIgnoreCase(Registry.SRP_SASL_KA)) + { + result = new SRP6SaslServer(); + } + else if (name.equalsIgnoreCase(Registry.SRP_TLS_KA)) + { + result = new SRP6TLSServer(); + } + + return result; + } + + /** + *

Returns a {@link Set} of key agreement protocol names supported by this + * Factory.

+ * + * @return a {@link Set} of key agreement protocol names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(Registry.DH_KA); + hs.add(Registry.ELGAMAL_KA); + hs.add(Registry.SRP6_KA); + hs.add(Registry.SRP_SASL_KA); + hs.add(Registry.SRP_TLS_KA); + + return Collections.unmodifiableSet(hs); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/key/OutgoingMessage.java b/gnu/javax/crypto/key/OutgoingMessage.java new file mode 100644 index 000000000..588012120 --- /dev/null +++ b/gnu/javax/crypto/key/OutgoingMessage.java @@ -0,0 +1,255 @@ +/* OutgoingMessage.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKey; +import gnu.java.security.key.rsa.GnuRSAKey; +import gnu.java.security.util.FormatUtil; +import gnu.javax.crypto.key.dh.GnuDHKey; +import gnu.javax.crypto.key.srp6.SRPKey; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.math.BigInteger; + +/** + *

An implementation of outgoing messages for use with key agreement + * protocols.

+ */ +public class OutgoingMessage +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The internal output stream. */ + private ByteArrayOutputStream out; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public OutgoingMessage() + { + super(); + + out = new ByteArrayOutputStream(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns the encoded form of the current message including the 4-byte + * length header.

+ * + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public byte[] toByteArray() throws KeyAgreementException + { + byte[] buffer = wrap(); + int length = buffer.length; + byte[] result = new byte[length + 4]; + result[0] = (byte) (length >>> 24); + result[1] = (byte) (length >>> 16); + result[2] = (byte) (length >>> 8); + result[3] = (byte) length; + System.arraycopy(buffer, 0, result, 4, length); + + return result; + } + + /** + *

Returns the encoded form of the current message excluding the 4-byte + * length header.

+ * + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public byte[] wrap() throws KeyAgreementException + { + int length = out.size(); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + { + throw new KeyAgreementException("message content is too long"); + } + return out.toByteArray(); + } + + /** + * Encodes a public key into the message. + *

+ * When a public key is encoded into an outgoing message, the byte array of + * the encoded key --according to its encoding/decoding format specified when + * the key was first instantiated-- are put in the message (a) preceeded by + * one byte representing both the type of key (upper 4-bit) and the identifier + * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity + * representing the total length, excluding these 4 bytes, of the bytes + * representing the encoded key and the one-byte representing the key-type and + * format; i.e. + * + *

+   *    key --> 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
+   * 
+ * + * @param k the public key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writePublicKey(PublicKey k) throws KeyAgreementException + { + writeKey(k); + } + + /** + * Encodes a private key into the message. + *

+ * When a private key is encoded into an outgoing message, the byte array of + * the encoded key --according to its encoding/decoding format specified when + * the key was first instantiated-- are put in the message (a) preceeded by + * one byte representing both the type of key (upper 4-bit) and the identifier + * of the format used (lower 4-bit), and (b) preceeed by a 4-byte entity + * representing the total length, excluding these 4 bytes, of the bytes + * representing the encoded key and the one-byte representing the key-type and + * format; i.e. + * + *

+   *    key --> 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
+   * 
+ * + * @param k the private key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writePrivateKey(PrivateKey k) throws KeyAgreementException + { + writeKey(k); + } + + /** + *

Encodes an MPI into the message.

+ * + * @param val the MPI to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + public void writeMPI(BigInteger val) throws KeyAgreementException + { + byte[] b = val.toByteArray(); + int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + { + throw new KeyAgreementException("MPI is too long"); + } + byte[] lengthBytes = { (byte) (length >>> 8), (byte) length }; + out.write(lengthBytes, 0, 2); + out.write(b, 0, b.length); + } + + /** + *

Encodes a string into the message.

+ * + * @param s the string to encode. + * @throws KeyAgreementException if the UTF8 encoding is not supported on + * this platform, or if an encoding size constraint is violated. + */ + public void writeString(String s) throws KeyAgreementException + { + byte[] b = null; + try + { + b = s.getBytes("UTF8"); + } + catch (UnsupportedEncodingException x) + { + throw new KeyAgreementException("unxupported UTF8 encoding", x); + } + int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + { + throw new KeyAgreementException("text too long"); + } + byte[] lengthBytes = { (byte) (length >>> 8), (byte) length }; + out.write(lengthBytes, 0, 2); + out.write(b, 0, b.length); + } + + /** + * @param k the key to encode. + * @throws KeyAgreementException if an encoding size constraint is violated. + */ + private void writeKey(Key k) throws KeyAgreementException + { + byte[] b = k.getEncoded(); + int keyType = getKeyType(k); + int formatID = FormatUtil.getFormatID(k.getFormat()); + int length = b.length + 1; + if (length > Registry.SASL_FOUR_BYTE_MAX_LIMIT) + throw new KeyAgreementException("Encoded key is too long"); + + byte[] lengthBytes = { (byte) (length >>> 24), (byte) (length >>> 16), + (byte) (length >>> 8), (byte) length }; + out.write(lengthBytes, 0, 4); + out.write(((keyType & 0x0F) << 4) | (formatID & 0x0F)); + out.write(b, 0, b.length); + } + + /** + * @param k the key to find an identifier for. + * @return an integer from 0 to 3 identifying + * the type of key. + * @throws KeyAgreementException if the designated key is of unknown or + * unsupported type. + */ + private int getKeyType(Key k) throws KeyAgreementException + { + if (k instanceof DSSKey) + return 0; + if (k instanceof GnuRSAKey) + return 1; + if (k instanceof GnuDHKey) + return 2; + if (k instanceof SRPKey) + return 3; + throw new KeyAgreementException("Unknown or unsupported key type: " + + k.getClass().getName()); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java b/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java new file mode 100644 index 000000000..34fb00706 --- /dev/null +++ b/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java @@ -0,0 +1,229 @@ +/* DHKeyPairPKCS8Codec.java -- PKCS#8 encoder/decoder for DH keys + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; +import gnu.java.security.util.Util; + +public class DHKeyPairPKCS8Codec + implements IKeyPairCodec +{ + private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return PKCS8_FORMAT; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePublicKey(PublicKey key) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * Returns the DER-encoded form of the PKCS#8 ASN.1 PrivateKeyInfo + * representation of a DH private key. The ASN.1 specification is as follows: + * + *
+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * 
+ * + * @return the DER encoded form of the ASN.1 representation of the + * PrivateKeyInfo field in an X.509 certificate. + * @throw InvalidParameterException if an error occurs during the marshalling + * process. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof GnuDHPrivateKey)) + throw new InvalidParameterException("Wrong key type"); + + DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID); + + GnuDHPrivateKey pk = (GnuDHPrivateKey) key; + BigInteger p = pk.getParams().getP(); + BigInteger g = pk.getParams().getG(); + BigInteger q = pk.getQ(); + BigInteger x = pk.getX(); + + ArrayList params = new ArrayList(3); + params.add(new DERValue(DER.INTEGER, p)); + params.add(new DERValue(DER.INTEGER, g)); + params.add(new DERValue(DER.INTEGER, q)); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, Util.trim(x)); + + ArrayList pki = new ArrayList(3); + pki.add(derVersion); + pki.add(derAlgorithmID); + pki.add(derPrivateKey); + DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derPKI); + result = baos.toByteArray(); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(e); + throw y; + } + + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PublicKey decodePublicKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DH + * {@link PrivateKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuDHPrivateKey} decoded from the + * PrivateKeyInfo material fed as input. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger version, p, q, g, x; + DERReader der = new DERReader(input); + try + { + DERValue derPKI = der.read(); + DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field"); + + DERValue derVersion = der.read(); + if (! (derVersion.getValue() instanceof BigInteger)) + throw new InvalidParameterException("Wrong Version field"); + + version = (BigInteger) derVersion.getValue(); + if (version.compareTo(BigInteger.ZERO) != 0) + throw new InvalidParameterException("Unexpected Version: " + version); + + DERValue derAlgoritmID = der.read(); + DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DH_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + + val = der.read(); + byte[] xBytes = (byte[]) val.getValue(); + x = new BigInteger(1, xBytes); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(e); + throw y; + } + + return new GnuDHPrivateKey(Registry.PKCS8_ENCODING_ID, q, p, g, x); + } +} diff --git a/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java b/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java new file mode 100644 index 000000000..c0ff82bea --- /dev/null +++ b/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java @@ -0,0 +1,370 @@ +/* DHKeyPairRawCodec.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + *

An object that implements the {@link IKeyPairCodec} operations for the + * Raw format to use with Diffie-Hellman keypairs.

+ */ +public class DHKeyPairRawCodec implements IKeyPairCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments ctor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.keys.IKeyPairCodec interface implementation ------------------- + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + *

Returns the encoded form of the designated Diffie-Hellman public key + * according to the Raw format supported by this library.

+ * + *

The Raw format for a DH public key, in this implementation, is + * a byte sequence consisting of the following:

+ * + *
    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DH_PUBLIC_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the DH parameter + * q in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter q,
  8. + *
  9. 4-byte count of following bytes representing the DH parameter + * p in internet order,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter p,
  12. + *
  13. 4-byte count of following bytes representing the DH parameter + * g,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter g,
  16. + *
  17. 4-byte count of following bytes representing the DH parameter + * y,
  18. + *
  19. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter y,
  20. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not a DH one. + * @see Registry#MAGIC_RAW_DH_PUBLIC_KEY + */ + public byte[] encodePublicKey(PublicKey key) + { + if (!(key instanceof GnuDHPublicKey)) + { + throw new IllegalArgumentException("key"); + } + + GnuDHPublicKey dhKey = (GnuDHPublicKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[0]); + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[1]); + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[2]); + baos.write(Registry.MAGIC_RAW_DH_PUBLIC_KEY[3]); + + // version + baos.write(0x01); + + // q + byte[] buffer = dhKey.getQ().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // p + buffer = dhKey.getParams().getP().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // g + buffer = dhKey.getParams().getG().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // y + buffer = dhKey.getY().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + public PublicKey decodePublicKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[0] + || k[1] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[1] + || k[2] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[2] + || k[3] != Registry.MAGIC_RAW_DH_PUBLIC_KEY[3]) + { + throw new IllegalArgumentException("magic"); + } + + // version + if (k[4] != 0x01) + { + throw new IllegalArgumentException("version"); + } + int i = 5; + int l; + byte[] buffer; + + // q + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + + // p + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + + // g + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + + // y + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger y = new BigInteger(1, buffer); + + return new GnuDHPublicKey(q, p, g, y); + } + + /** + *

Returns the encoded form of the designated Diffie-Hellman private key + * according to the Raw format supported by this library.

+ * + *

The Raw format for a DH private key, in this implementation, is + * a byte sequence consisting of the following:

+ * + *
    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_DH_PRIVATE_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the DH parameter + * q,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter q,
  8. + *
  9. 4-byte count of following bytes representing the DH parameter + * p in internet order,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter p,
  12. + *
  13. 4-byte count of following bytes representing the DH parameter + * g,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter g,
  16. + *
  17. 4-byte count of following bytes representing the DH parameter + * x,
  18. + *
  19. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the DH parameter x,
  20. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not a DH one. + * @see Registry#MAGIC_RAW_DH_PRIVATE_KEY + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (!(key instanceof GnuDHPrivateKey)) + { + throw new IllegalArgumentException("key"); + } + + GnuDHPrivateKey dhKey = (GnuDHPrivateKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]); + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[1]); + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[2]); + baos.write(Registry.MAGIC_RAW_DH_PRIVATE_KEY[3]); + + // version + baos.write(0x01); + + // q + byte[] buffer = dhKey.getQ().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // p + buffer = dhKey.getParams().getP().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // g + buffer = dhKey.getParams().getG().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // x + buffer = dhKey.getX().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + public PrivateKey decodePrivateKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[0] + || k[1] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[1] + || k[2] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[2] + || k[3] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[3]) + { + throw new IllegalArgumentException("magic"); + } + + // version + if (k[4] != 0x01) + { + throw new IllegalArgumentException("version"); + } + int i = 5; + int l; + byte[] buffer; + + // q + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger q = new BigInteger(1, buffer); + + // p + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger p = new BigInteger(1, buffer); + + // g + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + + // x + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger x = new BigInteger(1, buffer); + + return new GnuDHPrivateKey(q, p, g, x); + } +} diff --git a/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java b/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java new file mode 100644 index 000000000..7e8688bd3 --- /dev/null +++ b/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java @@ -0,0 +1,244 @@ +/* DHKeyPairX509Codec.java -- X.509 DER encoder/decoder for DH keys + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; + +public class DHKeyPairX509Codec + implements IKeyPairCodec +{ + private static final OID DH_ALG_OID = new OID(Registry.DH_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return X509_FORMAT; + } + + /** + * Returns the DER-encoded form of the X.509 ASN.1 SubjectPublicKeyInfo + * representation of a DH public key. The ASN.1 specification, as defined in + * RFC-3280, and RFC-2459, is as follows: + * + *
+   *   SubjectPublicKeyInfo ::= SEQUENCE {
+   *     algorithm         AlgorithmIdentifier,
+   *     subjectPublicKey  BIT STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DhParams ::= SEQUENCE {
+   *     p  INTEGER, -- odd prime, p=jq +1
+   *     g  INTEGER, -- generator, g
+   *     q  INTEGER  -- factor of p-1
+   *   }
+   * 
+ * + *

The subjectPublicKey field, which is a BIT STRING, contains the + * DER-encoded form of the DH public key as an INTEGER.

+ * + *
+   *       DHPublicKey ::= INTEGER -- public key, y = g^x mod p
+   * 
+ * + * @param key the {@link PublicKey} instance to encode. MUST be an instance of + * {@link GnuDHPublicKey}. + * @return the DER-encoded form of the ASN.1 representation of the + * SubjectPublicKeyInfo in an X.509 certificate. + * @throw InvalidParameterException if key is not an instance + * of {@link GnuDHPublicKey} or if an exception occurs during the + * marshalling process. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof GnuDHPublicKey)) + throw new InvalidParameterException("Wrong key type"); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DH_ALG_OID); + + GnuDHPublicKey dhKey = (GnuDHPublicKey) key; + BigInteger p = dhKey.getParams().getP(); + BigInteger g = dhKey.getParams().getG(); + BigInteger q = dhKey.getQ(); + BigInteger y = dhKey.getY(); + + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derG = new DERValue(DER.INTEGER, g); + DERValue derQ = new DERValue(DER.INTEGER, q); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derG); + params.add(derQ); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + DERValue derDHPublicKey = new DERValue(DER.INTEGER, y); + byte[] yBytes = derDHPublicKey.getEncoded(); + DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes)); + + ArrayList spki = new ArrayList(2); + spki.add(derAlgorithmID); + spki.add(derSPK); + DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derSPKI); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(); + e.initCause(x); + throw e; + } + + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + throw new InvalidParameterException("Wrong format for private keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DH + * {@link PublicKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuDHPublicKey} decoded from the + * SubjectPublicKeyInfo material in an X.509 certificate. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PublicKey decodePublicKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger p, g, q, y; + DERReader der = new DERReader(input); + try + { + DERValue derSPKI = der.read(); + DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); + + DERValue derAlgorithmID = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + if (! (derOID.getValue() instanceof OID)) + throw new InvalidParameterException("Wrong Algorithm field"); + + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DH_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DH Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + + val = der.read(); + if (! (val.getValue() instanceof BitString)) + throw new InvalidParameterException("Wrong SubjectPublicKey field"); + + byte[] yBytes = ((BitString) val.getValue()).toByteArray(); + + DERReader dhPub = new DERReader(yBytes); + val = dhPub.read(); + DerUtil.checkIsBigInteger(val, "Wrong Y field"); + y = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(); + e.initCause(x); + throw e; + } + + return new GnuDHPublicKey(Registry.X509_ENCODING_ID, q, p, g, y); + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for private keys"); + } +} diff --git a/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java b/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java new file mode 100644 index 000000000..5b1caa7d1 --- /dev/null +++ b/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java @@ -0,0 +1,134 @@ +/* DiffieHellmanKeyAgreement.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.BaseKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementException; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + *

The basic version of the Diffie-Hellman key agreement is described in the + * Handbook of Applied Cryptography [HAC] as follows:

+ *
    + *
  • An appropriate prime p and generator g of Zp* + * (2 <= g <= p-2) are selected and published.
  • + *
  • A and B each send the other one message over an open channel; as a + * result, they both can then compute a shared secret key K which they can + * use to protect their future communication.
  • + *
  • A chooses a random secret x, 1 <= x <= p-2, and sends B message + * (1) which is g^x mod p.
  • + *
  • B chooses a random secret y, 1 <= y <= p-2, and sends A message + * (2) which is g^y mod p.
  • + *
  • B receives message (1) and computes the shared key as K = (g^x)^y mod + * p.
  • + *
  • A receives message (2) and computes the shared key as K = (g^y)^x mod + * p.
  • + *
+ * + *

RFC-2631 describes a Static-Static Mode of operations with + * Diffie-Hellman keypairs as follows:

+ *
+ * "In Static-Static mode, both the sender and the recipient have a
+ static (and certified) key pair. Since the sender's and recipient's
+ keys are therefore the same for each message, ZZ will be the same for
+ each message. Thus, partyAInfo MUST be used (and different for each
+ message) in order to ensure that different messages use different
+ KEKs. Implementations MAY implement Static-Static mode."
+ * 
+ * + *

Reference:

+ *
    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
  3. [HAC]: Handbook of + * Applied Cryptography.
    + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997
    + * Menezes, A., van Oorschot, P. and S. Vanstone.
  4. + *
+ */ +public abstract class DiffieHellmanKeyAgreement extends BaseKeyAgreementParty +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.ka.prng"; + + public static final String KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY = "gnu.crypto.dh.ka.owner.private.key"; + + /** The key agreement party's private key. */ + protected DHPrivateKey ownerKey; + + /** The shared secret key. */ + protected BigInteger ZZ; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected DiffieHellmanKeyAgreement() + { + super(Registry.DH_KA); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of common abstract methods in BaseKeyAGreementParty ------ + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(ZZ); + } + + protected void engineReset() + { + ownerKey = null; + ZZ = null; + } +} diff --git a/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java b/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java new file mode 100644 index 000000000..4a3664d6a --- /dev/null +++ b/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java @@ -0,0 +1,147 @@ +/* DiffieHellmanReceiver.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.prng.IRandom; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + *

This implementation is the receiver's part of the basic version of the + * Diffie-Hellman key agreement exchange (B in [HAC]).

+ * + * @see DiffieHellmanKeyAgreement + */ +public class DiffieHellmanReceiver extends DiffieHellmanKeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private BigInteger y; // the receiver's random secret + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + protected void engineInit(Map attributes) throws KeyAgreementException + { + Object random = attributes.get(SOURCE_OF_RANDOMNESS); + rnd = null; + irnd = null; + if (random instanceof SecureRandom) + { + rnd = (SecureRandom) random; + } + else if (random instanceof IRandom) + { + irnd = (IRandom) random; + } + ownerKey = (DHPrivateKey) attributes.get(KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY); + if (ownerKey == null) + { + throw new KeyAgreementException("missing owner's private key"); + } + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + // own methods ------------------------------------------------------------- + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger m1 = in.readMPI(); + if (m1 == null) + { + throw new KeyAgreementException("missing message (1)"); + } + + BigInteger p = ownerKey.getParams().getP(); + BigInteger g = ownerKey.getParams().getG(); + + // B chooses a random integer y, 1 <= y <= p-2 + // rfc-2631 restricts y to only be in [2, p-1] + BigInteger p_minus_2 = p.subtract(TWO); + byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8]; + do + { + nextRandomBytes(xBytes); + y = new BigInteger(1, xBytes); + } + while (!(y.compareTo(TWO) >= 0 && y.compareTo(p_minus_2) <= 0)); + + ZZ = m1.modPow(y, p); // ZZ = (yb ^ xa) mod p + + complete = true; + + // B sends A the message: g^y mod p + OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(g.modPow(y, p)); // message (2) + + return result; + } +} diff --git a/gnu/javax/crypto/key/dh/DiffieHellmanSender.java b/gnu/javax/crypto/key/dh/DiffieHellmanSender.java new file mode 100644 index 000000000..71838fdac --- /dev/null +++ b/gnu/javax/crypto/key/dh/DiffieHellmanSender.java @@ -0,0 +1,156 @@ +/* DiffieHellmanSender.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.prng.IRandom; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + *

This implementation is the sender's part of the basic version of the + * Diffie-Hellman key agreement exchange (A in [HAC]).

+ * + * @see DiffieHellmanKeyAgreement + * @version $Revision: 1.1.4.1 $ + */ +public class DiffieHellmanSender extends DiffieHellmanKeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private BigInteger x; // the sender's random secret + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + protected void engineInit(Map attributes) throws KeyAgreementException + { + Object random = attributes.get(SOURCE_OF_RANDOMNESS); + rnd = null; + irnd = null; + if (random instanceof SecureRandom) + { + rnd = (SecureRandom) random; + } + else if (random instanceof IRandom) + { + irnd = (IRandom) random; + } + ownerKey = (DHPrivateKey) attributes.get(KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY); + if (ownerKey == null) + { + throw new KeyAgreementException("missing owner's private key"); + } + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendRandomSecret(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + // own methods ------------------------------------------------------------- + + private OutgoingMessage sendRandomSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger p = ownerKey.getParams().getP(); + BigInteger g = ownerKey.getParams().getG(); + + // A chooses a random integer x, 1 <= x <= p-2 + // rfc-2631 restricts x to only be in [2, p-1] + BigInteger p_minus_2 = p.subtract(TWO); + byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8]; + do + { + nextRandomBytes(xBytes); + x = new BigInteger(1, xBytes); + } + while (!(x.compareTo(TWO) >= 0 && x.compareTo(p_minus_2) <= 0)); + + // A sends B the message: g^x mod p + OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(g.modPow(x, p)); + + return result; + } + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger m1 = in.readMPI(); + if (m1 == null) + { + throw new KeyAgreementException("missing message (2)"); + } + + BigInteger p = ownerKey.getParams().getP(); + ZZ = m1.modPow(x, p); // ZZ = (yb ^ xa) mod p + + complete = true; + return null; + } +} diff --git a/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java b/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java new file mode 100644 index 000000000..1c4e11ce2 --- /dev/null +++ b/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java @@ -0,0 +1,130 @@ +/* ElGamalKeyAgreement.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.BaseKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementException; + +import java.math.BigInteger; + +/** + *

The ElGamal key agreement, also known as the half-certified Diffie-Hellman + * key agreement, is described in the Handbook of Applied Cryptography [HAC] as + * follows:

+ *
    + *
  • A sends to B a single message allowing one-pass key agreement.
  • + *
  • A obtains an authentic copy of B's public key (p, g, yb), where + * yb = g**xb.
  • + *
  • A chooses a random integer x, 1 <= x <= p-2, and sends B the + * message g**x. A computes the shared secret key K as yb**x.
  • + *
  • B computes the same key K on receipt of the previous message as + * (g**x)**xb.
  • + *
+ * + *

RFC-2631 describes an Ephemeral-Static Mode of operations with + * Diffie-Hellman keypairs as follows:

+ *
+ * "In Ephemeral-Static mode, the recipient has a static (and certified)
+ * key pair, but the sender generates a new key pair for each message
+ * and sends it using the originatorKey production. If the sender's key
+ * is freshly generated for each message, the shared secret ZZ will be
+ * similarly different for each message and partyAInfo MAY be omitted,
+ * since it serves merely to decouple multiple KEKs generated by the
+ * same set of pairwise keys. If, however, the same ephemeral sender key
+ * is used for multiple messages (e.g. it is cached as a performance
+ * optimization) then a separate partyAInfo MUST be used for each
+ * message. All implementations of this standard MUST implement
+ * Ephemeral-Static mode."
+ * 
+ * + *

Reference:

+ *
    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
  3. [HAC]: Handbook of + * Applied Cryptography.
    + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997
    + * Menezes, A., van Oorschot, P. and S. Vanstone.
  4. + *
+ */ +public abstract class ElGamalKeyAgreement extends BaseKeyAgreementParty +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.elgamal.ka.prng"; + + public static final String KA_ELGAMAL_RECIPIENT_PRIVATE_KEY = "gnu.crypto.elgamal.ka.recipient.private.key"; + + public static final String KA_ELGAMAL_RECIPIENT_PUBLIC_KEY = "gnu.crypto.elgamal.ka.recipient.public.key"; + + /** The shared secret key. */ + protected BigInteger ZZ; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected ElGamalKeyAgreement() + { + super(Registry.ELGAMAL_KA); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of common abstract methods in BaseKeyAGreementParty ------ + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(ZZ); + } + + protected void engineReset() + { + ZZ = null; + } +} diff --git a/gnu/javax/crypto/key/dh/ElGamalReceiver.java b/gnu/javax/crypto/key/dh/ElGamalReceiver.java new file mode 100644 index 000000000..24776cba1 --- /dev/null +++ b/gnu/javax/crypto/key/dh/ElGamalReceiver.java @@ -0,0 +1,121 @@ +/* ElGamalReceiver.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + *

This implementation is the receiver's part of the ElGamal key agreement + * exchange (B in [HAC]).

+ * + * @see ElGamalKeyAgreement + */ +public class ElGamalReceiver extends ElGamalKeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The recipient's private key. */ + private DHPrivateKey B; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + protected void engineInit(Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // One-time setup (key generation and publication). Each user B generates + // a keypair and publishes its public key + B = (DHPrivateKey) attributes.get(KA_ELGAMAL_RECIPIENT_PRIVATE_KEY); + if (B == null) + { + throw new KeyAgreementException("missing recipient private key"); + } + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + // own methods ------------------------------------------------------------- + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + // (b) B computes the same key on receipt of message (1) as + // K = (g^x)^xb mod p + BigInteger m1 = in.readMPI(); + if (m1 == null) + { + throw new KeyAgreementException("missing message (1)"); + } + + ZZ = m1.modPow(B.getX(), B.getParams().getP()); // ZZ = (ya ^ xb) mod p + + complete = true; + return null; + } +} diff --git a/gnu/javax/crypto/key/dh/ElGamalSender.java b/gnu/javax/crypto/key/dh/ElGamalSender.java new file mode 100644 index 000000000..a2de80a67 --- /dev/null +++ b/gnu/javax/crypto/key/dh/ElGamalSender.java @@ -0,0 +1,134 @@ +/* ElGamalSender.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.interfaces.DHPublicKey; + +/** + *

This implementation is the sender's part of the ElGamal key agreement + * exchange (A in [HAC]).

+ * + * @see ElGamalKeyAgreement + */ +public class ElGamalSender extends ElGamalKeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The recipient's public key. */ + private DHPublicKey B; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + protected void engineInit(Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // One-time setup (key generation and publication). Each user B generates + // a keypair and publishes its public key + B = (DHPublicKey) attributes.get(KA_ELGAMAL_RECIPIENT_PUBLIC_KEY); + if (B == null) + { + throw new KeyAgreementException("missing recipient public key"); + } + } + + protected OutgoingMessage engineProcessMessage(IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + // own methods ------------------------------------------------------------- + + private OutgoingMessage computeSharedSecret(IncomingMessage in) + throws KeyAgreementException + { + BigInteger p = B.getParams().getP(); + BigInteger g = B.getParams().getG(); + BigInteger yb = B.getY(); + + // A chooses a random integer x, 1 <= x <= p-2 + // rfc-2631 restricts x to only be in [2, p-1] + BigInteger p_minus_2 = p.subtract(TWO); + byte[] xBytes = new byte[(p_minus_2.bitLength() + 7) / 8]; + BigInteger x; + do + { + nextRandomBytes(xBytes); + x = new BigInteger(1, xBytes); + } + while (x.compareTo(TWO) >= 0 && x.compareTo(p_minus_2) <= 0); + + // A sends B the message: g^x mod p + OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(g.modPow(x, p)); + + // A computes the key as K = (yb)^x mod p + ZZ = yb.modPow(x, p); // ZZ = (yb ^ xa) mod p + + complete = true; + return result; + } +} diff --git a/gnu/javax/crypto/key/dh/GnuDHKey.java b/gnu/javax/crypto/key/dh/GnuDHKey.java new file mode 100644 index 000000000..f1e42d93a --- /dev/null +++ b/gnu/javax/crypto/key/dh/GnuDHKey.java @@ -0,0 +1,184 @@ +/* GnuDHKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.util.FormatUtil; + +import java.math.BigInteger; +import java.security.Key; + +import javax.crypto.interfaces.DHKey; +import javax.crypto.spec.DHParameterSpec; + +/** + *

A base asbtract class for both public and private Diffie-Hellman keys. It + * encapsulates the two DH numbers: p, and g.

+ * + *

According to the JDK, cryptographic Keys all have a format. + * The format used in this implementation is called Raw, and basically + * consists of the raw byte sequences of algorithm parameters. The exact order + * of the byte sequences and the implementation details are given in each of + * the relevant getEncoded() methods of each of the private and + * public keys.

+ * + *

Reference:

+ *
    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
+ */ +public abstract class GnuDHKey implements Key, DHKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The public prime q. A prime divisor of p-1. */ + protected BigInteger q; + + /** The public prime p. */ + protected BigInteger p; + + /** The generator g. */ + protected BigInteger g; + + /** + * Identifier of the default encoding format to use when externalizing the + * key material. + */ + protected final int defaultFormat; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial protected constructor. + * + * @param defaultFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + */ + protected GnuDHKey(int defaultFormat, BigInteger q, BigInteger p, BigInteger g) + { + super(); + + this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID + : defaultFormat; + this.q = q; + this.p = p; + this.g = g; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // javax.crypto.interfaces.DHKey interface implementation ------------------ + + public DHParameterSpec getParams() + { + if (q == null) + { + return new DHParameterSpec(p, g); + } + else + { + return new DHParameterSpec(p, g, q.bitLength()); + } + } + + // java.security.Key interface implementation ------------------------------ + + public String getAlgorithm() + { + return Registry.DH_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(defaultFormat); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + // Other instance methods -------------------------------------------------- + + public BigInteger getQ() + { + return q; + } + + /** + *

Returns true if the designated object is an instance of + * {@link DHKey} and has the same Diffie-Hellman parameter values as this + * one.

+ * + * @param obj the other non-null DH key to compare to. + * @return true if the designated object is of the same type and + * value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (!(obj instanceof DHKey)) + { + return false; + } + DHKey that = (DHKey) obj; + return p.equals(that.getParams().getP()) + && g.equals(that.getParams().getG()); + } + + // abstract methods to be implemented by subclasses ------------------------ + + public abstract byte[] getEncoded(int format); +} diff --git a/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java b/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java new file mode 100644 index 000000000..eafc8d01c --- /dev/null +++ b/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java @@ -0,0 +1,290 @@ +/* GnuDHKeyPairGenerator.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.hash.Sha160; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.io.PrintWriter; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.spec.DHGenParameterSpec; +import javax.crypto.spec.DHParameterSpec; + +/** + *

An implementation of a Diffie-Hellman keypair generator.

+ * + *

Reference:

+ *
    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
+ */ +public class GnuDHKeyPairGenerator implements IKeyPairGenerator +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "dh"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 5; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.prng"; + + /** + * Property name of an optional {@link DHGenParameterSpec} or + * {@link DHParameterSpec} instance to use for this generator. + */ + public static final String DH_PARAMETERS = "gnu.crypto.dh.params"; + + /** Property name of the size in bits (Integer) of the public prime (p). */ + public static final String PRIME_SIZE = "gnu.crypto.dh.L"; + + /** Property name of the size in bits (Integer) of the private exponent (x). */ + public static final String EXPONENT_SIZE = "gnu.crypto.dh.m"; + + /** + * Property name of the preferred encoding format to use when externalizing + * generated instance of key-pairs from this generator. The property is taken + * to be an {@link Integer} that encapsulates an encoding format identifier. + */ + public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dh.encoding"; + + /** Default value for the size in bits of the public prime (p). */ + // private static final int DEFAULT_PRIME_SIZE = 1024; + public static final int DEFAULT_PRIME_SIZE = 512; + + /** Default value for the size in bits of the private exponent (x). */ + public static final int DEFAULT_EXPONENT_SIZE = 160; + + /** Default encoding format to use when none was specified. */ + private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID; + + /** The SHA instance to use. */ + private Sha160 sha = new Sha160(); + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + /** The desired size in bits of the public prime (p). */ + private int l; + + /** The desired size in bits of the private exponent (x). */ + private int m; + + private BigInteger seed; + + private BigInteger counter; + + private BigInteger q; + + private BigInteger p; + + private BigInteger j; + + private BigInteger g; + + /** Our default source of randomness. */ + private PRNG prng = null; + + /** Preferred encoding format of generated keys. */ + private int preferredFormat; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.keys.IKeyPairGenerator interface implementation --------------- + + public String name() + { + return Registry.DH_KPG; + } + + public void setup(Map attributes) + { + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + + // are we given a set of Diffie-Hellman generation parameters or we shall + // use our own? + Object params = attributes.get(DH_PARAMETERS); + + // find out the desired sizes + if (params instanceof DHGenParameterSpec) + { + DHGenParameterSpec jceSpec = (DHGenParameterSpec) params; + l = jceSpec.getPrimeSize(); + m = jceSpec.getExponentSize(); + } + else if (params instanceof DHParameterSpec) + { + DHParameterSpec jceSpec = (DHParameterSpec) params; + l = jceSpec.getP().bitLength(); + m = jceSpec.getL(); + } + else + { + Integer bi = (Integer) attributes.get(PRIME_SIZE); + l = (bi == null ? DEFAULT_PRIME_SIZE : bi.intValue()); + bi = (Integer) attributes.get(EXPONENT_SIZE); + m = (bi == null ? DEFAULT_EXPONENT_SIZE : bi.intValue()); + } + + // if ((L % 256) != 0 || L < 1024) { + if ((l % 256) != 0 || l < DEFAULT_PRIME_SIZE) + { + throw new IllegalArgumentException("invalid modulus size"); + } + if ((m % 8) != 0 || m < DEFAULT_EXPONENT_SIZE) + { + throw new IllegalArgumentException("invalid exponent size"); + } + if (m > l) + { + throw new IllegalArgumentException("exponent size > modulus size"); + } + + // what is the preferred encoding format + Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT); + preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT + : formatID.intValue(); + } + + public KeyPair generate() + { + if (p == null) + { + BigInteger[] params = new RFC2631(m, l, rnd).generateParameters(); + seed = params[RFC2631.DH_PARAMS_SEED]; + counter = params[RFC2631.DH_PARAMS_COUNTER]; + q = params[RFC2631.DH_PARAMS_Q]; + p = params[RFC2631.DH_PARAMS_P]; + j = params[RFC2631.DH_PARAMS_J]; + g = params[RFC2631.DH_PARAMS_G]; + if (DEBUG && debuglevel > 0) + { + debug("seed: 0x" + seed.toString(16)); + debug("counter: " + counter.intValue()); + debug("q: 0x" + q.toString(16)); + debug("p: 0x" + p.toString(16)); + debug("j: 0x" + j.toString(16)); + debug("g: 0x" + g.toString(16)); + } + } + + // generate a private number x of length m such as: 1 < x < q - 1 + BigInteger q_minus_1 = q.subtract(BigInteger.ONE); + byte[] mag = new byte[(m + 7) / 8]; + BigInteger x; + while (true) + { + nextRandomBytes(mag); + x = new BigInteger(1, mag); + if (x.bitLength() == m && x.compareTo(BigInteger.ONE) > 0 + && x.compareTo(q_minus_1) < 0) + { + break; + } + } + BigInteger y = g.modPow(x, p); + + PrivateKey secK = new GnuDHPrivateKey(preferredFormat, q, p, g, x); + PublicKey pubK = new GnuDHPublicKey(preferredFormat, q, p, g, y); + + return new KeyPair(pubK, secK); + } + + // other methods ----------------------------------------------------------- + + /** + *

Fills the designated byte array with random data.

+ * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java b/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java new file mode 100644 index 000000000..0e71623b9 --- /dev/null +++ b/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java @@ -0,0 +1,196 @@ +/* GnuDHPrivateKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPrivateKey; + +/** + *

An implementation of the Diffie-Hellman private key.

+ * + *

Reference:

+ *
    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
+ */ +public class GnuDHPrivateKey extends GnuDHKey implements DHPrivateKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The private exponent. */ + private final BigInteger x; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Convenience constructor. Calls the constructor with five arguments passing + * {@link Registry#RAW_ENCODING_ID} as the value of its first argument. + * + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param x the private value x. + */ + public GnuDHPrivateKey(BigInteger q, BigInteger p, BigInteger g, BigInteger x) + { + this(Registry.RAW_ENCODING_ID, q, p, g, x); + } + + /** + * Constructs a new instance of GnuDHPrivateKey given the + * designated parameters. + * + * @param preferredFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param x the private value x. + */ + public GnuDHPrivateKey(int preferredFormat, + BigInteger q, BigInteger p, BigInteger g, BigInteger x) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID + : preferredFormat, + q, p, g); + + this.x = x; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

A class method that takes the output of the encodePrivateKey() + * method of a DH keypair codec object (an instance implementing + * {@link IKeyPairCodec} for DH keys, and re-constructs an instance of this + * object.

+ * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, + * in k, to represent a valid encoding of an instance of + * this object. + * @exception IllegalArgumentException if the byte sequence does not + * represent a valid encoding of an instance of this object. + */ + public static GnuDHPrivateKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]) + try + { + return (GnuDHPrivateKey) new DHKeyPairRawCodec().decodePrivateKey(k); + } + catch (IllegalArgumentException ignored) + { + } + + // try PKCS#8 codec + return (GnuDHPrivateKey) new DHKeyPairPKCS8Codec().decodePrivateKey(k); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // javax.crypto.interfaces.DHPrivateKey interface implementation ----------- + + public BigInteger getX() + { + return x; + } + + // other methods ----------------------------------------------------------- + + /** + *

Returns the encoded form of this private key according to the + * designated format.

+ * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + * @see gnu.crypto.key.dh.DHKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DHKeyPairRawCodec().encodePrivateKey(this); + break; + case IKeyPairCodec.PKCS8_FORMAT: + result = new DHKeyPairPKCS8Codec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of + * {@link DHPrivateKey} and has the same parameter values as this one. + * + * @param obj the other non-null DH key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof DHPrivateKey)) + return false; + + DHPrivateKey that = (DHPrivateKey) obj; + return super.equals(that) && x.equals(that.getX()); + } +} diff --git a/gnu/javax/crypto/key/dh/GnuDHPublicKey.java b/gnu/javax/crypto/key/dh/GnuDHPublicKey.java new file mode 100644 index 000000000..56516c9d0 --- /dev/null +++ b/gnu/javax/crypto/key/dh/GnuDHPublicKey.java @@ -0,0 +1,194 @@ +/* GnuDHPublicKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPublicKey; + +/** + *

An implementation of the Diffie-Hellman public key.

+ * + *

Reference:

+ *
    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
+ */ +public class GnuDHPublicKey extends GnuDHKey implements DHPublicKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private BigInteger y; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Convenience constructor. Calls the constructor with five arguments passing + * {@link Registry#RAW_ENCODING_ID} as the value of its first argument. + * + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param y the public value y. + */ + public GnuDHPublicKey(BigInteger q, BigInteger p, BigInteger g, BigInteger y) + { + this(Registry.RAW_ENCODING_ID, q, p, g, y); + } + + /** + * Constructs a new instance of GnuDHPublicKey given the + * designated parameters. + * + * @param preferredFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param q a prime divisor of p-1. + * @param p the public prime. + * @param g the generator of the group. + * @param y the public value y. + */ + public GnuDHPublicKey(int preferredFormat, + BigInteger q, BigInteger p, BigInteger g, BigInteger y) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID + : preferredFormat, + q, p, g); + + this.y = y; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

A class method that takes the output of the encodePublicKey() + * method of a DH keypair codec object (an instance implementing + * {@link IKeyPairCodec} for DSS keys, and re-constructs an instance of this + * object.

+ * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, + * in k, to represent a valid encoding of an instance of this + * object. + * @exception IllegalArgumentException if the byte sequence does not + * represent a valid encoding of an instance of this object. + */ + public static GnuDHPublicKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DH_PUBLIC_KEY[0]) + try + { + return (GnuDHPublicKey) new DHKeyPairRawCodec().decodePublicKey(k); + } + catch (IllegalArgumentException ignored) + { + } + + // try X.509 codec + return (GnuDHPublicKey) new DHKeyPairX509Codec().decodePublicKey(k); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // javax.crypto.interfaces.DHPublicKey interface implementation ------------ + + public BigInteger getY() + { + return y; + } + + // other methods ----------------------------------------------------------- + + /** + *

Returns the encoded form of this public key according to the designated + * format.

+ * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DHKeyPairRawCodec().encodePublicKey(this); + break; + case IKeyPairCodec.X509_FORMAT: + result = new DHKeyPairX509Codec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of + * {@link DHPublicKey} and has the same parameter values as this one. + * + * @param obj the other non-null DH key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof DHPublicKey)) + return false; + + DHPublicKey that = (DHPublicKey) obj; + return super.equals(that) && y.equals(that.getY()); + } +} diff --git a/gnu/javax/crypto/key/dh/RFC2631.java b/gnu/javax/crypto/key/dh/RFC2631.java new file mode 100644 index 000000000..d6e30b4bc --- /dev/null +++ b/gnu/javax/crypto/key/dh/RFC2631.java @@ -0,0 +1,255 @@ +/* RFC2631.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.dh; + +import gnu.java.security.hash.Sha160; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Prime2; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + *

An implementation of the Diffie-Hellman parameter generation as defined in + * RFC-2631.

+ * + *

Reference:

+ *
    + *
  1. Diffie-Hellman Key + * Agreement Method
    + * Eric Rescorla.
  2. + *
+ */ +public class RFC2631 +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int DH_PARAMS_SEED = 0; + + public static final int DH_PARAMS_COUNTER = 1; + + public static final int DH_PARAMS_Q = 2; + + public static final int DH_PARAMS_P = 3; + + public static final int DH_PARAMS_J = 4; + + public static final int DH_PARAMS_G = 5; + + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** The SHA instance to use. */ + private Sha160 sha = new Sha160(); + + /** Length of private modulus and of q. */ + private int m; + + /** Length of public modulus p. */ + private int L; + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + /** Our default source of randomness. */ + private PRNG prng = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public RFC2631(int m, int L, SecureRandom rnd) + { + super(); + + this.m = m; + this.L = L; + this.rnd = rnd; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public BigInteger[] generateParameters() + { + int i, j, counter; + byte[] u1, u2, v; + byte[] seedBytes = new byte[m / 8]; + BigInteger SEED, U, q, R, V, W, X, p, g; + // start by genrating p and q, where q is of length m and p is of length L + // 1. Set m' = m/160 where / represents integer division with rounding + // upwards. I.e. 200/160 = 2. + int m_ = (m + 159) / 160; + // 2. Set L'= L/160 + int L_ = (L + 159) / 160; + // 3. Set N'= L/1024 + int N_ = (L + 1023) / 1024; + algorithm: while (true) + { + step4: while (true) + { + // 4. Select an arbitrary bit string SEED such that length of SEED >= m + nextRandomBytes(seedBytes); + SEED = new BigInteger(1, seedBytes).setBit(m - 1).setBit(0); + // 5. Set U = 0 + U = BigInteger.ZERO; + // 6. For i = 0 to m' - 1 + // U = U + (SHA1[SEED + i] XOR SHA1[(SEED + m' + i)) * 2^(160 * i) + // Note that for m=160, this reduces to the algorithm of [FIPS-186] + // U = SHA1[SEED] XOR SHA1[(SEED+1) mod 2^160 ]. + for (i = 0; i < m_; i++) + { + u1 = SEED.add(BigInteger.valueOf(i)).toByteArray(); + u2 = SEED.add(BigInteger.valueOf(m_ + i)).toByteArray(); + sha.update(u1, 0, u1.length); + u1 = sha.digest(); + sha.update(u2, 0, u2.length); + u2 = sha.digest(); + for (j = 0; j < u1.length; j++) + { + u1[j] ^= u2[j]; + } + U = U.add(new BigInteger(1, u1).multiply(TWO.pow(160 * i))); + } + // 5. Form q from U by computing U mod (2^m) and setting the most + // significant bit (the 2^(m-1) bit) and the least significant bit to + // 1. In terms of boolean operations, q = U OR 2^(m-1) OR 1. Note + // that 2^(m-1) < q < 2^m + q = U.setBit(m - 1).setBit(0); + // 6. Use a robust primality algorithm to test whether q is prime. + // 7. If q is not prime then go to 4. + if (Prime2.isProbablePrime(q)) + { + break step4; + } + } + // 8. Let counter = 0 + counter = 0; + step9: while (true) + { + // 9. Set R = seed + 2*m' + (L' * counter) + R = SEED.add(BigInteger.valueOf(2 * m_)).add( + BigInteger.valueOf(L_ + * counter)); + // 10. Set V = 0 + V = BigInteger.ZERO; + // 12. For i = 0 to L'-1 do: V = V + SHA1(R + i) * 2^(160 * i) + for (i = 0; i < L_; i++) + { + v = R.toByteArray(); + sha.update(v, 0, v.length); + v = sha.digest(); + V = V.add(new BigInteger(1, v).multiply(TWO.pow(160 * i))); + } + // 13. Set W = V mod 2^L + W = V.mod(TWO.pow(L)); + // 14. Set X = W OR 2^(L-1) + // Note that 0 <= W < 2^(L-1) and hence X >= 2^(L-1) + X = W.setBit(L - 1); + // 15. Set p = X - (X mod (2*q)) + 1 + p = X.add(BigInteger.ONE).subtract(X.mod(TWO.multiply(q))); + // 16. If p > 2^(L-1) use a robust primality test to test whether p is + // prime. Else go to 18. + //17. If p is prime output p, q, seed, counter and stop. + if (Prime2.isProbablePrime(p)) + { + break algorithm; + } + // 18. Set counter = counter + 1 + counter++; + // 19. If counter < (4096 * N) then go to 8. + // 20. Output "failure" + if (counter >= 4096 * N_) + { + continue algorithm; + } + } + } + + // compute g. from FIPS-186, Appendix 4: + // 1. Generate p and q as specified in Appendix 2. + // 2. Let e = (p - 1) / q + BigInteger e = p.subtract(BigInteger.ONE).divide(q); + BigInteger h = TWO; + BigInteger p_minus_1 = p.subtract(BigInteger.ONE); + g = TWO; + // 3. Set h = any integer, where 1 < h < p - 1 and h differs from any + // value previously tried + for (; h.compareTo(p_minus_1) < 0; h = h.add(BigInteger.ONE)) + { + // 4. Set g = h**e mod p + g = h.modPow(e, p); + // 5. If g = 1, go to step 3 + if (!g.equals(BigInteger.ONE)) + { + break; + } + } + + return new BigInteger[] { SEED, BigInteger.valueOf(counter), q, p, e, g }; + } + + // helper methods ---------------------------------------------------------- + + /** + *

Fills the designated byte array with random data.

+ * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6Host.java b/gnu/javax/crypto/key/srp6/SRP6Host.java new file mode 100644 index 000000000..192e877b7 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6Host.java @@ -0,0 +1,213 @@ +/* SRP6Host.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.sasl.srp.SRP; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPRegistry; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + *

The implementation of the Host in the SRP-6 key agreement protocol.

+ * + *

Reference:

+ *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRP6Host extends SRP6KeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The user's ephemeral key pair. */ + private KeyPair hostKeyPair; + + /** The SRP password database. */ + private SRPAuthInfoProvider passwordDB; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + N = (BigInteger) attributes.get(SHARED_MODULUS); + if (N == null) + { + throw new KeyAgreementException("missing shared modulus"); + } + g = (BigInteger) attributes.get(GENERATOR); + if (g == null) + { + throw new KeyAgreementException("missing generator"); + } + + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || "".equals(md.trim())) + { + throw new KeyAgreementException("missing hash function"); + } + srp = SRP.instance(md); + + passwordDB = (SRPAuthInfoProvider) attributes.get(HOST_PASSWORD_DB); + if (passwordDB == null) + { + throw new KeyAgreementException("missing SRP password database"); + } + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + hostKeyPair = null; + super.engineReset(); + } + + // own methods ------------------------------------------------------------- + + private OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final String I = in.readString(); + final BigInteger A = in.readMPI(); + + // get s and v for user identified by I + // ---------------------------------------------------------------------- + final Map credentials; + try + { + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, I); + userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm()); + credentials = passwordDB.lookup(userID); + } + catch (IOException x) + { + throw new KeyAgreementException("computeSharedSecret()", x); + } + + final BigInteger s = new BigInteger( + 1, + Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD))); + final BigInteger v = new BigInteger( + 1, + Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD))); + + // Map configuration = null; + // try { + // String mode = (String) credentials.get(SRPRegistry.CONFIG_NDX_FIELD); + // configuration = passwordDB.getConfiguration(mode); + // } catch (IOException x) { + // throw new KeyAgreementException("computeSharedSecret()", x); + // } + // + // BigInteger N = new BigInteger(1, Util.fromBase64( + // (String) configuration.get(SRPRegistry.SHARED_MODULUS))); + // BigInteger g = new BigInteger(1, Util.fromBase64( + // (String) configuration.get(SRPRegistry.FIELD_GENERATOR))); + // ---------------------------------------------------------------------- + + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + { + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + } + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v); + kpg.setup(attributes); + hostKeyPair = kpg.generate(); + + final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + + // compute S = (Av^u) ^ b + final BigInteger b = ((SRPPrivateKey) hostKeyPair.getPrivate()).getX(); + final BigInteger S = A.multiply(v.modPow(u, N)).modPow(b, N); + + final byte[] sBytes = Util.trim(S); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + + final OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(s); + result.writeMPI(B); + + complete = true; + return result; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java b/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java new file mode 100644 index 000000000..63c981d80 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java @@ -0,0 +1,172 @@ +/* SRP6KeyAgreement.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.BaseKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.sasl.srp.SRP; + +import java.math.BigInteger; + +/** + *

The Secure Remote Password (SRP) key agreement protocol, also known as + * SRP-6, is designed by Thomas J. Wu (see references). The protocol, and its + * elements are described as follows:

+ * + *
+ * N    A large safe prime (N = 2q+1, where q is prime)
+ *      All arithmetic is done modulo N.
+ * g    A generator modulo N
+ * s    User's salt
+ * I    Username
+ * p    Cleartext Password
+ * H()  One-way hash function
+ * ^    (Modular) Exponentiation
+ * u    Random scrambling parameter
+ * a,b  Secret ephemeral values
+ * A,B  Public ephemeral values
+ * x    Private key (derived from p and s)
+ * v    Password verifier
+ *
+ * The host stores passwords using the following formula:
+ * x = H(s | H(I ":" p))           (s is chosen randomly)
+ * v = g^x                   (computes password verifier)
+ *
+ * The host then keeps {I, s, v} in its password database.
+ *
+ * The authentication protocol itself goes as follows:
+ * User -> Host:  I, A = g^a         (identifies self, a = random number)
+ * Host -> User:  s, B = 3v + g^b    (sends salt, b = random number)
+ *
+ * Both:  u = H(A, B)
+ *
+ * User:  x = H(s, p)                (user enters password)
+ * User:  S = (B - 3g^x) ^ (a + ux)  (computes session key)
+ * User:  K = H(S)
+ *
+ * Host:  S = (Av^u) ^ b             (computes session key)
+ * Host:  K = H(S)
+ * 
+ * + *

Reference:

+ *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public abstract class SRP6KeyAgreement extends BaseKeyAgreementParty +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.srp6.ka.prng"; + + public static final String SHARED_MODULUS = "gnu.crypto.srp6.ka.N"; + + public static final String GENERATOR = "gnu.crypto.srp6.ka.g"; + + public static final String HASH_FUNCTION = "gnu.crypto.srp6.ka.H"; + + public static final String USER_IDENTITY = "gnu.crypto.srp6.ka.I"; + + public static final String USER_PASSWORD = "gnu.crypto.srp6.ka.p"; + + public static final String HOST_PASSWORD_DB = "gnu.crypto.srp6.ka.password.db"; + + protected static final BigInteger THREE = BigInteger.valueOf(3L); + + protected SRP srp; + + protected BigInteger N; + + protected BigInteger g; + + /** The shared secret key. */ + protected BigInteger K; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected SRP6KeyAgreement() + { + super(Registry.SRP6_KA); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of common abstract methods in BaseKeyAGreementParty ------ + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(K); + } + + protected void engineReset() + { + // mda = null; + srp = null; + N = null; + g = null; + K = null; + } + + // helper methods ---------------------------------------------------------- + + protected BigInteger uValue(final BigInteger A, final BigInteger B) + { + // IMessageDigest hash = (IMessageDigest) mda.clone(); + final IMessageDigest hash = srp.newDigest(); + byte[] b; + b = Util.trim(A); + hash.update(b, 0, b.length); + b = Util.trim(B); + hash.update(b, 0, b.length); + + return new BigInteger(1, hash.digest()); + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6SaslClient.java b/gnu/javax/crypto/key/srp6/SRP6SaslClient.java new file mode 100644 index 000000000..ef460b13b --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6SaslClient.java @@ -0,0 +1,101 @@ +/* SRP6SaslClient.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; + +/** + *

A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for + * the User (client side).

+ * + *

In this alternative, the exchange goes as follows:

+ *
+ *    C -> S:  I                      (identifies self)
+ *    S -> C:  N, g, s, B = 3v + g^b  (sends salt, b = random number)
+ *    C -> S:  A = g^a                (a = random number)
+ * 
+ * + *

All elements are computed the same way as in the standard version.

+ * + *

Reference:

+ *
    + *
  1. + * Secure Remote Password Authentication Mechanism
    + * K. Burdis, R. Naffah.
  2. + *
  3. SRP Protocol Design
    + * Thomas J. Wu.
  4. + *
+ */ +public class SRP6SaslClient extends SRP6TLSClient +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final OutgoingMessage result = super.computeSharedSecret(in); + + final byte[] sBytes = Util.trim(K); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + + return result; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6SaslServer.java b/gnu/javax/crypto/key/srp6/SRP6SaslServer.java new file mode 100644 index 000000000..5e759964e --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6SaslServer.java @@ -0,0 +1,101 @@ +/* SRP6SaslServer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; + +import java.math.BigInteger; + +/** + *

A variation of the SRP-6 protocol as used in the SASL-SRP mechanism, for + * the Host (server side).

+ * + *

In this alternative, the exchange goes as follows:

+ *
+ *    C -> S:  I                      (identifies self)
+ *    S -> C:  N, g, s, B = 3v + g^b  (sends salt, b = random number)
+ *    C -> S:  A = g^a                (a = random number)
+ * 
+ * + *

All elements are computed the same way as in the standard version.

+ * + *

Reference:

+ *
    + *
  1. + * Secure Remote Password Authentication Mechanism
    + * K. Burdis, R. Naffah.
  2. + *
  3. SRP Protocol Design
    + * Thomas J. Wu.
  4. + *
+ */ +public class SRP6SaslServer extends SRP6TLSServer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + super.computeSharedSecret(in); + + final byte[] sBytes = Util.trim(K); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + + return null; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6TLSClient.java b/gnu/javax/crypto/key/srp6/SRP6TLSClient.java new file mode 100644 index 000000000..5474a1e8e --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6TLSClient.java @@ -0,0 +1,191 @@ +/* SRP6TLSClient.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.sasl.srp.SRP; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + *

A variation of the SRP6 key agreement protocol, for the client-side as + * proposed in + * Using + * SRP for TLS Authentication. The only difference between it and the SASL + * variant is that the shared secret is the entity S and not + * H(S).

+ */ +public class SRP6TLSClient extends SRP6KeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The user's identity. */ + private String I; + + /** The user's cleartext password. */ + private byte[] p; + + /** The user's ephemeral key pair. */ + private KeyPair userKeyPair; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || "".equals(md.trim())) + { + throw new KeyAgreementException("missing hash function"); + } + srp = SRP.instance(md); + + I = (String) attributes.get(USER_IDENTITY); + if (I == null) + { + throw new KeyAgreementException("missing user identity"); + } + p = (byte[]) attributes.get(USER_PASSWORD); + if (p == null) + { + throw new KeyAgreementException("missing user password"); + } + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendIdentity(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + I = null; + p = null; + userKeyPair = null; + super.engineReset(); + } + + // own methods ------------------------------------------------------------- + + private OutgoingMessage sendIdentity(final IncomingMessage in) + throws KeyAgreementException + { + final OutgoingMessage result = new OutgoingMessage(); + result.writeString(I); + + return result; + } + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + N = in.readMPI(); + g = in.readMPI(); + final BigInteger s = in.readMPI(); + final BigInteger B = in.readMPI(); + + // generate an ephemeral keypair + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + { + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + } + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + kpg.setup(attributes); + userKeyPair = kpg.generate(); + + final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + final BigInteger x; + try + { + x = new BigInteger(1, srp.computeX(Util.trim(s), I, p)); + } + catch (Exception e) + { + throw new KeyAgreementException("computeSharedSecret()", e); + } + + // compute S = (B - 3g^x) ^ (a + ux) + final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX(); + final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N))).modPow( + a.add(u.multiply(x)), + N); + + K = S; + + final OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(A); + + complete = true; + return result; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6TLSServer.java b/gnu/javax/crypto/key/srp6/SRP6TLSServer.java new file mode 100644 index 000000000..718646012 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6TLSServer.java @@ -0,0 +1,220 @@ +/* SRP6TLSServer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.sasl.srp.SRP; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPRegistry; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + *

A variation of the SRP6 key agreement protocol, for the server-side as + * proposed in + * Using + * SRP for TLS Authentication. The only difference between it and the SASL + * variant is that the shared secret is the entity S and not + * H(S).

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class SRP6TLSServer extends SRP6KeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The user's ephemeral key pair. */ + private KeyPair hostKeyPair; + + /** The SRP password database. */ + private SRPAuthInfoProvider passwordDB; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || "".equals(md.trim())) + { + throw new KeyAgreementException("missing hash function"); + } + srp = SRP.instance(md); + + passwordDB = (SRPAuthInfoProvider) attributes.get(HOST_PASSWORD_DB); + if (passwordDB == null) + { + throw new KeyAgreementException("missing SRP password database"); + } + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendParameters(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + hostKeyPair = null; + super.engineReset(); + } + + // own methods ------------------------------------------------------------- + + private OutgoingMessage sendParameters(final IncomingMessage in) + throws KeyAgreementException + { + final String I = in.readString(); + + // get s and v for user identified by I + // ---------------------------------------------------------------------- + final Map credentials; + try + { + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, I); + userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm()); + credentials = passwordDB.lookup(userID); + } + catch (IOException x) + { + throw new KeyAgreementException("computeSharedSecret()", x); + } + + final BigInteger s = new BigInteger( + 1, + Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD))); + final BigInteger v = new BigInteger( + 1, + Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD))); + + final Map configuration; + try + { + final String mode = (String) credentials.get(SRPRegistry.CONFIG_NDX_FIELD); + configuration = passwordDB.getConfiguration(mode); + } + catch (IOException x) + { + throw new KeyAgreementException("computeSharedSecret()", x); + } + + N = new BigInteger( + 1, + Util.fromBase64((String) configuration.get(SRPRegistry.SHARED_MODULUS))); + g = new BigInteger( + 1, + Util.fromBase64((String) configuration.get(SRPRegistry.FIELD_GENERATOR))); + // ---------------------------------------------------------------------- + + // generate an ephemeral keypair + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + { + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + } + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v); + kpg.setup(attributes); + hostKeyPair = kpg.generate(); + + final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY(); + + final OutgoingMessage result = new OutgoingMessage(); + result.writeMPI(N); + result.writeMPI(g); + result.writeMPI(s); + result.writeMPI(B); + + return result; + } + + protected OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final BigInteger A = in.readMPI(); + + final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + + // compute S = (Av^u) ^ b + final BigInteger b = ((SRPPrivateKey) hostKeyPair.getPrivate()).getX(); + final BigInteger v = ((SRPPrivateKey) hostKeyPair.getPrivate()).getV(); + final BigInteger S = A.multiply(v.modPow(u, N)).modPow(b, N); + + K = S; + + complete = true; + return null; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRP6User.java b/gnu/javax/crypto/key/srp6/SRP6User.java new file mode 100644 index 000000000..d300d6f76 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRP6User.java @@ -0,0 +1,203 @@ +/* SRP6User.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.sasl.srp.SRP; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; + +/** + *

The implementation of the User in the SRP-6 protocol.

+ * + *

Reference:

+ *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRP6User extends SRP6KeyAgreement +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The user's identity. */ + private String I; + + /** The user's cleartext password. */ + private byte[] p; + + /** The user's ephemeral key pair. */ + private KeyPair userKeyPair; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // implementation of abstract methods in base class ------------------------ + + protected void engineInit(final Map attributes) throws KeyAgreementException + { + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + N = (BigInteger) attributes.get(SHARED_MODULUS); + if (N == null) + { + throw new KeyAgreementException("missing shared modulus"); + } + g = (BigInteger) attributes.get(GENERATOR); + if (g == null) + { + throw new KeyAgreementException("missing generator"); + } + + final String md = (String) attributes.get(HASH_FUNCTION); + if (md == null || "".equals(md.trim())) + { + throw new KeyAgreementException("missing hash function"); + } + srp = SRP.instance(md); + + I = (String) attributes.get(USER_IDENTITY); + if (I == null) + { + throw new KeyAgreementException("missing user identity"); + } + p = (byte[]) attributes.get(USER_PASSWORD); + if (p == null) + { + throw new KeyAgreementException("missing user password"); + } + } + + protected OutgoingMessage engineProcessMessage(final IncomingMessage in) + throws KeyAgreementException + { + switch (step) + { + case 0: + return sendIdentity(in); + case 1: + return computeSharedSecret(in); + default: + throw new IllegalStateException("unexpected state"); + } + } + + protected void engineReset() + { + I = null; + p = null; + userKeyPair = null; + super.engineReset(); + } + + // own methods ------------------------------------------------------------- + + private OutgoingMessage sendIdentity(final IncomingMessage in) + throws KeyAgreementException + { + // generate an ephemeral keypair + final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator(); + final Map attributes = new HashMap(); + if (rnd != null) + { + attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd); + } + attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attributes.put(SRPKeyPairGenerator.GENERATOR, g); + kpg.setup(attributes); + userKeyPair = kpg.generate(); + + final OutgoingMessage result = new OutgoingMessage(); + result.writeString(I); + result.writeMPI(((SRPPublicKey) userKeyPair.getPublic()).getY()); + + return result; + } + + private OutgoingMessage computeSharedSecret(final IncomingMessage in) + throws KeyAgreementException + { + final BigInteger s = in.readMPI(); + final BigInteger B = in.readMPI(); + + final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY(); + final BigInteger u = uValue(A, B); // u = H(A | B) + + final BigInteger x; + try + { + x = new BigInteger(1, srp.computeX(Util.trim(s), I, p)); + } + catch (Exception e) + { + throw new KeyAgreementException("computeSharedSecret()", e); + } + + // compute S = (B - 3g^x) ^ (a + ux) + final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX(); + final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N))).modPow( + a.add(u.multiply(x)), + N); + + final byte[] sBytes = Util.trim(S); + final IMessageDigest hash = srp.newDigest(); + hash.update(sBytes, 0, sBytes.length); + K = new BigInteger(1, hash.digest()); + + complete = true; + return null; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRPAlgorithm.java b/gnu/javax/crypto/key/srp6/SRPAlgorithm.java new file mode 100644 index 000000000..b068863ed --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPAlgorithm.java @@ -0,0 +1,175 @@ +/* SRPAlgorithm.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.util.Prime2; +import gnu.javax.crypto.sasl.srp.SRPRegistry; + +import java.math.BigInteger; + +/** + *

Utilities for use with SRP-6 based methods and protocols.

+ * + *

Reference:

+ *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRPAlgorithm +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // lifted from draft-burdis-cat-srp-sasl-09 + public static final BigInteger N_2048 = new BigInteger( + "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050" + + "A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50" + + "E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B8" + + "55F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773B" + + "CA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748" + + "544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6" + + "AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6" + + "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", + 16); + + public static final BigInteger N_1536 = new BigInteger( + "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D" + + "5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DC" + + "DF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC" + + "764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C486" + + "65772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E" + + "5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB", + 16); + + public static final BigInteger N_1280 = new BigInteger( + "D77946826E811914B39401D56A0A7843A8E7575D738C672A090AB1187D690DC4" + + "3872FC06A7B6A43F3B95BEAEC7DF04B9D242EBDC481111283216CE816E004B78" + + "6C5FCE856780D41837D95AD787A50BBE90BD3A9C98AC0F5FC0DE744B1CDE1891" + + "690894BC1F65E00DE15B4B2AA6D87100C9ECC2527E45EB849DEB14BB2049B163" + + "EA04187FD27C1BD9C7958CD40CE7067A9C024F9B7C5A0B4F5003686161F0605B", + 16); + + public static final BigInteger N_1024 = new BigInteger( + "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576" + + "D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD1" + + "5DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC" + + "68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", + 16); + + public static final BigInteger N_768 = new BigInteger( + "B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F40" + + "2653BE7147F00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF" + + "737D9BE9713CEF8D837ADA6380B1093E94B6A529A8C6C2BE33E0867C60C3262B", + 16); + + public static final BigInteger N_640 = new BigInteger( + "C94D67EB5B1A2346E8AB422FC6A0EDAEDA8C7F894C9EEEC42F9ED250FD7F0046" + + "E5AF2CF73D6B2FA26BB08033DA4DE322E144E7A8E9B12A0E4637F6371F34A207" + + "1C4B3836CBEEAB15034460FAA7ADF483", + 16); + + public static final BigInteger N_512 = new BigInteger( + "D4C7F8A2B32C11B8FBA9581EC4BA4F1B04215642EF7355E37C0FC0443EF756EA" + + "2C6B8EEB755A1C723027663CAA265EF785B8FF6A9B35227A52D86633DBDFCA43", + 16); + + public static final BigInteger N_384 = new BigInteger( + "8025363296FB943FCE54BE717E0E2958A02A9672EF561953B2BAA3BAACC3ED57" + + "54EB764C7AB7184578C57D5949CCB41B", + 16); + + public static final BigInteger N_264 = new BigInteger( + "115B8B692E0E045692CF280B436735C77A5A9E8A9E7ED56C965F87DB5B2A2ECE3", + 16); + + private static final BigInteger ZERO = BigInteger.ZERO; + + private static final BigInteger ONE = BigInteger.ONE; + + private static final BigInteger TWO = BigInteger.valueOf(2L); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce usage through class methods. */ + private SRPAlgorithm() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static void checkParams(final BigInteger N, final BigInteger g) + { + // 1. N should be at least 512-bit long + final int blen = N.bitLength(); + if (blen < SRPRegistry.MINIMUM_MODULUS_BITLENGTH) + { + throw new IllegalArgumentException( + "Bit length of N (" + + blen + + ") is too low. Should be at least " + + SRPRegistry.MINIMUM_MODULUS_BITLENGTH); + } + // 2. N should be a prime + if (!Prime2.passEulerCriterion(N)) + { + throw new IllegalArgumentException("N should be prime but isn't"); + } + // 3. N should be of the form 2*q + 1, where q is prime + final BigInteger q = N.subtract(ONE).divide(TWO); + if (!Prime2.passEulerCriterion(q)) + { + throw new IllegalArgumentException("(N-1)/2 should be prime but isn't"); + } + // 4. g**q should be -1 mod N + final BigInteger gq = g.modPow(q, N).add(ONE).mod(N); + if (gq.compareTo(ZERO) != 0) + { + throw new IllegalArgumentException( + "g**q should be -1 (mod N) but isn't"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/javax/crypto/key/srp6/SRPKey.java b/gnu/javax/crypto/key/srp6/SRPKey.java new file mode 100644 index 000000000..202ef33b7 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPKey.java @@ -0,0 +1,170 @@ +/* SRPKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.Serializable; +import java.math.BigInteger; +import java.security.Key; + +/** + *

An abstract representation of a base SRP ephemeral key.

+ * + *

This object encapsulates the two numbers:

+ *
    + *
  • N: A large safe prime (N = 2q+1, where q is prime).
  • + *
  • g: A generator modulo N.
  • + *
+ * + *

Note that in SRP, all arithmetic is done modulo N.

+ * + *

Reference:

+ *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public abstract class SRPKey implements Key, Serializable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The public, Germaine prime, shared modulus. */ + protected final BigInteger N; + + /** The generator. */ + protected final BigInteger g; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected SRPKey(BigInteger N, BigInteger g) + { + super(); + + this.N = N; + this.g = g; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.security.Key interface implementation ------------------------------ + + /** + *

Returns the standard algorithm name for this key.

+ * + * @return the standard algorithm name for this key. + */ + public String getAlgorithm() + { + return Registry.SRP_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(IKeyPairCodec.RAW_FORMAT); + } + + /** + * Returns {@link Registry#RAW_ENCODING_SHORT_NAME} which is the sole format + * supported for this type of keys. + * + * @return {@link Registry#RAW_ENCODING_SHORT_NAME} ALWAYS. + */ + public String getFormat() + { + return Registry.RAW_ENCODING_SHORT_NAME; + } + + // other methods ----------------------------------------------------------- + + /** + *

Returns the public shared modulus.

+ * + * @return N. + */ + public BigInteger getN() + { + return N; + } + + /** + *

Returns the generator.

+ * + * @return g. + */ + public BigInteger getG() + { + return g; + } + + /** + *

Returns true if the designated object is an instance of + * SRPKey and has the same SRP parameter values as this one.

+ * + * @param obj the other non-null SRP key to compare to. + * @return true if the designated object is of the same type and + * value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (!(obj instanceof SRPKey)) + { + return false; + } + SRPKey that = (SRPKey) obj; + return N.equals(that.getN()) && g.equals(that.getG()); + } + + // abstract methods to be implemented by subclasses ------------------------ + + public abstract byte[] getEncoded(int format); +} diff --git a/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java b/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java new file mode 100644 index 000000000..2957fc3c8 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java @@ -0,0 +1,351 @@ +/* SRPKeyPairGenerator.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Prime2; + +import java.io.PrintWriter; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.Map; + +/** + * + * + *

Reference:

+ *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRPKeyPairGenerator implements IKeyPairGenerator +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "srp"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 5; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final BigInteger ZERO = BigInteger.ZERO; + + private static final BigInteger ONE = BigInteger.ONE; + + private static final BigInteger TWO = BigInteger.valueOf(2L); + + private static final BigInteger THREE = BigInteger.valueOf(3L); + + /** Property name of the length (Integer) of the modulus (N) of an SRP key. */ + public static final String MODULUS_LENGTH = "gnu.crypto.srp.L"; + + /** Property name of the Boolean indicating wether or not to use defaults. */ + public static final String USE_DEFAULTS = "gnu.crypto.srp.use.defaults"; + + /** Property name of the modulus (N) of an SRP key. */ + public static final String SHARED_MODULUS = "gnu.crypto.srp.N"; + + /** Property name of the generator (g) of an SRP key. */ + public static final String GENERATOR = "gnu.crypto.srp.g"; + + /** Property name of the user's verifier (v) for a Server SRP key. */ + public static final String USER_VERIFIER = "gnu.crypto.srp.v"; + + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.srp.prng"; + + /** Default value for the modulus length. */ + private static final int DEFAULT_MODULUS_LENGTH = 1024; + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + /** Bit length of the shared modulus. */ + private int l; + + /** The shared public modulus. */ + private BigInteger N; + + /** The Field generator. */ + private BigInteger g; + + /** The user's verifier MPI. */ + private BigInteger v; + + /** Our default source of randomness. */ + private PRNG prng = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.key.IKeyPairGenerator interface implementation --------------- + + public String name() + { + return Registry.SRP_KPG; + } + + public void setup(Map attributes) + { + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + + N = (BigInteger) attributes.get(SHARED_MODULUS); + if (N != null) + { + l = N.bitLength(); + g = (BigInteger) attributes.get(GENERATOR); + if (g == null) + { + g = TWO; + } + SRPAlgorithm.checkParams(N, g); + } + else + { // generate or use default values for N and g + Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS); + if (useDefaults == null) + { + useDefaults = Boolean.TRUE; + } + Integer L = (Integer) attributes.get(MODULUS_LENGTH); + l = DEFAULT_MODULUS_LENGTH; + if (useDefaults.equals(Boolean.TRUE)) + { + if (L != null) + { + l = L.intValue(); + switch (l) + { + case 512: + N = SRPAlgorithm.N_512; + break; + case 640: + N = SRPAlgorithm.N_640; + break; + case 768: + N = SRPAlgorithm.N_768; + break; + case 1024: + N = SRPAlgorithm.N_1024; + break; + case 1280: + N = SRPAlgorithm.N_1280; + break; + case 1536: + N = SRPAlgorithm.N_1536; + break; + case 2048: + N = SRPAlgorithm.N_2048; + break; + default: + throw new IllegalArgumentException( + "unknown default shared modulus bit length"); + } + g = TWO; + l = N.bitLength(); + } + } + else + { // generate new N and g + if (L != null) + { + l = L.intValue(); + if ((l % 256) != 0 || l < 512 || l > 2048) + { + throw new IllegalArgumentException( + "invalid shared modulus bit length"); + } + } + } + } + + // are we using this generator on the server side, or the client side? + v = (BigInteger) attributes.get(USER_VERIFIER); + } + + public KeyPair generate() + { + if (N == null) + { + BigInteger[] params = generateParameters(); + BigInteger q = params[0]; + N = params[1]; + g = params[2]; + if (DEBUG && debuglevel > 0) + { + debug("q: " + q.toString(16)); + debug("N: " + N.toString(16)); + debug("g: " + g.toString(16)); + } + } + + return (v != null ? hostKeyPair() : userKeyPair()); + } + + // helper methods ---------------------------------------------------------- + + private synchronized BigInteger[] generateParameters() + { + // N A large safe prime (N = 2q+1, where q is prime) + // g A generator modulo N + BigInteger q, p, g; + byte[] qBytes = new byte[l / 8]; + do + { + do + { + nextRandomBytes(qBytes); + q = new BigInteger(1, qBytes); + q = q.setBit(0).setBit(l - 2).clearBit(l - 1); + } + while (!Prime2.isProbablePrime(q)); + p = q.multiply(TWO).add(ONE); + } + while (p.bitLength() != l || !Prime2.isProbablePrime(p)); + + // compute g. from FIPS-186, Appendix 4: e == 2 + BigInteger p_minus_1 = p.subtract(ONE); + g = TWO; + // Set h = any integer, where 1 < h < p - 1 and + // h differs from any value previously tried + for (BigInteger h = TWO; h.compareTo(p_minus_1) < 0; h = h.add(ONE)) + { + // Set g = h**2 mod p + g = h.modPow(TWO, p); + // If g = 1, go to step 3 + if (!g.equals(ONE)) + { + break; + } + } + + return new BigInteger[] { q, p, g }; + } + + private KeyPair hostKeyPair() + { + byte[] bBytes = new byte[(l + 7) / 8]; + BigInteger b, B; + do + { + do + { + nextRandomBytes(bBytes); + b = new BigInteger(1, bBytes); + } + while (b.compareTo(ONE) <= 0 || b.compareTo(N) >= 0); + B = THREE.multiply(v).add(g.modPow(b, N)).mod(N); + } + while (B.compareTo(ZERO) == 0 || B.compareTo(N) >= 0); + + KeyPair result = new KeyPair( + new SRPPublicKey(new BigInteger[] { N, g, B }), + new SRPPrivateKey(new BigInteger[] { N, g, b, + v })); + return result; + } + + private KeyPair userKeyPair() + { + byte[] aBytes = new byte[(l + 7) / 8]; + BigInteger a, A; + do + { + do + { + nextRandomBytes(aBytes); + a = new BigInteger(1, aBytes); + } + while (a.compareTo(ONE) <= 0 || a.compareTo(N) >= 0); + A = g.modPow(a, N); + } + while (A.compareTo(ZERO) == 0 || A.compareTo(N) >= 0); + + KeyPair result = new KeyPair( + new SRPPublicKey(new BigInteger[] { N, g, A }), + new SRPPrivateKey(new BigInteger[] { N, g, a })); + return result; + } + + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + { + rnd.nextBytes(buffer); + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java b/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java new file mode 100644 index 000000000..39234b627 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java @@ -0,0 +1,380 @@ +/* SRPKeyPairRawCodec.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + *

An object that implements the {@link IKeyPairCodec} operations for the + * Raw format to use with SRP keypairs.

+ * + *

Reference:

+ *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRPKeyPairRawCodec implements IKeyPairCodec +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.keys.IKeyPairCodec interface implementation ------------------ + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + *

Returns the encoded form of the designated SRP public key according to + * the Raw format supported by this library.

+ * + *

The Raw format for an SRP public key, in this implementation, is + * a byte sequence consisting of the following:

+ *
    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_SRP_PUBLIC_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the SRP parameter + * N in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter + * N,
  8. + *
  9. 4-byte count of following bytes representing the SRP parameter + * g,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter + * g,
  12. + *
  13. 4-byte count of following bytes representing the SRP parameter + * y,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter + * y,
  16. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not an SRP one. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (!(key instanceof SRPPublicKey)) + { + throw new IllegalArgumentException("key"); + } + + SRPPublicKey srpKey = (SRPPublicKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0]); + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[1]); + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[2]); + baos.write(Registry.MAGIC_RAW_SRP_PUBLIC_KEY[3]); + + // version + baos.write(0x01); + + // N + byte[] buffer = srpKey.getN().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // g + buffer = srpKey.getG().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // y + buffer = srpKey.getY().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + return baos.toByteArray(); + } + + public PublicKey decodePublicKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0] + || k[1] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[1] + || k[2] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[2] + || k[3] != Registry.MAGIC_RAW_SRP_PUBLIC_KEY[3]) + { + throw new IllegalArgumentException("magic"); + } + + // version + if (k[4] != 0x01) + { + throw new IllegalArgumentException("version"); + } + int i = 5; + + int l; + byte[] buffer; + + // N + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger N = new BigInteger(1, buffer); + + // g + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + + // y + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger y = new BigInteger(1, buffer); + + return new SRPPublicKey(N, g, y); + } + + /** + *

Returns the encoded form of the designated SRP private key according to + * the Raw format supported by this library.

+ * + *

The Raw format for an SRP private key, in this implementation, + * is a byte sequence consisting of the following:

+ *
    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_SRP_PRIVATE_KEY},
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the SRP parameter + * N in internet order,
  6. + *
  7. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter + * N,
  8. + *
  9. 4-byte count of following bytes representing the SRP parameter + * g,
  10. + *
  11. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter + * g,
  12. + *
  13. 4-byte count of following bytes representing the SRP parameter + * x,
  14. + *
  15. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter + * x,
  16. + *
  17. one byte which indicates whether the SRP parameter v + * is included in this encoding (value 0x01) or not + * (value 0x00).
  18. + *
  19. 4-byte count of following bytes representing the SRP parameter + * v,
  20. + *
  21. n-bytes representation of a {@link BigInteger} obtained by invoking + * the toByteArray() method on the SRP parameter + * v,
  22. + *
+ * + * @param key the key to encode. + * @return the Raw format encoding of the designated key. + * @throws IllegalArgumentException if the designated key is not an SRP one. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (!(key instanceof SRPPrivateKey)) + { + throw new IllegalArgumentException("key"); + } + + SRPPrivateKey srpKey = (SRPPrivateKey) key; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // magic + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0]); + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[1]); + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[2]); + baos.write(Registry.MAGIC_RAW_SRP_PRIVATE_KEY[3]); + + // version + baos.write(0x01); + + // N + byte[] buffer = srpKey.getN().toByteArray(); + int length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // g + buffer = srpKey.getG().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // x + buffer = srpKey.getX().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + + // v + if (srpKey.getV() != null) + { + baos.write(0x01); + + buffer = srpKey.getV().toByteArray(); + length = buffer.length; + baos.write(length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + } + else + { + baos.write(0x00); + } + + return baos.toByteArray(); + } + + public PrivateKey decodePrivateKey(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0] + || k[1] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[1] + || k[2] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[2] + || k[3] != Registry.MAGIC_RAW_SRP_PRIVATE_KEY[3]) + { + throw new IllegalArgumentException("magic"); + } + + // version + if (k[4] != 0x01) + { + throw new IllegalArgumentException("version"); + } + int i = 5; + + int l; + byte[] buffer; + + // N + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger N = new BigInteger(1, buffer); + + // g + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger g = new BigInteger(1, buffer); + + // x + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger x = new BigInteger(1, buffer); + + // v + l = k[i++]; + if (l == 0x01) + { + l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + buffer = new byte[l]; + System.arraycopy(k, i, buffer, 0, l); + i += l; + BigInteger v = new BigInteger(1, buffer); + + return new SRPPrivateKey(N, g, x, v); + } + else + { + return new SRPPrivateKey(N, g, x); + } + } +} diff --git a/gnu/javax/crypto/key/srp6/SRPPrivateKey.java b/gnu/javax/crypto/key/srp6/SRPPrivateKey.java new file mode 100644 index 000000000..d9f7a19a6 --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPPrivateKey.java @@ -0,0 +1,250 @@ +/* SRPPrivateKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PrivateKey; + +/** + *

A representation of an SRP ephemeral private key.

+ * + *

Reference:

+ *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRPPrivateKey extends SRPKey implements PrivateKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * The private exponent for either the server or the client engaged in the + * SRP protocol exchange. + */ + private final BigInteger X; + + /** + * The user's verifier (v) --for the server-- also computed at the client + * side as g.modPow(x, N), where x is the hashed output of the user name and + * password . + */ + private final BigInteger v; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Public constructor for use from outside this package.

+ * + * @param N the public shared modulus. + * @param g the generator. + * @param x the private exponent of the ephemeral key. + */ + public SRPPrivateKey(BigInteger N, BigInteger g, BigInteger x) + { + this(N, g, x, null); + } + + /** + *

Public constructor for use from outside this package.

+ * + * @param N the public shared modulus. + * @param g the generator. + * @param x the private exponent of the ephemeral key. + * @param v the user's verifier value (for the server side only). + */ + public SRPPrivateKey(BigInteger N, BigInteger g, BigInteger x, BigInteger v) + { + super(N, g); + + SRPAlgorithm.checkParams(N, g); + this.X = x; + this.v = v; + } + + /** + *

Default constructor. Assumes N and g are already validated.

+ * + * @param params an array of either 3 or 4 values representing N, g, and + * either v and X for the server, or just X for the client. Those values + * represent the following: + *
    + *
  1. v (server side): the user's verifier.
  2. + *
  3. X (both sides): the server's or client's ephemeral private exponent.
  4. + *
+ */ + SRPPrivateKey(BigInteger[] params) + { + super(params[0], params[1]); + + if (params.length == 3) + { + X = params[2]; + v = null; + } + else if (params.length == 4) + { + X = params[2]; + v = params[3]; + } + else + { + throw new IllegalArgumentException("invalid number of SRP parameters"); + } + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

A class method that takes the output of the encodePrivateKey() + * method of an SRP keypair codec object (an instance implementing + * {@link IKeyPairCodec} for DSS keys, and re-constructs an instance of this + * object.

+ * + * @param k the contents of a previously encoded instance of this object. + * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an instance of this object. + * @throws IllegalArgumentException if the byte sequence does not represent a + * valid encoding of an instance of this object. + */ + public static SRPPrivateKey valueOf(byte[] k) + { + // check magic... + // we should parse here enough bytes to know which codec to use, and + // direct the byte array to the appropriate codec. since we only have one + // codec, we could have immediately tried it; nevertheless since testing + // one byte is cheaper than instatiating a codec that will fail we test + // the first byte before we carry on. + if (k[0] == Registry.MAGIC_RAW_SRP_PRIVATE_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + IKeyPairCodec codec = new SRPKeyPairRawCodec(); + return (SRPPrivateKey) codec.decodePrivateKey(k); + } + else + { + throw new IllegalArgumentException("magic"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns the private exponent of the key as a {@link BigInteger}.

+ * + * @return the private exponent of the key as a {@link BigInteger}. + */ + public BigInteger getX() + { + return X; + } + + /** + *

Returns the user's verifier as a {@link BigInteger}.

+ * + * @return the user's verifier as a {@link BigInteger} if this is an SRP + * private key of a Host, or null if this is a private SRP key + * for a User. + */ + public BigInteger getV() + { + return v; + } + + // Other instance methods -------------------------------------------------- + + /** + *

Returns the encoded form of this private key according to the + * designated format.

+ * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new SRPKeyPairRawCodec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("format"); + } + return result; + } + + /** + *

Returns true if the designated object is an instance of + * SRPPrivateKey and has the same SRP parameter values as this + * one.

+ * + * @param obj the other non-null SRP key to compare to. + * @return true if the designated object is of the same type and + * value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (!(obj instanceof SRPPrivateKey)) + { + return false; + } + SRPPrivateKey that = (SRPPrivateKey) obj; + boolean result = super.equals(that) && X.equals(that.getX()); + if (v != null) + { + result = result && v.equals(that.getV()); + } + return result; + } +} diff --git a/gnu/javax/crypto/key/srp6/SRPPublicKey.java b/gnu/javax/crypto/key/srp6/SRPPublicKey.java new file mode 100644 index 000000000..7283fd3da --- /dev/null +++ b/gnu/javax/crypto/key/srp6/SRPPublicKey.java @@ -0,0 +1,194 @@ +/* SRPPublicKey.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.key.srp6; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.PublicKey; + +/** + *

A representation of an SRP ephemeral public key.

+ * + *

Reference:

+ *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class SRPPublicKey extends SRPKey implements PublicKey +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * The public exponent for either the server or the client engaged in the + * SRP protocol exchange. + */ + private final BigInteger Y; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Public constructor for use from outside this package.

+ * + * @param N the public shared modulus. + * @param g the generator. + * @param Y the public exponent of the ephemeral key. + */ + public SRPPublicKey(BigInteger N, BigInteger g, BigInteger Y) + { + super(N, g); + + SRPAlgorithm.checkParams(N, g); + this.Y = Y; + } + + /** + *

Default constructor. Assumes that N and g are already validated.

+ * + * @param params an array of 3 values representing N, g and Y; the latter + * being the client's or server's public exponent. + */ + SRPPublicKey(BigInteger[] params) + { + super(params[0], params[1]); + + this.Y = params[2]; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

A class method that takes the output of the encodePublicKey() + * method of an SRP keypair codec object (an instance implementing + * {@link IKeyPairCodec} for SRP keys, and re-constructs an instance of this + * object.

+ * + * @param k the contents of a previously encoded instance of this object. + * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an instance of this object. + * @throws IllegalArgumentException if the byte sequence does not represent a + * valid encoding of an instance of this object. + */ + public static SRPPublicKey valueOf(byte[] k) + { + // check magic... + // we should parse here enough bytes to know which codec to use, and + // direct the byte array to the appropriate codec. since we only have one + // codec, we could have immediately tried it; nevertheless since testing + // one byte is cheaper than instatiating a codec that will fail we test + // the first byte before we carry on. + if (k[0] == Registry.MAGIC_RAW_SRP_PUBLIC_KEY[0]) + { + // it's likely to be in raw format. get a raw codec and hand it over + IKeyPairCodec codec = new SRPKeyPairRawCodec(); + return (SRPPublicKey) codec.decodePublicKey(k); + } + else + { + throw new IllegalArgumentException("magic"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns the public exponent of the key as a {@link BigInteger}.

+ * + * @return the public exponent of the key as a {@link BigInteger}. + */ + public BigInteger getY() + { + return Y; + } + + // Other instance methods -------------------------------------------------- + + /** + *

Returns the encoded form of this public key according to the designated + * format.

+ * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new SRPKeyPairRawCodec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("format"); + } + return result; + } + + /** + *

Returns true if the designated object is an instance of + * SRPPublicKeyand has the same SRP parameter values as this one. + *

+ * + * @param obj the other non-null SRP key to compare to. + * @return true if the designated object is of the same type and + * value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (!(obj instanceof SRPPublicKey)) + { + return false; + } + SRPPublicKey that = (SRPPublicKey) obj; + return super.equals(that) && Y.equals(that.getY()); + } +} diff --git a/gnu/javax/crypto/keyring/AuthenticatedEntry.java b/gnu/javax/crypto/keyring/AuthenticatedEntry.java new file mode 100644 index 000000000..22b42b3ea --- /dev/null +++ b/gnu/javax/crypto/keyring/AuthenticatedEntry.java @@ -0,0 +1,222 @@ +/* AuthenticatedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.InvalidKeyException; + +import java.util.Arrays; +import java.util.Date; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; + +import gnu.java.security.Registry; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacInputStream; +import gnu.javax.crypto.mac.MacOutputStream; + +public final class AuthenticatedEntry extends MaskableEnvelopeEntry implements + Registry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 2; + + // Constructor. + // ------------------------------------------------------------------------ + + public AuthenticatedEntry(String mac, int macLen, Properties properties) + { + super(TYPE, properties); + + if (macLen <= 0) + { + throw new IllegalArgumentException("invalid mac length"); + } + this.properties.put("mac", mac); + this.properties.put("maclen", String.valueOf(macLen)); + setMasked(false); + } + + private AuthenticatedEntry() + { + super(TYPE); + setMasked(true); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static AuthenticatedEntry decode(DataInputStream in) + throws IOException + { + AuthenticatedEntry entry = new AuthenticatedEntry(); + entry.properties.decode(in); + if (!entry.properties.containsKey("mac")) + { + throw new MalformedKeyringException("no mac specified"); + } + if (!entry.properties.containsKey("maclen")) + { + throw new MalformedKeyringException("no mac length specified"); + } + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Computes the mac over this envelope's data. This method must be + * called before this entry in encoded. + * + * @param key The key to authenticate with. + * @throws IOException If encoding fails. + * @throws InvalidKeyException If the supplied key is bad. + */ + public void authenticate(byte[] key) throws IOException, InvalidKeyException + { + if (isMasked()) + { + throw new IllegalStateException("entry is masked"); + } + IMac m = getMac(key); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + MacOutputStream macout = new MacOutputStream(bout, m); + DataOutputStream out2 = new DataOutputStream(macout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + } + + /** + * Verifies this entry's payload. This method will unmask this entry, + * thus it must be called before accessing its contents. + * + * @param key The key to use to authenticate. + * @throws InvalidKeyException If the given key is improper. + */ + public void verify(byte[] key) throws InvalidKeyException + { + if (!isMasked() || payload == null) + { + return; + } + IMac m = getMac(key); + + m.update(payload, 0, payload.length - m.macSize()); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, 0, + macValue.length); + if (!Arrays.equals(macValue, m.digest())) + { + throw new IllegalArgumentException("MAC verification failed"); + } + try + { + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + payload, + 0, + payload.length + - m.macSize())); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + setMasked(false); + payload = null; + } + + protected void encodePayload() throws IOException + { + if (payload == null) + { + throw new IllegalStateException("not authenticated"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private IMac getMac(byte[] key) throws InvalidKeyException + { + IMac mac = MacFactory.getInstance(properties.get("mac")); + if (mac == null) + { + throw new IllegalArgumentException("no such mac: " + + properties.get("mac")); + } + int maclen = 0; + if (!properties.containsKey("maclen")) + { + throw new IllegalArgumentException("no MAC length"); + } + try + { + maclen = Integer.parseInt(properties.get("maclen")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad MAC length"); + } + + HashMap macAttr = new HashMap(); + macAttr.put(IMac.MAC_KEY_MATERIAL, key); + macAttr.put(IMac.TRUNCATED_SIZE, new Integer(maclen)); + mac.init(macAttr); + return mac; + } +} diff --git a/gnu/javax/crypto/keyring/BaseKeyring.java b/gnu/javax/crypto/keyring/BaseKeyring.java new file mode 100644 index 000000000..5fe7dbf4d --- /dev/null +++ b/gnu/javax/crypto/keyring/BaseKeyring.java @@ -0,0 +1,198 @@ +/* BaseKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import gnu.java.security.Registry; + +public abstract class BaseKeyring implements IKeyring +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** + * The top-level keyring data. + */ + protected PasswordAuthenticatedEntry keyring; + + protected CompressedEntry keyring2; + + // Constructors. + // ------------------------------------------------------------------------ + + public BaseKeyring() + { + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public void load(Map attributes) throws IOException + { + InputStream in = (InputStream) attributes.get(KEYRING_DATA_IN); + if (in == null) + { + throw new IllegalArgumentException("no input stream"); + } + char[] password = (char[]) attributes.get(KEYRING_PASSWORD); + if (password == null) + { + password = new char[0]; + } + + if (in.read() != Registry.GKR_MAGIC[0] + || in.read() != Registry.GKR_MAGIC[1] + || in.read() != Registry.GKR_MAGIC[2] + || in.read() != Registry.GKR_MAGIC[3]) + { + throw new MalformedKeyringException("magic"); + } + + load(in, password); + + List l = keyring.getEntries(); + if (l.size() == 1 && (l.get(0) instanceof CompressedEntry)) + { + keyring2 = (CompressedEntry) l.get(0); + } + } + + public void store(Map attributes) throws IOException + { + OutputStream out = (OutputStream) attributes.get(KEYRING_DATA_OUT); + if (out == null) + { + throw new IllegalArgumentException("no output stream"); + } + char[] password = (char[]) attributes.get(KEYRING_PASSWORD); + if (password == null) + { + password = new char[0]; + } + if (keyring == null) + { + throw new IllegalStateException("empty keyring"); + } + + out.write(Registry.GKR_MAGIC); + store(out, password); + } + + public void reset() + { + keyring = null; + } + + public int size() + { + if (keyring == null) + { + throw new IllegalStateException ("keyring not loaded"); + } + return ((StringTokenizer) aliases()).countTokens(); + } + + public Enumeration aliases() + { + if (keyring == null) + { + throw new IllegalStateException ("keyring not loaded"); + } + return new StringTokenizer(keyring.getAliasList(), ";"); + } + + public boolean containsAlias(String alias) + { + if (keyring == null) + { + throw new IllegalStateException("keyring not loaded"); + } + return keyring.containsAlias(alias); + } + + public List get(String alias) + { + if (keyring == null) + { + throw new IllegalStateException("keyring not loaded"); + } + return keyring.get(alias); + } + + public void add(Entry entry) + { + if (keyring == null) + { + throw new IllegalStateException("keyring not loaded"); + } + if (keyring2 != null) + keyring2.add(entry); + else + keyring.add(entry); + } + + public void remove(String alias) + { + if (keyring == null) + { + throw new IllegalStateException("keyring not loaded"); + } + keyring.remove(alias); + } + + protected String fixAlias(String alias) + { + return alias.replace(';', '_'); + } + + protected abstract void load(InputStream in, char[] password) + throws IOException; + + protected abstract void store(OutputStream out, char[] password) + throws IOException; +} diff --git a/gnu/javax/crypto/keyring/BinaryDataEntry.java b/gnu/javax/crypto/keyring/BinaryDataEntry.java new file mode 100644 index 000000000..2dcd5454f --- /dev/null +++ b/gnu/javax/crypto/keyring/BinaryDataEntry.java @@ -0,0 +1,128 @@ +/* BinaryDataEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.IOException; + +import java.util.Date; + +/** + * A binary data entry is a primitive entry that simply contains some amount + * of arbitrary binary data and an optional content type. + */ +public class BinaryDataEntry extends PrimitiveEntry +{ + + // Fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 9; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Creates a new binary data entry. + * + * @param contentType The content type of this entry. This parameter can + * be null if no content type is needed. + * @param data The data. + * @param creationDate The creation date. + * @param properties This entry's properties. + */ + public BinaryDataEntry(String contentType, byte[] data, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (data == null) + { + throw new IllegalArgumentException("no data"); + } + payload = (byte[]) data.clone(); + if (contentType != null) + { + this.properties.put("content-type", contentType); + } + } + + private BinaryDataEntry() + { + super(TYPE); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static BinaryDataEntry decode(DataInputStream in) throws IOException + { + BinaryDataEntry entry = new BinaryDataEntry(); + entry.defaultDecode(in); + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the content type of this entry, or null if this + * property is not set. + * + * @return The content type. + */ + public String getContentType() + { + return properties.get("content-type"); + } + + /** + * Returns this object's data field. + * + * @return The data. + */ + public byte[] getData() + { + return getPayload(); + } + + protected void encodePayload() + { + // Empty. + } +} diff --git a/gnu/javax/crypto/keyring/CertPathEntry.java b/gnu/javax/crypto/keyring/CertPathEntry.java new file mode 100644 index 000000000..ef62347ec --- /dev/null +++ b/gnu/javax/crypto/keyring/CertPathEntry.java @@ -0,0 +1,133 @@ +/* CertPathEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + +import java.util.Date; + +/** + * A primitive entry that contains a path of X.509 certificates. + */ +public final class CertPathEntry extends PrimitiveEntry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 8; + + private Certificate[] path; + + // Constructor. + // ------------------------------------------------------------------------ + + public CertPathEntry(Certificate[] path, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + if (path == null || path.length == 0) + { + throw new IllegalArgumentException("no certificate path"); + } + this.path = (Certificate[]) path.clone(); + } + + private CertPathEntry() + { + super(TYPE); + } + + // Class method. + // ------------------------------------------------------------------------ + + public static CertPathEntry decode(DataInputStream in) throws IOException + { + CertPathEntry entry = new CertPathEntry(); + entry.properties.decode(in); + entry.makeCreationDate(); + int len = in.readInt(); + MeteredInputStream in2 = new MeteredInputStream(in, len); + try + { + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + entry.path = (Certificate[]) fact.generateCertificates(in2).toArray( + new Certificate[0]); + } + catch (CertificateException ce) + { + throw new MalformedKeyringException(ce.toString()); + } + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public Certificate[] getCertPath() + { + return path; + } + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + byte[] enc = null; + try + { + for (int i = 0; i < path.length; i++) + { + bout.write(path[i].getEncoded()); + } + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + payload = bout.toByteArray(); + } +} diff --git a/gnu/javax/crypto/keyring/CertificateEntry.java b/gnu/javax/crypto/keyring/CertificateEntry.java new file mode 100644 index 000000000..95a708ac5 --- /dev/null +++ b/gnu/javax/crypto/keyring/CertificateEntry.java @@ -0,0 +1,150 @@ +/* CertificateEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Date; + +/** + *

An immutable class representing a trusted certificate entry.

+ */ +public final class CertificateEntry extends PrimitiveEntry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int TYPE = 5; + + /** The certificate. */ + private Certificate certificate; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Creates a new certificate entry. + * + * @param certificate The certificate. + * @param creationDate The creation date. + * @param properties The alias. + * @throws IllegalArgumentException If any argument is null, or if the alias + * is empty. + */ + public CertificateEntry(Certificate certificate, Date creationDate, + Properties properties) + { + super(TYPE, creationDate, properties); + + if (certificate == null) + { + throw new IllegalArgumentException("no certificate"); + } + this.certificate = certificate; + this.properties.put("type", certificate.getType()); + } + + private CertificateEntry() + { + super(TYPE); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static CertificateEntry decode(DataInputStream in) throws IOException + { + CertificateEntry entry = new CertificateEntry(); + entry.properties.decode(in); + entry.makeCreationDate(); + String type = entry.properties.get("type"); + if (type == null) + { + throw new MalformedKeyringException("no certificate type"); + } + int len = in.readInt(); + MeteredInputStream in2 = new MeteredInputStream(in, len); + try + { + CertificateFactory fact = CertificateFactory.getInstance(type); + entry.certificate = fact.generateCertificate(in2); + } + catch (CertificateException ce) + { + throw new MalformedKeyringException(ce.toString()); + } + if (!in2.limitReached()) + { + throw new MalformedKeyringException("extra data at end of payload"); + } + return entry; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * Returns this entry's certificate. + * + * @return The certificate. + */ + public Certificate getCertificate() + { + return certificate; + } + + protected void encodePayload() throws IOException + { + try + { + payload = certificate.getEncoded(); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + } +} diff --git a/gnu/javax/crypto/keyring/CompressedEntry.java b/gnu/javax/crypto/keyring/CompressedEntry.java new file mode 100644 index 000000000..cce930d73 --- /dev/null +++ b/gnu/javax/crypto/keyring/CompressedEntry.java @@ -0,0 +1,113 @@ +/* CompressedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.util.Iterator; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +public class CompressedEntry extends EnvelopeEntry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 4; + + // Constructor. + // ------------------------------------------------------------------------ + + public CompressedEntry(Properties properties) + { + super(TYPE, properties); + this.properties.put("algorithm", "DEFLATE"); + } + + private CompressedEntry() + { + this(new Properties()); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static CompressedEntry decode(DataInputStream in) throws IOException + { + CompressedEntry entry = new CompressedEntry(); + entry.properties.decode(in); + String alg = entry.properties.get("algorithm"); + if (alg == null) + { + throw new MalformedKeyringException("no compression algorithm"); + } + if (!alg.equalsIgnoreCase("DEFLATE")) + { + throw new MalformedKeyringException( + "unsupported compression algorithm: " + + alg); + } + int len = in.readInt(); + MeteredInputStream min = new MeteredInputStream(in, len); + InflaterInputStream infin = new InflaterInputStream(min); + DataInputStream in2 = new DataInputStream(infin); + entry.decodeEnvelope(in2); + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(1024); + DeflaterOutputStream dout = new DeflaterOutputStream(buf); + DataOutputStream out2 = new DataOutputStream(dout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + ((Entry) it.next()).encode(out2); + } + dout.finish(); + payload = buf.toByteArray(); + } +} diff --git a/gnu/javax/crypto/keyring/EncryptedEntry.java b/gnu/javax/crypto/keyring/EncryptedEntry.java new file mode 100644 index 000000000..fad5f54b2 --- /dev/null +++ b/gnu/javax/crypto/keyring/EncryptedEntry.java @@ -0,0 +1,235 @@ +/* EncryptedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.InvalidKeyException; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +public class EncryptedEntry extends MaskableEnvelopeEntry implements Registry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 0; + + // Constructor. + // ------------------------------------------------------------------------ + + public EncryptedEntry(String cipher, String mode, Properties properties) + { + super(TYPE, properties); + if (cipher == null || mode == null) + { + throw new IllegalArgumentException( + "neither cipher nor mode can be null"); + } + properties.put("cipher", cipher); + properties.put("mode", mode); + setMasked(false); + } + + private EncryptedEntry() + { + super(TYPE, new Properties()); + setMasked(true); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static EncryptedEntry decode(DataInputStream in) throws IOException + { + EncryptedEntry entry = new EncryptedEntry(); + entry.defaultDecode(in); + if (!entry.properties.containsKey("cipher")) + { + throw new MalformedKeyringException("no cipher"); + } + if (!entry.properties.containsKey("cipher")) + { + throw new MalformedKeyringException("no cipher"); + } + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public void decrypt(byte[] key, byte[] iv) throws IllegalArgumentException, + WrongPaddingException + { + if (!isMasked() || payload == null) + { + return; + } + IMode mode = getMode(key, iv, IMode.DECRYPTION); + IPad padding = null; + padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + for (int i = 0; i < payload.length; i++) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + buf, + 0, + buf.length + - padlen)); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + setMasked(false); + payload = null; + } + + public void encrypt(byte[] key, byte[] iv) throws IOException + { + IMode mode = getMode(key, iv, IMode.ENCRYPTION); + IPad pad = PadFactory.getInstance("PKCS7"); + pad.init(mode.currentBlockSize()); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out2 = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + byte[] plaintext = bout.toByteArray(); + byte[] padding = pad.pad(plaintext, 0, plaintext.length); + payload = new byte[plaintext.length + padding.length]; + byte[] lastBlock = new byte[mode.currentBlockSize()]; + int l = mode.currentBlockSize() - padding.length; + System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l); + System.arraycopy(padding, 0, lastBlock, l, padding.length); + int count = 0; + while (count + mode.currentBlockSize() < plaintext.length) + { + mode.update(plaintext, count, payload, count); + count += mode.currentBlockSize(); + } + mode.update(lastBlock, 0, payload, count); + } + + public void encodePayload() throws IOException + { + if (payload == null) + { + throw new IOException("not encrypted"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private IMode getMode(byte[] key, byte[] iv, int state) + { + IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher")); + if (cipher == null) + { + throw new IllegalArgumentException("no such cipher: " + + properties.get("cipher")); + } + int blockSize = cipher.defaultBlockSize(); + if (properties.containsKey("block-size")) + { + try + { + blockSize = Integer.parseInt(properties.get("block-size")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad block size: " + + nfe.getMessage()); + } + } + IMode mode = ModeFactory.getInstance(properties.get("mode"), cipher, + blockSize); + if (mode == null) + { + throw new IllegalArgumentException("no such mode: " + + properties.get("mode")); + } + + HashMap modeAttr = new HashMap(); + modeAttr.put(IMode.KEY_MATERIAL, key); + modeAttr.put(IMode.STATE, new Integer(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/gnu/javax/crypto/keyring/Entry.java b/gnu/javax/crypto/keyring/Entry.java new file mode 100644 index 000000000..fa7f49679 --- /dev/null +++ b/gnu/javax/crypto/keyring/Entry.java @@ -0,0 +1,178 @@ +/* Entry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * An immutable class representing a single entry in a keyring. + */ +public abstract class Entry +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** This entry's type identifier. */ + protected int type; + + /** This entry's property set. */ + protected Properties properties; + + /** This entry's payload. */ + protected byte[] payload; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Creates a new Entry. + * + * @param type This entry's type. + * @param properties This entry's properties. + * @throws IllegalArgumentException If the properties argument is null, + * or if the type is out of range. + */ + protected Entry(int type, Properties properties) + { + if (type < 0 || type > 255) + { + throw new IllegalArgumentException("invalid packet type"); + } + if (properties == null) + { + throw new IllegalArgumentException("no properties"); + } + this.type = type; + this.properties = (Properties) properties.clone(); + } + + /** + * Constructor for use by subclasses. + */ + protected Entry(final int type) + { + if (type < 0 || type > 255) + { + throw new IllegalArgumentException("invalid packet type"); + } + this.type = type; + properties = new Properties(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns this entry's properties object. The properties are cloned before + * being returned. + * + * @return The properties. + */ + public Properties getProperties() + { + return (Properties) properties.clone(); + } + + /** + * Returns this entry's payload data, or null if + */ + public byte[] getPayload() + { + if (payload == null) + return null; + return (byte[]) payload.clone(); + } + + /** + * This method is called when this entry needs to be written to an + * output stream. + * + * @param out The stream to write to. + * @throws IOException If an I/O exception occurs. + */ + public void encode(DataOutputStream out) throws IOException + { + if (payload == null) + { + encodePayload(); + } + if (out == null) + { + return; + } + out.write(type); + properties.encode(out); + out.writeInt(payload.length); + out.write(payload); + } + + /** + * Generic decoding method, which simply decodes the properties field + * and reads the payload field. + * + * @param in The input data stream. + * @throws IOException If an I/O error occurs. + */ + protected void defaultDecode(DataInputStream in) throws IOException + { + properties = new Properties(); + properties.decode(in); + int len = in.readInt(); + if (len < 0) + { + throw new IOException("corrupt length"); + } + payload = new byte[len]; + in.readFully(payload); + } + + // Abstract methods. + // ------------------------------------------------------------------------ + + /** + * This method is called of subclasses when the payload data needs to be + * created. + * + * @throws IOException If an encoding error occurs. + */ + protected abstract void encodePayload() throws IOException; +} diff --git a/gnu/javax/crypto/keyring/EnvelopeEntry.java b/gnu/javax/crypto/keyring/EnvelopeEntry.java new file mode 100644 index 000000000..25b1dc2a0 --- /dev/null +++ b/gnu/javax/crypto/keyring/EnvelopeEntry.java @@ -0,0 +1,398 @@ +/* EnvelopeEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +/** + * An envelope entry is a generic container for some number of primitive + * and other envelope entries. + */ +public abstract class EnvelopeEntry extends Entry +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The envelope that contains this one (if any). */ + protected EnvelopeEntry containingEnvelope; + + /** The contained entries. */ + protected List entries; + + // Constructor. + // ------------------------------------------------------------------------ + + public EnvelopeEntry(int type, Properties properties) + { + super(type, properties); + entries = new LinkedList(); + if (this.properties.get("alias-list") != null) + { + this.properties.remove("alias-list"); + } + } + + protected EnvelopeEntry(int type) + { + super(type); + entries = new LinkedList(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Adds an entry to this envelope. + * + * @param entry The entry to add. + */ + public void add(Entry entry) + { + if (!containsEntry(entry)) + { + if (entry instanceof EnvelopeEntry) + { + ((EnvelopeEntry) entry).setContainingEnvelope(this); + } + entries.add(entry); + payload = null; + makeAliasList(); + } + } + + /** + * Tests if this envelope contains a primitive entry with the + * given alias. + * + * @param alias The alias to test. + * @return True if this envelope (or one of the contained envelopes) + * contains a primitive entry with the given alias. + */ + public boolean containsAlias(String alias) + { + String aliases = getAliasList(); + if (aliases == null) + { + return false; + } + StringTokenizer tok = new StringTokenizer(aliases, ";"); + while (tok.hasMoreTokens()) + { + if (tok.nextToken().equals(alias)) + { + return true; + } + } + return false; + } + + /** + * Tests if this envelope contains the given entry. + * + * @param entry The entry to test. + * @return True if this envelope contains the given entry. + */ + public boolean containsEntry(Entry entry) + { + if (entry instanceof EnvelopeEntry) + { + return entries.contains(entry); + } + else if (entry instanceof PrimitiveEntry) + { + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e.equals(entry)) + return true; + if ((e instanceof EnvelopeEntry) + && ((EnvelopeEntry) e).containsEntry(entry)) + return true; + } + } + return false; + } + + /** + * Returns a copy of all entries this envelope contains. + * + * @return All contained entries. + */ + public List getEntries() + { + return new ArrayList(entries); + } + + /** + * Gets all primitive entries that have the given alias. If there + * are any masked entries that contain the given alias, they will + * be returned as well. + * + * @param alias The alias of the entries to get. + * @return A list of all primitive entries that have the given alias. + */ + public List get(String alias) + { + List result = new LinkedList(); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + if (!((EnvelopeEntry) e).containsAlias(alias)) + { + continue; + } + if (e instanceof MaskableEnvelopeEntry) + { + if (((MaskableEnvelopeEntry) e).isMasked()) + { + result.add(e); + continue; + } + } + result.addAll(((EnvelopeEntry) e).get(alias)); + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).getAlias().equals(alias)) + { + result.add(e); + } + } + } + return result; + } + + /** + * Returns the list of all aliases contained by this envelope, + * separated by a semicolon (';'). + * + * @return The list of aliases. + */ + public String getAliasList() + { + String list = properties.get("alias-list"); + if (list == null) + { + return ""; + } + else + { + return list; + } + } + + /** + * Removes the specified entry. + * + * @param entry The entry. + * @return True if an entry was removed. + */ + public boolean remove(Entry entry) + { + boolean ret = false; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + if (e == entry) + { + it.remove(); + ret = true; + break; + } + if (((EnvelopeEntry) e).remove(entry)) + { + ret = true; + break; + } + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).equals(entry)) + { + it.remove(); + ret = true; + break; + } + } + } + if (ret) + { + payload = null; + makeAliasList(); + } + return ret; + } + + /** + * Removes all primitive entries that have the specified alias. + * + * @param alias The alias of the entries to remove. + */ + public void remove(String alias) + { + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + ((EnvelopeEntry) e).remove(alias); + } + else if (e instanceof PrimitiveEntry) + { + if (((PrimitiveEntry) e).getAlias().equals(alias)) + { + it.remove(); + } + } + } + payload = null; + makeAliasList(); + } + + // Protected methods. + // ------------------------------------------------------------------------ + + protected void encodePayload() throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + ((Entry) it.next()).encode(out); + } + } + + protected void setContainingEnvelope(EnvelopeEntry e) + { + if (containingEnvelope != null) + { + throw new IllegalArgumentException("envelopes may not be shared"); + } + containingEnvelope = e; + } + + protected void decodeEnvelope(DataInputStream in) throws IOException + { + while (true) + { + int type = in.read(); + switch (type) + { + case EncryptedEntry.TYPE: + add(EncryptedEntry.decode(in)); + break; + case PasswordEncryptedEntry.TYPE: + add(PasswordEncryptedEntry.decode(in)); + break; + case PasswordAuthenticatedEntry.TYPE: + add(PasswordAuthenticatedEntry.decode(in)); + break; + case AuthenticatedEntry.TYPE: + add(AuthenticatedEntry.decode(in)); + break; + case CompressedEntry.TYPE: + add(CompressedEntry.decode(in)); + break; + case CertificateEntry.TYPE: + add(CertificateEntry.decode(in)); + break; + case PublicKeyEntry.TYPE: + add(PublicKeyEntry.decode(in)); + break; + case PrivateKeyEntry.TYPE: + add(PrivateKeyEntry.decode(in)); + break; + case CertPathEntry.TYPE: + add(CertPathEntry.decode(in)); + break; + case BinaryDataEntry.TYPE: + add(BinaryDataEntry.decode(in)); + break; + case -1: + return; + default: + throw new MalformedKeyringException("unknown type " + type); + } + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private void makeAliasList() + { + if (entries.isEmpty()) + return; + StringBuffer buf = new StringBuffer(); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + if (entry instanceof EnvelopeEntry) + { + buf.append(((EnvelopeEntry) entry).getAliasList()); + } + else if (entry instanceof PrimitiveEntry) + { + buf.append(((PrimitiveEntry) entry).getAlias()); + } + if (it.hasNext()) + buf.append(';'); + } + properties.put("alias-list", buf.toString()); + if (containingEnvelope != null) + { + containingEnvelope.makeAliasList(); + } + } +} diff --git a/gnu/javax/crypto/keyring/GnuPrivateKeyring.java b/gnu/javax/crypto/keyring/GnuPrivateKeyring.java new file mode 100644 index 000000000..d49bd0963 --- /dev/null +++ b/gnu/javax/crypto/keyring/GnuPrivateKeyring.java @@ -0,0 +1,328 @@ +/* GnuPrivateKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.Key; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +/** + *

.

+ */ +public class GnuPrivateKeyring extends BaseKeyring implements IPrivateKeyring +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int USAGE = Registry.GKR_PRIVATE_KEYS + | Registry.GKR_PUBLIC_CREDENTIALS; + + protected String mac; + + protected int maclen; + + protected String cipher; + + protected String mode; + + protected int keylen; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public GnuPrivateKeyring(String mac, int maclen, String cipher, String mode, + int keylen) + { + keyring = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + this.mac = mac; + this.maclen = maclen; + this.cipher = cipher; + this.mode = mode; + this.keylen = keylen; + } + + public GnuPrivateKeyring() + { + this("HMAC-SHA-1", 20, "AES", "OFB", 16); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public boolean containsPrivateKey(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof PasswordAuthenticatedEntry) + { + return true; + } + } + return false; + } + + public Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + PasswordAuthenticatedEntry e1 = null; + PasswordEncryptedEntry e2 = null; + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PasswordAuthenticatedEntry) + { + e1 = (PasswordAuthenticatedEntry) e; + break; + } + } + if (e1 == null) + { + return null; + } + try + { + e1.verify(password); + } + catch (Exception e) + { + throw new UnrecoverableKeyException("authentication failed"); + } + for (Iterator it = e1.getEntries().iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PasswordEncryptedEntry) + { + e2 = (PasswordEncryptedEntry) e; + break; + } + } + if (e2 == null) + { + return null; + } + try + { + e2.decrypt(password); + } + catch (Exception e) + { + throw new UnrecoverableKeyException("decryption failed"); + } + for (Iterator it = e2.get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PrivateKeyEntry) + { + return ((PrivateKeyEntry) e).getKey(); + } + } + return null; + } + + public void putPrivateKey(String alias, Key key, char[] password) + { + if (containsPrivateKey(alias)) + { + return; + } + alias = fixAlias(alias); + Properties p = new Properties(); + p.put("alias", alias); + PrivateKeyEntry pke = new PrivateKeyEntry(key, new Date(), p); + PasswordEncryptedEntry enc = new PasswordEncryptedEntry(cipher, mode, + keylen, + new Properties()); + PasswordAuthenticatedEntry auth = new PasswordAuthenticatedEntry( + mac, + maclen, + new Properties()); + enc.add(pke); + auth.add(enc); + try + { + enc.encode(null, password); + auth.encode(null, password); + } + catch (IOException ioe) + { + throw new IllegalArgumentException(ioe.toString()); + } + keyring.add(auth); + } + + public boolean containsPublicKey(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof PublicKeyEntry) + { + return true; + } + } + return false; + } + + public PublicKey getPublicKey(String alias) + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PublicKeyEntry) + { + return ((PublicKeyEntry) e).getKey(); + } + } + return null; + } + + public void putPublicKey(String alias, PublicKey key) + { + if (containsPublicKey(alias)) + { + return; + } + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new PublicKeyEntry(key, new Date(), p)); + } + + public boolean containsCertPath(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof CertPathEntry) + { + return true; + } + } + return false; + } + + public Certificate[] getCertPath(String alias) + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertPathEntry) + { + return ((CertPathEntry) e).getCertPath(); + } + } + return null; + } + + public void putCertPath(String alias, Certificate[] path) + { + if (containsCertPath(alias)) + { + return; + } + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertPathEntry(path, new Date(), p)); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (in.read() != USAGE) + { + throw new MalformedKeyringException("incompatible keyring usage"); + } + if (in.read() != PasswordAuthenticatedEntry.TYPE) + { + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + } + keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), + password); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + } +} diff --git a/gnu/javax/crypto/keyring/GnuPublicKeyring.java b/gnu/javax/crypto/keyring/GnuPublicKeyring.java new file mode 100644 index 000000000..318eb036f --- /dev/null +++ b/gnu/javax/crypto/keyring/GnuPublicKeyring.java @@ -0,0 +1,146 @@ +/* GnuPublicKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import java.security.cert.Certificate; + +import gnu.java.security.Registry; + +public class GnuPublicKeyring extends BaseKeyring implements IPublicKeyring +{ + + // Fields. + // ------------------------------------------------------------------------ + + public static final int USAGE = Registry.GKR_CERTIFICATES; + + // Constructors. + // ------------------------------------------------------------------------ + + public GnuPublicKeyring(String mac, int macLen) + { + keyring = new PasswordAuthenticatedEntry(mac, macLen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + } + + public GnuPublicKeyring() + { + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public boolean containsCertificate(String alias) + { + if (!containsAlias(alias)) + { + return false; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + if (it.next() instanceof CertificateEntry) + { + return true; + } + } + return false; + } + + public Certificate getCertificate(String alias) + { + if (!containsAlias(alias)) + { + return null; + } + List l = get(alias); + for (Iterator it = l.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertificateEntry) + { + return ((CertificateEntry) e).getCertificate(); + } + } + return null; + } + + public void putCertificate(String alias, Certificate cert) + { + if (containsCertificate(alias)) + { + return; + } + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertificateEntry(cert, new Date(), p)); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (in.read() != USAGE) + { + throw new MalformedKeyringException("incompatible keyring usage"); + } + if (in.read() != PasswordAuthenticatedEntry.TYPE) + { + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + } + keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), + password); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + } +} diff --git a/gnu/javax/crypto/keyring/IKeyring.java b/gnu/javax/crypto/keyring/IKeyring.java new file mode 100644 index 000000000..56f467df2 --- /dev/null +++ b/gnu/javax/crypto/keyring/IKeyring.java @@ -0,0 +1,164 @@ +/* IKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +/** + *

The top-level interface to a keyring: a file that is used to + * store and protect public and private cryptographic keys.

+ * + *

A keyring is modelled as a mapping of one alias to one or + * more entries (optionally of different types).

+ * + *

See also the sub-interfaces {@link IPublicKeyring} and + * {@link IPrivateKeyring} for special types of keyrings --the difference + * being in the type of entries they contain.

+ */ +public interface IKeyring +{ + + /** + *

Property name for the source of data to load the keyring from. The + * value mapped must be a {@link java.io.InputStream}.

+ */ + public static final String KEYRING_DATA_IN = "gnu.crypto.keyring.data.in"; + + /** + *

Property name for the data sink to store the keyring to. The value + * mapped must be a {@link java.io.OutputStream}.

+ */ + public static final String KEYRING_DATA_OUT = "gun.crypto.keyring.data.out"; + + /** + *

Property name for the keyring's top-level password, used to + * authenticate and/or transform the store itself. The mapped value must be a + * char array.

+ */ + public static final String KEYRING_PASSWORD = "gnu.crypto.keyring.password"; + + /** + *

Loads a keyring into memory.

+ * + *

What happens to the current contents of this keyring? are the new ones + * merged with the current ones or do they simply replace them?

+ * + * @param attributes The attributes that designate the source where the store + * is to be loaded from. What happens + * @throws IllegalArgumentException If the attributes are inappropriate. + * @throws IOException If the keyring file cannot be read. + * @throws SecurityException If the given password is incorrect, or if the + * top-level authentication or decryption fails. + */ + void load(Map attributes) throws IOException; + + /** + *

Stores the contents of this keyring to persistent storage as specified + * by the designated attributes.

+ * + * @param attributes the attributes that define where the contents of this + * keyring will be stored. + * @throws IOException if an exception occurs during the process. + */ + void store(Map attributes) throws IOException; + + /** + *

Resets this keyring, clearing all sensitive data. This method always + * suceeds.

+ */ + void reset(); + + /** + *

Returns the number of entries in this keyring.

+ * + * @return The number of current entries in this keyring. + */ + int size(); + + /** + *

Returns an {@link Enumeration} of all aliases (instances of + * {@link String}) in this keyring.

+ * + * @return The enumeration of {@link String}s each representing an + * alias found in this keyring. + */ + Enumeration aliases(); + + /** + * Tests whether or not this keyring contains the given alias. + * + * @param alias The alias to check. + * @return true if this keyring contains the alias. + */ + boolean containsAlias(String alias); + + /** + *

Returns a {@link List} of entries (instances of {@link Entry}) for the + * given alias, or null if there no such entry + * exists.

+ * + * @param alias The alias of the entry(ies) to return. + * @return A list of all entries (instances of {@link Entry} that have the + * given alias, or null if no one {@link Entry} can + * be found with the designated alias. + */ + List get(String alias); + + /** + *

Adds a designated {@link Entry} to this keyring.

+ * + *

What happens if there is already an entry with the same alias?

+ * + * @param entry The entry to put in this keyring. + */ + void add(Entry entry); + + /** + *

Removes an entry with the designated alias from this + * keyring. Does nothing if there was no such entry.

+ * + *

What happens if there are more than one?

+ * + * @param alias The alias of the entry to remove. + */ + void remove(String alias); +} diff --git a/gnu/javax/crypto/keyring/IPrivateKeyring.java b/gnu/javax/crypto/keyring/IPrivateKeyring.java new file mode 100644 index 000000000..66bbd84f5 --- /dev/null +++ b/gnu/javax/crypto/keyring/IPrivateKeyring.java @@ -0,0 +1,142 @@ +/* IPrivateKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.security.Key; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; + +/** + *

An interface to private, or "personal", keyrings, which contain private + * credentials. The contract is that each such entry is known by a unique + * alias.

+ * + *

What about public keys? and certificate-path?

+ */ +public interface IPrivateKeyring extends IKeyring +{ + + /** + *

Tests if this keyring contains a private key entry with the given + * alias.

+ * + * @param alias The alias to check. + * @return true if this keyring contains a private key with the + * given alias; false otherwise.

+ */ + boolean containsPrivateKey(String alias); + + /** + *

Returns the private key with the given alias.

+ * + * @param alias The alias of the private key to find. + * @param password The password of the private key. + * @return The private, or secret, key if one is found; null if + * none were found. + * @throws UnrecoverableKeyException If the private key could not be + * recovered, possibly due to a bad password. + */ + Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException; + + /** + *

Adds a private key to this keyring.

+ * + * @param alias The alias of the private key. + * @param key The private key. + * @param password The password used to protect this private key. + */ + void putPrivateKey(String alias, Key key, char[] password); + + /** + *

Checks if this keyring contains a public key with the given + * alias.

+ * + * @param alias The alias to test. + * @return true if this keyring contains a public key entry with + * the given alias; false otherwise. + */ + boolean containsPublicKey(String alias); + + /** + *

Returns the public key with the given alias, or + * null if there is no such entry.

+ * + * @param alias The alias of the public key to find. + * @return The public key; or null if none were found. + */ + PublicKey getPublicKey(String alias); + + /** + *

Sets a public key entry.

+ * + * @param alias The alias for this public key. + * @param key The public key. + */ + void putPublicKey(String alias, PublicKey key); + + /** + *

Checks if this keyring contains a certificate path with the given + * alias.

+ * + * @param alias The alias to check. + * @return true if this keyring contains a certificate path with + * the given alias; false otherwise. + */ + boolean containsCertPath(String alias); + + /** + *

Returns the certificate path with the given alias, or + * null if there is no such entry.

+ * + * @param alias The alias of the certificate path to find. + * @return The certificate path for the designated alias; or + * null if none were found. + */ + Certificate[] getCertPath(String alias); + + /** + *

Sets a certificate path entry.

+ * + * @param alias The alias for this certificate path. + * @param path The certificate path. + */ + void putCertPath(String alias, Certificate[] path); +} diff --git a/gnu/javax/crypto/keyring/IPublicKeyring.java b/gnu/javax/crypto/keyring/IPublicKeyring.java new file mode 100644 index 000000000..ccf9ca73b --- /dev/null +++ b/gnu/javax/crypto/keyring/IPublicKeyring.java @@ -0,0 +1,81 @@ +/* IPublicKeyring.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.security.cert.Certificate; + +/** + *

An interface for keyrings that contain trusted (by the owner) public + * credentials (incl. certificates).

+ * + * @see IKeyring + */ +public interface IPublicKeyring extends IKeyring +{ + + /** + *

Tests if this keyring contains a certificate entry with the specified + * alias.

+ * + * @param alias The alias of the certificate to check. + * @return true if this keyring contains a certificate entry + * that has the given alias; false otherwise. + */ + boolean containsCertificate(String alias); + + /** + *

Returns a certificate that has the given alias, or + * null if this keyring has no such entry.

+ * + * @param alias The alias of the certificate to find. + * @return The certificate with the designated alias, or + * null if none found. + */ + Certificate getCertificate(String alias); + + /** + *

Adds a certificate in this keyring, with the given alias.

+ * + *

What happens if there is already a certificate entry with this alias?

+ * + * @param alias The alias of this certificate entry. + * @param cert The certificate. + */ + void putCertificate(String alias, Certificate cert); +} diff --git a/gnu/javax/crypto/keyring/MalformedKeyringException.java b/gnu/javax/crypto/keyring/MalformedKeyringException.java new file mode 100644 index 000000000..44c953946 --- /dev/null +++ b/gnu/javax/crypto/keyring/MalformedKeyringException.java @@ -0,0 +1,58 @@ +/* MalformedKeyringException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.IOException; + +public class MalformedKeyringException extends IOException +{ + + // Constructors. + // ------------------------------------------------------------------------ + + public MalformedKeyringException() + { + super(); + } + + public MalformedKeyringException(String msg) + { + super(msg); + } +} diff --git a/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java b/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java new file mode 100644 index 000000000..7fed7c40c --- /dev/null +++ b/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java @@ -0,0 +1,148 @@ +/* MaskableEnvelopeEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.util.ArrayList; +import java.util.List; + +/** + * An envelope entry that can be "masked" -- placed in a state where the + * envelope's contents cannot be accessed, due to the envelope not being + * fully decoded, for example. + */ +public abstract class MaskableEnvelopeEntry extends EnvelopeEntry +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The masked state. */ + protected boolean masked; + + // Constructors. + // ------------------------------------------------------------------------ + + public MaskableEnvelopeEntry(int type, Properties properties) + { + super(type, properties); + } + + protected MaskableEnvelopeEntry(int type) + { + super(type); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Sets the masked state to the specified value. + * + * @param masked The new masked state. + */ + protected final void setMasked(boolean masked) + { + this.masked = masked; + } + + /** + * Gets the masked state of this object. Certain operations on this object + * will fail if it is masked. + * + * @return The current masked state. + */ + public boolean isMasked() + { + return masked; + } + + public void add(Entry entry) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + super.add(entry); + } + + public boolean containsEntry(Entry entry) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + return super.containsEntry(entry); + } + + public List getEntries() + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + return new ArrayList(entries); + } + + public List get(String alias) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + return super.get(alias); + } + + public boolean remove(Entry entry) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + return super.remove(entry); + } + + public void remove(String alias) + { + if (isMasked()) + { + throw new IllegalStateException("masked envelope"); + } + super.remove(alias); + } +} diff --git a/gnu/javax/crypto/keyring/MeteredInputStream.java b/gnu/javax/crypto/keyring/MeteredInputStream.java new file mode 100644 index 000000000..fcf2be746 --- /dev/null +++ b/gnu/javax/crypto/keyring/MeteredInputStream.java @@ -0,0 +1,137 @@ +/* MeteredInputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +final class MeteredInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------ + + private int count; + + private final int limit; + + // Constructor. + // ------------------------------------------------------------------------ + + MeteredInputStream(InputStream in, int limit) + { + super(in); + if (limit < 0) + throw new IllegalArgumentException("limit must be nonnegative"); + this.limit = limit; + count = 0; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Tests if the number of bytes read has reached the limit. + * + * @return True if the limit has been reached. + */ + public boolean limitReached() + { + return count == limit; + } + + public int available() throws IOException + { + return Math.min(in.available(), limit - count); + } + + public void close() throws IOException + { + in.close(); + } + + public void mark(int readLimit) + { + } + + public boolean markSupported() + { + return false; + } + + public int read() throws IOException + { + if (limitReached()) + return -1; + int i = in.read(); + if (i != -1) + count++; + return i; + } + + public int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + public int read(byte[] buf, int off, int len) throws IOException + { + if (limitReached()) + return -1; + int i = in.read(buf, off, Math.min(len, limit - count)); + if (i != -1) + count += i; + return i; + } + + public void reset() throws IOException + { + } + + public long skip(long len) throws IOException + { + if (limitReached()) + return 0L; + len = Math.min(len, limit - count); + len = in.skip(len); + count += (int) len; + return len; + } +} diff --git a/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java b/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java new file mode 100644 index 000000000..2e3a0d145 --- /dev/null +++ b/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java @@ -0,0 +1,285 @@ +/* PasswordAuthenticatedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.Util; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacInputStream; +import gnu.javax.crypto.mac.MacOutputStream; +import gnu.javax.crypto.prng.IPBE; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Iterator; +import java.util.HashMap; + +/** + *

An entry authenticated with a password-based MAC.

+ */ +public final class PasswordAuthenticatedEntry extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int TYPE = 3; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public PasswordAuthenticatedEntry(String mac, int maclen, + Properties properties) + { + super(TYPE, properties); + + if (mac == null || mac.length() == 0) + { + throw new IllegalArgumentException("no MAC specified"); + } + this.properties.put("mac", mac); + this.properties.put("maclen", String.valueOf(maclen)); + setMasked(false); + } + + private PasswordAuthenticatedEntry() + { + super(TYPE); + setMasked(true); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static PasswordAuthenticatedEntry decode(DataInputStream in, + char[] password) + throws IOException + { + PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); + entry.properties.decode(in); + IMac mac = entry.getMac(password); + int len = in.readInt() - mac.macSize(); + MeteredInputStream min = new MeteredInputStream(in, len); + MacInputStream macin = new MacInputStream(min, mac); + DataInputStream in2 = new DataInputStream(macin); + entry.setMasked(false); + entry.decodeEnvelope(in2); + byte[] macValue = new byte[mac.macSize()]; + in.readFully(macValue); + if (!Arrays.equals(macValue, mac.digest())) + { + throw new MalformedKeyringException("MAC verification failed"); + } + return entry; + } + + public static PasswordAuthenticatedEntry decode(DataInputStream in) + throws IOException + { + PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); + entry.defaultDecode(in); + if (!entry.properties.containsKey("mac")) + { + throw new MalformedKeyringException("no MAC"); + } + if (!entry.properties.containsKey("maclen")) + { + throw new MalformedKeyringException("no MAC length"); + } + if (!entry.properties.containsKey("salt")) + { + throw new MalformedKeyringException("no salt"); + } + return entry; + } + + // Instance methods + // ------------------------------------------------------------------------- + + public void verify(char[] password) + { + if (!isMasked() || payload == null) + { + return; + } + IMac m = null; + try + { + m = getMac(password); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.toString()); + } + + m.update(payload, 0, payload.length - m.macSize()); + byte[] macValue = new byte[m.macSize()]; + System.arraycopy(payload, payload.length - macValue.length, macValue, 0, + macValue.length); + if (!Arrays.equals(macValue, m.digest())) + { + throw new IllegalArgumentException("MAC verification failed"); + } + try + { + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + payload, + 0, + payload.length + - m.macSize())); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + setMasked(false); + payload = null; + } + + public void authenticate(char[] password) throws IOException + { + if (isMasked()) + { + throw new IllegalStateException("entry is masked"); + } + byte[] salt = new byte[8]; + new SecureRandom ().nextBytes (salt); + properties.put("salt", Util.toString(salt)); + IMac m = getMac(password); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + MacOutputStream macout = new MacOutputStream(bout, m); + DataOutputStream out2 = new DataOutputStream(macout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + authenticate(password); + encode(out); + } + + protected void encodePayload(DataOutputStream out) throws IOException + { + if (payload == null) + { + throw new IllegalStateException("mac not computed"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private IMac getMac(char[] password) throws MalformedKeyringException + { + if (!properties.containsKey("salt")) + { + throw new MalformedKeyringException("no salt"); + } + byte[] salt = Util.toBytesFromString(properties.get("salt")); + IMac mac = MacFactory.getInstance(properties.get("mac")); + if (mac == null) + { + throw new MalformedKeyringException("no such mac: " + + properties.get("mac")); + } + int keylen = mac.macSize(); + int maclen = 0; + if (!properties.containsKey("maclen")) + { + throw new MalformedKeyringException("no MAC length"); + } + try + { + maclen = Integer.parseInt(properties.get("maclen")); + } + catch (NumberFormatException nfe) + { + throw new MalformedKeyringException("bad MAC length"); + } + + HashMap pbAttr = new HashMap(); + pbAttr.put(IPBE.PASSWORD, password); + pbAttr.put(IPBE.SALT, salt); + pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); + kdf.init(pbAttr); + + byte[] dk = new byte[keylen]; + try + { + kdf.nextBytes(dk, 0, keylen); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + + HashMap macAttr = new HashMap(); + macAttr.put(IMac.MAC_KEY_MATERIAL, dk); + macAttr.put(IMac.TRUNCATED_SIZE, new Integer(maclen)); + try + { + mac.init(macAttr); + } + catch (InvalidKeyException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + return mac; + } +} diff --git a/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java b/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java new file mode 100644 index 000000000..26b4032bd --- /dev/null +++ b/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java @@ -0,0 +1,301 @@ +/* PasswordEncryptedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.pad.WrongPaddingException; +import gnu.javax.crypto.prng.IPBE; +import gnu.javax.crypto.prng.PRNGFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.InvalidKeyException; +import java.security.SecureRandom; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; + +/** + * An envelope that is encrypted with a password-derived key. + */ +public class PasswordEncryptedEntry extends MaskableEnvelopeEntry implements + PasswordProtectedEntry, Registry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 1; + + // Constructors. + // ------------------------------------------------------------------------ + + public PasswordEncryptedEntry(String cipher, String mode, int keylen, + Properties properties) + { + super(TYPE, properties); + if ((cipher == null || cipher.length() == 0) + || (mode == null || mode.length() == 0)) + { + throw new IllegalArgumentException("cipher nor mode can be empty"); + } + this.properties.put("cipher", cipher); + this.properties.put("mode", mode); + this.properties.put("keylen", String.valueOf(keylen)); + setMasked(false); + } + + private PasswordEncryptedEntry() + { + super(TYPE); + setMasked(true); + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static PasswordEncryptedEntry decode(DataInputStream in, + char[] password) + throws IOException + { + PasswordEncryptedEntry entry = decode(in); + try + { + entry.decrypt(password); + } + catch (WrongPaddingException wpe) + { + throw new MalformedKeyringException("wrong padding in decrypted data"); + } + return entry; + } + + public static PasswordEncryptedEntry decode(DataInputStream in) + throws IOException + { + PasswordEncryptedEntry entry = new PasswordEncryptedEntry(); + entry.defaultDecode(in); + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public void decrypt(char[] password) throws IllegalArgumentException, + WrongPaddingException + { + if (!isMasked() || payload == null) + { + return; + } + IMode mode = getMode(password, IMode.DECRYPTION); + IPad padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + for (int i = 0; i < payload.length; i++) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + DataInputStream in = new DataInputStream( + new ByteArrayInputStream( + buf, + 0, + buf.length + - padlen)); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + setMasked(false); + payload = null; + } + + public void encrypt(char[] password) throws IOException + { + byte[] salt = new byte[8]; + new SecureRandom ().nextBytes (salt); + properties.put("salt", Util.toString(salt)); + IMode mode = getMode(password, IMode.ENCRYPTION); + IPad pad = PadFactory.getInstance("PKCS7"); + pad.init(mode.currentBlockSize()); + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + DataOutputStream out2 = new DataOutputStream(bout); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + entry.encode(out2); + } + byte[] plaintext = bout.toByteArray(); + byte[] padding = pad.pad(plaintext, 0, plaintext.length); + payload = new byte[plaintext.length + padding.length]; + byte[] lastBlock = new byte[mode.currentBlockSize()]; + int l = mode.currentBlockSize() - padding.length; + System.arraycopy(plaintext, plaintext.length - l, lastBlock, 0, l); + System.arraycopy(padding, 0, lastBlock, l, padding.length); + int count = 0; + while (count + mode.currentBlockSize() < plaintext.length) + { + mode.update(plaintext, count, payload, count); + count += mode.currentBlockSize(); + } + mode.update(lastBlock, 0, payload, count); + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + encrypt(password); + encode(out); + } + + protected void encodePayload() throws IOException + { + if (payload == null) + { + throw new IllegalStateException("not encrypted"); + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + private IMode getMode(char[] password, int state) + { + String s = properties.get("salt"); + if (s == null) + { + throw new IllegalArgumentException("no salt"); + } + byte[] salt = Util.toBytesFromString(s); + IBlockCipher cipher = CipherFactory.getInstance(properties.get("cipher")); + if (cipher == null) + { + throw new IllegalArgumentException("no such cipher: " + + properties.get("cipher")); + } + int blockSize = cipher.defaultBlockSize(); + if (properties.containsKey("block-size")) + { + try + { + blockSize = Integer.parseInt(properties.get("block-size")); + } + catch (NumberFormatException nfe) + { + throw new IllegalArgumentException("bad block size: " + + nfe.getMessage()); + } + } + IMode mode = ModeFactory.getInstance(properties.get("mode"), cipher, + blockSize); + if (mode == null) + { + throw new IllegalArgumentException("no such mode: " + + properties.get("mode")); + } + + HashMap pbAttr = new HashMap(); + pbAttr.put(IPBE.PASSWORD, password); + pbAttr.put(IPBE.SALT, salt); + pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); + IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); + kdf.init(pbAttr); + + int keylen = 0; + if (!properties.containsKey("keylen")) + { + throw new IllegalArgumentException("no key length"); + } + try + { + keylen = Integer.parseInt(properties.get("keylen")); + } + catch (NumberFormatException nfe) + { + } + byte[] dk = new byte[keylen]; + byte[] iv = new byte[blockSize]; + try + { + kdf.nextBytes(dk, 0, keylen); + kdf.nextBytes(iv, 0, blockSize); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + HashMap modeAttr = new HashMap(); + modeAttr.put(IMode.KEY_MATERIAL, dk); + modeAttr.put(IMode.STATE, new Integer(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/gnu/javax/crypto/keyring/PasswordProtectedEntry.java b/gnu/javax/crypto/keyring/PasswordProtectedEntry.java new file mode 100644 index 000000000..0dcf73eb8 --- /dev/null +++ b/gnu/javax/crypto/keyring/PasswordProtectedEntry.java @@ -0,0 +1,66 @@ +/* PasswordProtectedEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataOutputStream; +import java.io.IOException; + +public interface PasswordProtectedEntry +{ + + // Constant. + // ------------------------------------------------------------------------ + + /** + * The iteration count for password-based KDFs. + */ + Integer ITERATION_COUNT = new Integer(1000); + + // Method. + // ------------------------------------------------------------------------ + + /** + * Encodes this entry, protected by a password. + * + * @param out The output stream to encode to. + * @param password The password. + * @throws IOException If an I/O error occurs. + */ + void encode(DataOutputStream out, char[] password) throws IOException; +} diff --git a/gnu/javax/crypto/keyring/PrimitiveEntry.java b/gnu/javax/crypto/keyring/PrimitiveEntry.java new file mode 100644 index 000000000..4c9ff0ff1 --- /dev/null +++ b/gnu/javax/crypto/keyring/PrimitiveEntry.java @@ -0,0 +1,129 @@ +/* PrimitiveEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.util.Date; + +/** + * A primitive entry is an entry that contains a single cryptographic entity. + */ +public abstract class PrimitiveEntry extends Entry +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The creation date. */ + protected Date creationDate; + + // Constructor. + // ------------------------------------------------------------------------ + + protected PrimitiveEntry(int type, Date creationDate, Properties properties) + { + super(type, properties); + if (creationDate == null) + { + this.creationDate = new Date(); + } + else + { + this.creationDate = (Date) creationDate.clone(); + } + if (!this.properties.containsKey("alias") + || this.properties.get("alias").length() == 0) + { + throw new IllegalArgumentException( + "primitive entries MUST have an alias"); + } + this.properties.put("creation-date", String.valueOf(creationDate.getTime())); + } + + protected PrimitiveEntry(int type) + { + super(type); + } + + // Instance method. + // ------------------------------------------------------------------------ + + /** + * Returns the alias of this primitive entry. + * + * @return The alias. + */ + public String getAlias() + { + return properties.get("alias"); + } + + /** + * Returns the creation date of this primitive entry. + * + * @return The creation date. + */ + public Date getCreationDate() + { + return (Date) creationDate.clone(); + } + + public boolean equals(Object object) + { + if (!getClass().equals(object.getClass())) + return false; + return getAlias().equals(((PrimitiveEntry) object).getAlias()); + } + + protected final void makeCreationDate() throws MalformedKeyringException + { + String s = properties.get("creation-date"); + if (s == null) + { + throw new MalformedKeyringException("no creation date"); + } + try + { + creationDate = new Date(Long.parseLong(s)); + } + catch (NumberFormatException nfe) + { + throw new MalformedKeyringException("invalid creation date"); + } + } +} diff --git a/gnu/javax/crypto/keyring/PrivateKeyEntry.java b/gnu/javax/crypto/keyring/PrivateKeyEntry.java new file mode 100644 index 000000000..c9c997da0 --- /dev/null +++ b/gnu/javax/crypto/keyring/PrivateKeyEntry.java @@ -0,0 +1,221 @@ +/* PrivateKeyEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.rsa.GnuRSAPrivateKey; + +import gnu.javax.crypto.key.GnuSecretKey; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Date; + +/** + *

An immutable class representing a private or secret key entry.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public final class PrivateKeyEntry extends PrimitiveEntry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final int TYPE = 7; + + /** The key. */ + private Key key; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Creates a new key entry.

+ * + * @param key The key. + * @param creationDate The entry creation date. + * @param properties The entry properties. + * @throws IllegalArgumentException If any parameter is null. + */ + public PrivateKeyEntry(Key key, Date creationDate, Properties properties) + { + super(TYPE, creationDate, properties); + + if (key == null) + { + throw new IllegalArgumentException("no private key"); + } + if (!(key instanceof PrivateKey) && !(key instanceof GnuSecretKey)) + { + throw new IllegalArgumentException("not a private or secret key"); + } + this.key = key; + } + + private PrivateKeyEntry() + { + super(TYPE); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static PrivateKeyEntry decode(DataInputStream in) throws IOException + { + PrivateKeyEntry entry = new PrivateKeyEntry(); + entry.defaultDecode(in); + String type = entry.properties.get("type"); + if (type == null) + { + throw new MalformedKeyringException("no key type"); + } + if (type.equalsIgnoreCase("RAW-DSS")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-RSA")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-DH")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + entry.key = coder.decodePrivateKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW")) + { + entry.key = new GnuSecretKey(entry.payload, null); + } + else if (type.equalsIgnoreCase("PKCS8")) + { + try + { + KeyFactory kf = KeyFactory.getInstance("RSA"); + entry.key = kf.generatePrivate(new PKCS8EncodedKeySpec( + entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + entry.key = kf.generatePrivate(new PKCS8EncodedKeySpec( + entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + throw new MalformedKeyringException( + "could not decode PKCS#8 key"); + } + } + } + else + { + throw new MalformedKeyringException("unsupported key type " + type); + } + return entry; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns this entry's key.

+ * + * @return The key. + */ + public Key getKey() + { + return key; + } + + protected void encodePayload() throws IOException + { + String format = key.getFormat(); + if (key instanceof DSSPrivateKey) + { + properties.put("type", "RAW-DSS"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuRSAPrivateKey) + { + properties.put("type", "RAW-RSA"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuDHPrivateKey) + { + properties.put("type", "RAW-DH"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + payload = coder.encodePrivateKey((PrivateKey) key); + } + else if (key instanceof GnuSecretKey) + { + properties.put("type", "RAW"); + payload = key.getEncoded(); + } + else if (format != null && format.equals("PKCS#8")) + { + properties.put("type", "PKCS8"); + payload = key.getEncoded(); + } + else + { + throw new IllegalArgumentException("unsupported private key"); + } + } +} diff --git a/gnu/javax/crypto/keyring/Properties.java b/gnu/javax/crypto/keyring/Properties.java new file mode 100644 index 000000000..646b5711d --- /dev/null +++ b/gnu/javax/crypto/keyring/Properties.java @@ -0,0 +1,227 @@ +/* Properties.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A set of (name => value) pairs used in keyring entries. + * Keys and values are simple strings, with the key never being empty and + * always treated case-insensitively. + */ +public class Properties implements Cloneable +{ + + // Field. + // ------------------------------------------------------------------------ + + private HashMap props; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Creates a new properties object. + */ + public Properties() + { + props = new HashMap(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Removes all properties from this object. + */ + public void clear() + { + props.clear(); + } + + /** + * Creates a copy of this properties object. + * + * @return The copy. + */ + public Object clone() + { + Properties result = new Properties(); + result.props.putAll(props); + return result; + } + + /** + * Tests if this object contains a given property name. + * + * @param key The key to test. + * @return True if this object contains the given key. + */ + public boolean containsKey(String key) + { + if (key == null || key.length() == 0) + { + return false; + } + return props.containsKey(canonicalize(key)); + } + + /** + * Tests if this object contains a given property value. + * + * @param value The value to test. + * @return True if this object contains the given value. + */ + public boolean containsValue(String value) + { + if (value == null) + { + return false; + } + return props.containsValue(value); + } + + /** + * Adds a new property to this object. + * + * @param key The key, which can neither be null nor empty. + * @param value The value, which cannot be null. + * @return The old value mapped by the key, if any. + * @throws IllegalArgumentException If either the key or value parameter + + * is null, or if the key is empty. + */ + public String put(String key, String value) + { + if (key == null || value == null || key.length() == 0) + { + throw new IllegalArgumentException("key nor value can be null"); + } + return (String) props.put(canonicalize(key), value); + } + + /** + * Returns the value mapped by the given key, or null if there is no + * such mapping. + * + * @param key + */ + public String get(String key) + { + if (key == null || key.length() == 0) + { + return null; + } + return (String) props.get(canonicalize(key)); + } + + /** + * Removes a key and its value from this object. + * + * @param key The key of the property to remove. + * @return The old value mapped by the key, if any. + */ + public String remove(String key) + { + if (key == null || key.length() == 0) + { + return null; + } + return (String) props.remove(canonicalize(key)); + } + + /** + * Decodes a set of properties from the given input stream. + * + * @param in The input stream. + * @throws IOException If an I/O error occurs. + */ + public void decode(DataInputStream in) throws IOException + { + int len = in.readInt(); + MeteredInputStream min = new MeteredInputStream(in, len); + DataInputStream in2 = new DataInputStream(min); + while (!min.limitReached()) + { + String name = in2.readUTF(); + String value = in2.readUTF(); + put(name, value); + } + } + + /** + * Encodes this set of properties to the given output stream. + * + * @param out The output stream to encode to. + * @throws IOException If an I/O error occurs. + */ + public void encode(DataOutputStream out) throws IOException + { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + DataOutputStream out2 = new DataOutputStream(buf); + for (Iterator it = props.entrySet().iterator(); it.hasNext();) + { + Map.Entry entry = (Map.Entry) it.next(); + out2.writeUTF((String) entry.getKey()); + out2.writeUTF((String) entry.getValue()); + } + out.writeInt(buf.size()); + buf.writeTo(out); + } + + public String toString() + { + return props.toString(); + } + + // Own methods. + // ------------------------------------------------------------------------ + + private String canonicalize(String key) + { + return key.toLowerCase(); + } +} diff --git a/gnu/javax/crypto/keyring/PublicKeyEntry.java b/gnu/javax/crypto/keyring/PublicKeyEntry.java new file mode 100644 index 000000000..528e70cc6 --- /dev/null +++ b/gnu/javax/crypto/keyring/PublicKeyEntry.java @@ -0,0 +1,192 @@ +/* PublicKeyEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.keyring; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import java.security.PublicKey; +import java.security.KeyFactory; +import java.security.spec.X509EncodedKeySpec; + +import java.util.Date; + +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.key.KeyPairCodecFactory; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.key.rsa.GnuRSAPublicKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; + +public final class PublicKeyEntry extends PrimitiveEntry +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + public static final int TYPE = 6; + + private PublicKey key; + + // Constructor. + // ------------------------------------------------------------------------ + + public PublicKeyEntry(PublicKey key, Date creationDate, Properties properties) + { + super(TYPE, creationDate, properties); + + if (key == null) + { + throw new IllegalArgumentException("no key specified"); + } + this.key = key; + } + + private PublicKeyEntry() + { + super(TYPE); + } + + // Class method. + // ------------------------------------------------------------------------ + + public static PublicKeyEntry decode(DataInputStream in) throws IOException + { + PublicKeyEntry entry = new PublicKeyEntry(); + entry.defaultDecode(in); + String type = entry.properties.get("type"); + if (type == null) + { + throw new MalformedKeyringException("no key type"); + } + if (type.equalsIgnoreCase("RAW-DSS")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-RSA")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("RAW-DH")) + { + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + entry.key = coder.decodePublicKey(entry.payload); + } + else if (type.equalsIgnoreCase("X.509")) + { + try + { + KeyFactory kf = KeyFactory.getInstance("RSA"); + entry.key = kf.generatePublic(new X509EncodedKeySpec(entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + entry.key = kf.generatePublic(new X509EncodedKeySpec( + entry.payload)); + } + catch (Exception x) + { + } + if (entry.key == null) + { + throw new MalformedKeyringException( + "could not decode X.509 key"); + } + } + } + else + { + throw new MalformedKeyringException("unsupported public key type: " + + type); + } + return entry; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the public key. + * + * @return The public key. + */ + public PublicKey getKey() + { + return key; + } + + protected void encodePayload() throws IOException + { + if (key instanceof DSSPublicKey) + { + properties.put("type", "RAW-DSS"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dss"); + payload = coder.encodePublicKey(key); + } + else if (key instanceof GnuRSAPublicKey) + { + properties.put("type", "RAW-RSA"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("rsa"); + payload = coder.encodePublicKey(key); + } + else if (key instanceof GnuDHPublicKey) + { + properties.put("type", "RAW-DH"); + IKeyPairCodec coder = KeyPairCodecFactory.getInstance("dh"); + payload = coder.encodePublicKey(key); + } + else if (key.getFormat() != null && key.getFormat().equals("X.509")) + { + properties.put("type", "X.509"); + payload = key.getEncoded(); + } + else + { + throw new IllegalArgumentException("cannot encode public key"); + } + } +} diff --git a/gnu/javax/crypto/mac/BaseMac.java b/gnu/javax/crypto/mac/BaseMac.java new file mode 100644 index 000000000..1b42a1644 --- /dev/null +++ b/gnu/javax/crypto/mac/BaseMac.java @@ -0,0 +1,148 @@ +/* BaseMac.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.hash.IMessageDigest; + +import java.util.Map; +import java.security.InvalidKeyException; + +/** + *

A base abstract class to facilitate MAC (Message Authentication + * Code) implementations.

+ */ +public abstract class BaseMac implements IMac +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The canonical name prefix of the MAC. */ + protected String name; + + /** Reference to the underlying hash algorithm instance. */ + protected IMessageDigest underlyingHash; + + /** The length of the truncated output in bytes. */ + protected int truncatedSize; + + /** The authentication key for this instance. */ + // protected transient byte[] K; + // Constructor(s) + // ------------------------------------------------------------------------- + /** + *

Trivial constructor for use by concrete subclasses.

+ * + * @param name the canonical name of this instance. + */ + protected BaseMac(String name) + { + super(); + + this.name = name; + } + + /** + *

Trivial constructor for use by concrete subclasses.

+ * + * @param name the canonical name of this instance. + * @param underlyingHash the underlying message digest algorithm instance. + */ + protected BaseMac(String name, IMessageDigest underlyingHash) + { + this(name); + + if (underlyingHash != null) + { + truncatedSize = underlyingHash.hashSize(); + } + this.underlyingHash = underlyingHash; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.mac.IMac interface implementation ---------------------------- + + public String name() + { + return name; + } + + public int macSize() + { + return truncatedSize; + } + + public void update(byte b) + { + underlyingHash.update(b); + } + + public void update(byte[] b, int offset, int len) + { + underlyingHash.update(b, offset, len); + } + + public void reset() + { + underlyingHash.reset(); + } + + public Object clone() throws CloneNotSupportedException + { + BaseMac result = (BaseMac) super.clone(); + if (this.underlyingHash != null) + result.underlyingHash = (IMessageDigest) this.underlyingHash.clone(); + + return result; + } + + // methods to be implemented by concrete subclasses ------------------------ + + public abstract void init(Map attributes) throws InvalidKeyException, + IllegalStateException; + + public abstract byte[] digest(); + + public abstract boolean selfTest(); +} \ No newline at end of file diff --git a/gnu/javax/crypto/mac/HMac.java b/gnu/javax/crypto/mac/HMac.java new file mode 100644 index 000000000..c1f97b541 --- /dev/null +++ b/gnu/javax/crypto/mac/HMac.java @@ -0,0 +1,328 @@ +/* HMac.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.hash.MD5; +import gnu.java.security.util.Util; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + *

The implementation of the HMAC (Keyed-Hash Message Authentication + * Code).

+ * + *

HMAC can be used in combination with any iterated cryptographic + * hash function. HMAC also uses a secret key for calculation and + * verification of the message authentication values. The main goals behind this + * construction are

+ * + *
    + *
  • To use, without modifications, available hash functions. In + * particular, hash functions that perform well in software, and for which + * code is freely and widely available.
  • + * + *
  • To preserve the original performance of the hash function without + * incurring a significant degradation.
  • + * + *
  • To use and handle keys in a simple way.
  • + * + *
  • To have a well understood cryptographic analysis of the strength of + * the authentication mechanism based on reasonable assumptions on the + * underlying hash function.
  • + * + *
  • To allow for easy replaceability of the underlying hash function in + * case that faster or more secure hash functions are found or required.
  • + *
+ * + *

References:

+ * + *
    + *
  1. RFC 2104HMAC: + * Keyed-Hashing for Message Authentication.
    + * H. Krawczyk, M. Bellare, and R. Canetti.
  2. + *
+ */ +public class HMac extends BaseMac implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String USE_WITH_PKCS5_V2 = "gnu.crypto.hmac.pkcs5"; + + private static final byte IPAD_BYTE = 0x36; + + private static final byte OPAD_BYTE = 0x5C; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + protected int macSize; + + protected int blockSize; + + protected IMessageDigest ipadHash; + + protected IMessageDigest opadHash; + + protected byte[] ipad; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial constructor for use by concrete subclasses.

+ * + * @param underlyingHash the underlying hash algorithm instance. + */ + protected HMac(IMessageDigest underlyingHash) + { + super(Registry.HMAC_NAME_PREFIX + underlyingHash.name(), underlyingHash); + + this.blockSize = underlyingHash.blockSize(); + this.macSize = underlyingHash.hashSize(); + ipadHash = opadHash = null; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() throws CloneNotSupportedException + { + HMac result = (HMac) super.clone(); + if (this.ipadHash != null) + result.ipadHash = (IMessageDigest) this.ipadHash.clone(); + if (this.opadHash != null) + result.opadHash = (IMessageDigest) this.opadHash.clone(); + if (this.ipad != null) + result.ipad = (byte[]) this.ipad.clone(); + + return result; + } + + // implementation of abstract methods in BaseMac --------------------------- + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + Integer ts = (Integer) attributes.get(TRUNCATED_SIZE); + truncatedSize = (ts == null ? macSize : ts.intValue()); + if (truncatedSize < (macSize / 2)) + { + throw new IllegalArgumentException("Truncated size too small"); + } + else if (truncatedSize < 10) + { + throw new IllegalArgumentException("Truncated size less than 80 bits"); + } + + // we dont use/save the key outside this method + byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (K == null) + { // take it as an indication to re-use previous key if set + if (ipadHash == null) + { + throw new InvalidKeyException("Null key"); + } + // we already went through the motions; ie. up to step #4. re-use + underlyingHash = (IMessageDigest) ipadHash.clone(); + return; + } + + // for HMACs used in key-derivation functions (e.g. PBKDF2) the key + // material need not be >= the (output) block size of the underlying + // algorithm + Boolean pkcs5 = (Boolean) attributes.get(USE_WITH_PKCS5_V2); + if (pkcs5 == null) + { + pkcs5 = Boolean.FALSE; + } + if (K.length < macSize && !pkcs5.booleanValue()) + { + throw new InvalidKeyException("Key too short"); + } + + if (K.length > blockSize) + { + // (0) replace K with HASH(K) if K is larger than the hash's + // block size. Then pad with zeros until it is the correct + // size (the next `if'). + underlyingHash.update(K, 0, K.length); + K = underlyingHash.digest(); + } + if (K.length < blockSize) + { + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B=64, then K will be + // appended with 44 zero bytes 0x00) + int limit = (K.length > blockSize) ? blockSize : K.length; + byte[] newK = new byte[blockSize]; + System.arraycopy(K, 0, newK, 0, limit); + K = newK; + } + + underlyingHash.reset(); + opadHash = (IMessageDigest) underlyingHash.clone(); + if (ipad == null) + { + ipad = new byte[blockSize]; + } + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step + // (1) with ipad + // (3) append the stream of data 'text' to the B byte string resulting + // from step (2) + // (4) apply H to the stream generated in step (3) + for (int i = 0; i < blockSize; i++) + { + // underlyingHash.update((byte)(K[i] ^ IPAD_BYTE)); + ipad[i] = (byte) (K[i] ^ IPAD_BYTE); + } + for (int i = 0; i < blockSize; i++) + { + opadHash.update((byte) (K[i] ^ OPAD_BYTE)); + } + + underlyingHash.update(ipad, 0, blockSize); + ipadHash = (IMessageDigest) underlyingHash.clone(); + K = null; + } + + public void reset() + { + super.reset(); + if (ipad != null) + { + underlyingHash.update(ipad, 0, blockSize); + ipadHash = (IMessageDigest) underlyingHash.clone(); + } + } + + public byte[] digest() + { + if (ipadHash == null) + { + throw new IllegalStateException("HMAC not initialised"); + } + + byte[] out = underlyingHash.digest(); + // (5) XOR (bitwise exclusive-OR) the B byte string computed in + // step (1) with opad + underlyingHash = (IMessageDigest) opadHash.clone(); + // (6) append the H result from step (4) to the B byte string + // resulting from step (5) + underlyingHash.update(out, 0, macSize); + // (7) apply H to the stream generated in step (6) and output + // the result + out = underlyingHash.digest(); // which also resets the underlying hash + + // truncate and return + if (truncatedSize == macSize) + return out; + + byte[] result = new byte[truncatedSize]; + System.arraycopy(out, 0, result, 0, truncatedSize); + + return result; + } + + public boolean selfTest() + { + if (valid == null) + { + try + { + IMac mac = new HMac(new MD5()); // use rfc-2104 test vectors + String tv1 = "9294727A3638BB1C13F48EF8158BFC9D"; + String tv3 = "56BE34521D144C88DBB8C733F0E8B3F6"; + byte[] k1 = new byte[] { 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0B, 0x0B }; + byte[] k3 = new byte[] { (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, + (byte) 0xAA }; + byte[] data = new byte[50]; + for (int i = 0; i < 50;) + { + data[i++] = (byte) 0xDD; + } + + HashMap map = new HashMap(); + + // test vector #1 + map.put(MAC_KEY_MATERIAL, k1); + mac.init(map); + mac.update("Hi There".getBytes("ASCII"), 0, 8); + if (!tv1.equals(Util.toString(mac.digest()))) + { + valid = Boolean.FALSE; + } + + // test #2 is not used since it causes a "Key too short" exception + + // test vector #3 + map.put(MAC_KEY_MATERIAL, k3); + mac.init(map); + mac.update(data, 0, 50); + if (!tv3.equals(Util.toString(mac.digest()))) + { + valid = Boolean.FALSE; + } + valid = Boolean.TRUE; + } + catch (Exception x) + { + x.printStackTrace(System.err); + valid = Boolean.FALSE; + } + } + return valid.booleanValue(); + } +} diff --git a/gnu/javax/crypto/mac/HMacFactory.java b/gnu/javax/crypto/mac/HMacFactory.java new file mode 100644 index 000000000..156e6ced5 --- /dev/null +++ b/gnu/javax/crypto/mac/HMacFactory.java @@ -0,0 +1,128 @@ +/* HMacFactory.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + *

A Factory to instantiate Keyed-Hash Message Authentication Code + * (HMAC) algorithm instances.

+ */ +public class HMacFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private HMacFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Return an instance of a HMAC algorithm given the name of its + * underlying hash function, prefixed with the literal defined in + * {@link Registry#HMAC_NAME_PREFIX}.

+ * + * @param name the fully qualified name of the underlying algorithm: composed + * as the concatenation of a literal prefix (see {@link Registry#HMAC_NAME_PREFIX}) + * and the name of the underlying hash algorithm. + * @return an instance of the HMAC algorithm, or null if + * none can be constructed. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static IMac getInstance(String name) + { + if (name == null) + { + return null; + } + + name = name.trim(); + name = name.toLowerCase(); + if (!name.startsWith(HMAC_NAME_PREFIX)) + { + return null; + } + + // strip the prefix + name = name.substring(HMAC_NAME_PREFIX.length()).trim(); + IMac result = new HMac(HashFactory.getInstance(name)); + if (result != null && !result.selfTest()) + { + throw new InternalError(result.name()); + } + + return result; + } + + /** + *

Returns a {@link java.util.Set} of names of HMAC algorithms + * supported by this Factory.

+ * + * @return a {@link java.util.Set} of HMAC algorithm names (Strings). + */ + public static final Set getNames() + { + Set hashNames = HashFactory.getNames(); + HashSet hs = new HashSet(); + for (Iterator it = hashNames.iterator(); it.hasNext();) + { + hs.add(HMAC_NAME_PREFIX + ((String) it.next())); + } + + return Collections.unmodifiableSet(hs); + } + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/mac/IMac.java b/gnu/javax/crypto/mac/IMac.java new file mode 100644 index 000000000..c4170c42c --- /dev/null +++ b/gnu/javax/crypto/mac/IMac.java @@ -0,0 +1,197 @@ +/* IMac.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import java.util.Map; +import java.security.InvalidKeyException; + +/** + *

The basic visible methods of any MAC (Message Authentication Code) + * algorithm.

+ * + *

A MAC provides a way to check the integrity of information + * transmitted over, or stored in, an unreliable medium, based on a secret key. + * Typically, MACs are used between two parties, that share a common + * secret key, in order to validate information transmitted between them.

+ * + *

When a MAC algorithm is based on a cryptographic hash function, it + * is then called to a HMAC (Hashed Message Authentication Code) --see + * RFC-2104.

+ * + * Another type of MAC algorithms exist: UMAC or Universal Message + * Authentication Code, described in + * + * draft-krovetz-umac-01.txt.

+ * + *

With UMACs, the sender and receiver share a common secret key (the + * MAC key) which determines:

+ * + *
    + *
  • The key for a universal hash function. This hash function is + * non-cryptographic, in the sense that it does not need to have any + * cryptographic hardness property. Rather, it needs to satisfy some + * combinatorial property, which can be proven to hold without relying on + * unproven hardness assumptions.
  • + * + *
  • The key for a pseudorandom function. This is where one needs a + * cryptographic hardness assumption. The pseudorandom function may be + * obtained from a block cipher or a cryptographic hash function. + *
  • + *
+ * + *

References:

+ * + *
    + *
  1. RFC 2104HMAC: + * Keyed-Hashing for Message Authentication.
    + * H. Krawczyk, M. Bellare, and R. Canetti.
  2. + * + *
  3. + * UMAC: Message Authentication Code using Universal Hashing.
    + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.
  4. + *
+ */ +public interface IMac +{ + + // Constants + // ------------------------------------------------------------------------- + + /** + * Property name of the user-supplied key material. The value associated to + * this property name is taken to be a byte array. + */ + String MAC_KEY_MATERIAL = "gnu.crypto.mac.key.material"; + + /** + *

Property name of the desired truncated output size in bytes. The value + * associated to this property name is taken to be an integer. If no value + * is specified in the attributes map at initialisation time, then all bytes + * of the underlying hash algorithm's output are emitted.

+ * + *

This implementation, follows the recommendation of the RFC 2104 + * authors; specifically:

+ * + *
+   *    We recommend that the output length t be not less than half the
+   *    length of the hash output (to match the birthday attack bound)
+   *    and not less than 80 bits (a suitable lower bound on the number
+   *    of bits that need to be predicted by an attacker).
+   * 
+ */ + String TRUNCATED_SIZE = "gnu.crypto.mac.truncated.size"; + + // Methods + // ------------------------------------------------------------------------- + + /** + *

Returns the canonical name of this algorithm.

+ * + * @return the canonical name of this algorithm. + */ + String name(); + + /** + *

Returns the output length in bytes of this MAC algorithm.

+ * + * @return the output length in bytes of this MAC algorithm. + */ + int macSize(); + + /** + *

Initialises the algorithm with designated attributes. Permissible names + * and values are described in the class documentation above.

+ * + * @param attributes a set of name-value pairs that describe the desired + * future instance behaviour. + * @exception InvalidKeyException if the key data is invalid. + * @exception IllegalStateException if the instance is already initialised. + * @see #MAC_KEY_MATERIAL + */ + void init(Map attributes) throws InvalidKeyException, IllegalStateException; + + /** + *

Continues a MAC operation using the input byte.

+ * + * @param b the input byte to digest. + */ + void update(byte b); + + /** + *

Continues a MAC operation, by filling the buffer, processing + * data in the algorithm's MAC_SIZE-bit block(s), updating the context and + * count, and buffering the remaining bytes in buffer for the next + * operation.

+ * + * @param in the input block. + * @param offset start of meaningful bytes in input block. + * @param length number of bytes, in input block, to consider. + */ + void update(byte[] in, int offset, int length); + + /** + *

Completes the MAC by performing final operations such as + * padding and resetting the instance.

+ * + * @return the array of bytes representing the MAC value. + */ + byte[] digest(); + + /** + *

Resets the algorithm instance for re-initialisation and use with other + * characteristics. This method always succeeds.

+ */ + void reset(); + + /** + *

A basic test. Ensures that the MAC of a pre-determined message is equal + * to a known pre-computed value.

+ * + * @return true if the implementation passes a basic self-test. + * Returns false otherwise. + */ + boolean selfTest(); + + /** + *

Returns a clone copy of this instance.

+ * + * @return a clone copy of this instance. + */ + Object clone() throws CloneNotSupportedException; +} \ No newline at end of file diff --git a/gnu/javax/crypto/mac/MacFactory.java b/gnu/javax/crypto/mac/MacFactory.java new file mode 100644 index 000000000..d8f8bcfce --- /dev/null +++ b/gnu/javax/crypto/mac/MacFactory.java @@ -0,0 +1,164 @@ +/* MacFactory.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + *

A Factory that instantiates instances of every supported Message + * Authentication Code algorithms, including all HMAC algorithms.

+ */ +public class MacFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private MacFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a MAC algorithm given its name.

+ * + * @param name the name of the MAC algorithm. + * @return an instance of the MAC algorithm, or null if + * none can be constructed. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static IMac getInstance(String name) + { + if (name == null) + { + return null; + } + + name = name.trim(); + name = name.toLowerCase(); + if (name.startsWith(HMAC_NAME_PREFIX)) + { + return HMacFactory.getInstance(name); + } + + if (name.startsWith(OMAC_PREFIX)) + { + name = name.substring(OMAC_PREFIX.length()); + IBlockCipher cipher = CipherFactory.getInstance(name); + if (cipher == null) + { + return null; + } + return new OMAC(cipher); + } + + IMac result = null; + if (name.equalsIgnoreCase(UHASH32)) + { + result = new UHash32(); + } + else if (name.equalsIgnoreCase(UMAC32)) + { + result = new UMac32(); + } + else if (name.equalsIgnoreCase(TMMH16)) + { + result = new TMMH16(); + } + // else if (name.equalsIgnoreCase(TMMH32)) { + // result = new TMMH32(); + // } + + if (result != null && !result.selfTest()) + { + throw new InternalError(result.name()); + } + + return result; + } + + /** + *

Returns a {@link java.util.Set} of names of MAC algorithms + * supported by this Factory.

+ * + * @return a {@link java.util.Set} of MAC names (Strings). + */ + public static final Set getNames() + { + synchronized (MacFactory.class) + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.addAll(HMacFactory.getNames()); + hs.add(UHASH32); + hs.add(UMAC32); + hs.add(TMMH16); + // hs.add(TMMH32); + + for (Iterator it = CipherFactory.getNames().iterator(); it.hasNext();) + { + hs.add(OMAC_PREFIX + it.next()); + } + + names = Collections.unmodifiableSet(hs); + } + } + return names; + } + + private static Set names; + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/mac/MacInputStream.java b/gnu/javax/crypto/mac/MacInputStream.java new file mode 100644 index 000000000..9acd18b19 --- /dev/null +++ b/gnu/javax/crypto/mac/MacInputStream.java @@ -0,0 +1,138 @@ +/* MacInputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * A filtering input stream that computes a MAC (message authentication code) + * over all data read from the stream. + */ +public class MacInputStream extends FilterInputStream +{ + + // Field. + // ------------------------------------------------------------------------ + + /** + * The digesting state. The MAC is updated only if this flag is true. + */ + private boolean digesting; + + /** + * The MAC being updated. + */ + private IMac mac; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Creates a new MacInputStream. The stream is initially set to digest + * data written, the mac argument must have already been initialized, + * and the mac argument is not cloned. + * + * @param in The underlying input stream. + * @param mac The mac instance to use. + */ + public MacInputStream(InputStream in, IMac mac) + { + super(in); + if (mac == null) + throw new NullPointerException(); + this.mac = mac; + digesting = true; + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Returns the MAC this stream is updating. + * + * @return The MAC. + */ + public IMac getMac() + { + return mac; + } + + /** + * Sets the MAC this stream is updating, which must have already been + * initialized. The argument is not cloned by this method. + * + * @param mac The new MAC. + * @throws NullPointerException If the argument is null. + */ + public void setMac(IMac mac) + { + if (mac == null) + throw new NullPointerException(); + this.mac = mac; + } + + /** + * Turns the digesting state on or off. When off, the MAC will not be + * updated when data is written to the stream. + * + * @param flag The new digesting state. + */ + public void on(boolean flag) + { + digesting = flag; + } + + public int read() throws IOException + { + int i = in.read(); + if (digesting && i != -1) + mac.update((byte) i); + return i; + } + + public int read(byte[] buf, int off, int len) throws IOException + { + int i = in.read(buf, off, len); + if (digesting && i != -1) + mac.update(buf, off, i); + return i; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mac/MacOutputStream.java b/gnu/javax/crypto/mac/MacOutputStream.java new file mode 100644 index 000000000..a48d25ba3 --- /dev/null +++ b/gnu/javax/crypto/mac/MacOutputStream.java @@ -0,0 +1,140 @@ +/* MacOutputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + *

A filtering output stream that computes a MAC (message authentication + * code) over all data written to the stream.

+ */ +public class MacOutputStream extends FilterOutputStream +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The digesting state. The MAC is updated only if this flag is true. */ + private boolean digesting; + + /** The MAC being updated. */ + private IMac mac; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Creates a new MacOutputStream. The stream is initially set + * to digest data written, the mac argument must have already + * been initialized, and the mac argument is not cloned.

+ * + * @param out The underlying output stream. + * @param mac The mac instance to use. + */ + public MacOutputStream(OutputStream out, IMac mac) + { + super(out); + if (mac == null) + { + throw new NullPointerException(); + } + this.mac = mac; + digesting = true; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns the MAC this stream is updating.

+ * + * @return The MAC. + */ + public IMac getMac() + { + return mac; + } + + /** + *

Sets the MAC this stream is updating, which must have already been + * initialized. The argument is not cloned by this method.

+ * + * @param mac The non-null new MAC. + * @throws NullPointerException If the argument is null. + */ + public void setMac(IMac mac) + { + if (mac == null) + { + throw new NullPointerException(); + } + this.mac = mac; + } + + /** + *

Turns the digesting state on or off. When off, the MAC will not be + * updated when data is written to the stream.

+ * + * @param flag The new digesting state. + */ + public void on(boolean flag) + { + digesting = flag; + } + + public void write(int b) throws IOException + { + if (digesting) + { + mac.update((byte) b); + } + out.write(b); + } + + public void write(byte[] buf, int off, int len) throws IOException + { + if (digesting) + { + mac.update(buf, off, len); + } + out.write(buf, off, len); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mac/OMAC.java b/gnu/javax/crypto/mac/OMAC.java new file mode 100644 index 000000000..c83320a1b --- /dev/null +++ b/gnu/javax/crypto/mac/OMAC.java @@ -0,0 +1,402 @@ +/* OMAC.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; + +import java.security.InvalidKeyException; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + *

The One-Key CBC MAC, OMAC. This message authentication code is based on + * a block cipher in CBC mode.

+ * + *

References:

+ *
    + *
  1. Tetsu Iwata and Kaoru Kurosawa, OMAC: One-Key CBC + * MAC.
  2. + *
+ */ +public class OMAC implements IMac +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + private static final boolean DEBUG = false; + + private static void debug(String msg) + { + System.out.print(">>> OMAC: "); + System.out.println(msg); + } + + private static final byte C1 = (byte) 0x87; + + private static final byte C2 = 0x1b; + + // Test key for OMAC-AES-128 + private static final byte[] KEY0 = Util.toBytesFromString("2b7e151628aed2a6abf7158809cf4f3c"); + + // Test MAC for zero-length input. + private static final byte[] DIGEST0 = Util.toBytesFromString("bb1d6929e95937287fa37d129b756746"); + + private static Boolean valid; + + private final IBlockCipher cipher; + + private final String name; + + private IMode mode; + + private int blockSize; + + private int outputSize; + + private byte[] Lu, Lu2; + + private byte[] M; + + private byte[] Y; + + private boolean init; + + private int index; + + // Constructor. + // ------------------------------------------------------------------------ + + public OMAC(IBlockCipher cipher) + { + this.cipher = cipher; + this.name = "OMAC-" + cipher.name(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public Object clone() + { + return new OMAC(cipher); + } + + public String name() + { + return name; + } + + public int macSize() + { + return outputSize; + } + + public void init(Map attrib) throws InvalidKeyException + { + HashMap attrib2 = new HashMap(); + attrib2.put(IBlockCipher.KEY_MATERIAL, attrib.get(MAC_KEY_MATERIAL)); + cipher.reset(); + cipher.init(attrib2); + + blockSize = cipher.currentBlockSize(); + Integer os = (Integer) attrib.get(TRUNCATED_SIZE); + if (os != null) + { + outputSize = os.intValue(); + if (outputSize < 0 || outputSize > blockSize) + { + throw new IllegalArgumentException("truncated size out of range"); + } + } + else + { + outputSize = blockSize; + } + + byte[] L = new byte[blockSize]; + cipher.encryptBlock(L, 0, L, 0); + + if (DEBUG) + { + debug("L = " + Util.toString(L).toLowerCase()); + } + + if (Lu != null) + { + Arrays.fill(Lu, (byte) 0); + if (Lu.length != blockSize) + { + Lu = new byte[blockSize]; + } + } + else + { + Lu = new byte[blockSize]; + } + if (Lu2 != null) + { + Arrays.fill(Lu2, (byte) 0); + if (Lu2.length != blockSize) + { + Lu2 = new byte[blockSize]; + } + } + else + { + Lu2 = new byte[blockSize]; + } + + boolean msb = (L[0] & 0x80) != 0; + for (int i = 0; i < blockSize; i++) + { + Lu[i] = (byte) (L[i] << 1 & 0xFF); + if (i + 1 < blockSize) + { + Lu[i] |= (byte) ((L[i + 1] & 0x80) >> 7); + } + } + if (msb) + { + if (blockSize == 16) + { + Lu[Lu.length - 1] ^= C1; + } + else if (blockSize == 8) + { + Lu[Lu.length - 1] ^= C2; + } + else + { + throw new IllegalArgumentException( + "unsupported cipher block size: " + + blockSize); + } + } + if (DEBUG) + { + debug("Lu = " + Util.toString(Lu).toLowerCase()); + } + + msb = (Lu[0] & 0x80) != 0; + for (int i = 0; i < blockSize; i++) + { + Lu2[i] = (byte) (Lu[i] << 1 & 0xFF); + if (i + 1 < blockSize) + { + Lu2[i] |= (byte) ((Lu[i + 1] & 0x80) >> 7); + } + } + if (msb) + { + if (blockSize == 16) + { + Lu2[Lu2.length - 1] ^= C1; + } + else + { + Lu2[Lu2.length - 1] ^= C2; + } + } + if (DEBUG) + { + debug("Lu2 = " + Util.toString(Lu2).toLowerCase()); + } + + if (M != null) + { + Arrays.fill(M, (byte) 0); + if (M.length != blockSize) + { + M = new byte[blockSize]; + } + } + else + { + M = new byte[blockSize]; + } + if (Y != null) + { + Arrays.fill(Y, (byte) 0); + if (Y.length != blockSize) + { + Y = new byte[blockSize]; + } + } + else + { + Y = new byte[blockSize]; + } + + index = 0; + init = true; + } + + public void update(byte b) + { + if (!init) + { + throw new IllegalStateException("not initialized"); + } + if (index == M.length) + { + process(); + index = 0; + } + M[index++] = b; + } + + public void update(byte[] buf, int off, int len) + { + if (!init) + { + throw new IllegalStateException("not initialized"); + } + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new IndexOutOfBoundsException("size=" + buf.length + "; off=" + + off + "; len=" + len); + } + for (int i = 0; i < len;) + { + if (index == blockSize) + { + process(); + index = 0; + } + int count = Math.min(blockSize - index, len - i); + System.arraycopy(buf, off + i, M, index, count); + index += count; + i += count; + } + } + + public byte[] digest() + { + byte[] b = new byte[outputSize]; + digest(b, 0); + return b; + } + + public void digest(byte[] out, int off) + { + if (!init) + { + throw new IllegalStateException("not initialized"); + } + if (off < 0 || off + outputSize > out.length) + { + throw new IndexOutOfBoundsException("size=" + out.length + "; off=" + + off + "; len=" + outputSize); + } + byte[] T = new byte[blockSize]; + byte[] L = Lu; + if (index < blockSize) + { + M[index++] = (byte) 0x80; + while (index < blockSize) + { + M[index++] = 0; + } + L = Lu2; + } + for (int i = 0; i < blockSize; i++) + { + T[i] = (byte) (M[i] ^ Y[i] ^ L[i]); + } + cipher.encryptBlock(T, 0, T, 0); + System.arraycopy(T, 0, out, off, outputSize); + reset(); + } + + public void reset() + { + index = 0; + if (Y != null) + { + Arrays.fill(Y, (byte) 0); + } + if (M != null) + { + Arrays.fill(M, (byte) 0); + } + } + + public boolean selfTest() + { + OMAC mac = new OMAC(CipherFactory.getInstance(Registry.AES_CIPHER)); + mac.reset(); + Map attr = new HashMap(); + attr.put(MAC_KEY_MATERIAL, KEY0); + byte[] digest = null; + try + { + mac.init(attr); + digest = mac.digest(); + } + catch (Exception x) + { + return false; + } + if (digest == null) + { + return false; + } + return Arrays.equals(DIGEST0, digest); + } + + // Own methods. + // ------------------------------------------------------------------------ + + private void process() + { + for (int i = 0; i < blockSize; i++) + { + M[i] = (byte) (M[i] ^ Y[i]); + } + cipher.encryptBlock(M, 0, Y, 0); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mac/TMMH16.java b/gnu/javax/crypto/mac/TMMH16.java new file mode 100644 index 000000000..af6e78fcf --- /dev/null +++ b/gnu/javax/crypto/mac/TMMH16.java @@ -0,0 +1,402 @@ +/* TMMH16.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +import java.security.InvalidKeyException; +import java.util.Map; + +/** + *

TMMH is a universal hash function suitable for message + * authentication in the Wegman-Carter paradigm, as in the Stream Cipher + * Security Transform. It is simple, quick, and especially appropriate for + * Digital Signal Processors and other processors with a fast multiply + * operation, though a straightforward implementation requires storage equal in + * length to the largest message to be hashed.

+ * + *

TMMH is a simple hash function which maps a key and a message to a + * hash value. There are two versions of TMMH: TMMH/16 and TMMH/32. TMMH + * can be used as a message authentication code, as described in Section 5 (see + * References).

+ * + *

The key, message, and hash value are all octet strings, and the lengths of + * these quantities are denoted as KEY_LENGTH, + * MESSAGE_LENGTH, and TAG_LENGTH, respectively. The + * values of KEY_LENGTH and TAG_LENGTH + * MUST be fixed for any particular fixed value of the key, and + * must obey the alignment restrictions described below.

+ * + *

The parameter MAX_HASH_LENGTH, which denotes the maximum + * value which MESSAGE_LENGTH may take, is equal to + * KEY_LENGTH - TAG_LENGTH.

+ * + *

References:

+ * + *
    + *
  1. + * The Truncated Multi-Modular Hash Function (TMMH), David A. McGrew.
  2. + *
+ */ +public class TMMH16 extends BaseMac implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + public static final String TAG_LENGTH = "gnu.crypto.mac.tmmh.tag.length"; + + public static final String KEYSTREAM = "gnu.crypto.mac.tmmh.keystream"; + + public static final String PREFIX = "gnu.crypto.mac.tmmh.prefix"; + + private static final int P = (1 << 16) + 1; // the TMMH/16 prime + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + private int tagWords = 0; // the tagLength expressed in words + + private IRandom keystream = null; // the keystream generator + + private byte[] prefix; // mask to use when operating as an authentication f. + + private long keyWords; // key words counter + + private long msgLength; // in bytes + + private long msgWords; // should be = msgLength * WORD_LENGTH + + private int[] context; // the tmmh running context; length == TAG_WORDS + + private int[] K0; // the first TAG_WORDS words of the keystream + + private int[] Ki; // the sliding TAG_WORDS words of the keystream + + private int Mi; // current message word being constructed + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public TMMH16() + { + super(Registry.TMMH16); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // gnu.crypto.mac.IMac interface implementation ---------------------------- + + public int macSize() + { + return tagWords * 2; + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + int wantTagLength = 0; + Integer tagLength = (Integer) attributes.get(TAG_LENGTH); // get tag length + if (tagLength == null) + { + if (tagWords == 0) + { // was never set + throw new IllegalArgumentException(TAG_LENGTH); + } // else re-use + } + else + { // check if positive and is divisible by WORD_LENGTH + wantTagLength = tagLength.intValue(); + if (wantTagLength < 2 || (wantTagLength % 2 != 0)) + { + throw new IllegalArgumentException(TAG_LENGTH); + } + else if (wantTagLength > (512 / 8)) + { // 512-bits is our maximum + throw new IllegalArgumentException(TAG_LENGTH); + } + + tagWords = wantTagLength / 2; // init local vars + K0 = new int[tagWords]; + Ki = new int[tagWords]; + context = new int[tagWords]; + } + + prefix = (byte[]) attributes.get(PREFIX); + if (prefix == null) + { // default to all-zeroes + prefix = new byte[tagWords * 2]; + } + else + { // ensure it's as long as it should + if (prefix.length != tagWords * 2) + { + throw new IllegalArgumentException(PREFIX); + } + } + + IRandom prng = (IRandom) attributes.get(KEYSTREAM); // get keystream + if (prng == null) + { + if (keystream == null) + { + throw new IllegalArgumentException(KEYSTREAM); + } // else reuse + } + else + { + keystream = prng; + } + + reset(); // reset context variables + for (int i = 0; i < tagWords; i++) + { // init starting key words + Ki[i] = K0[i] = getNextKeyWord(keystream); + } + } + + // The words of the key are denoted as K[1], K[2], ..., K[KEY_WORDS], and the + // words of the message (after zero padding, if needed) are denoted as M[1], + // M[2], ..., M[MSG_WORDS], where MSG_WORDS is the smallest number such that + // 2 * MSG_WORDS is at least MESSAGE_LENGTH, and KEY_WORDS is KEY_LENGTH / 2. + // + // If MESSAGE_LENGTH is greater than MAX_HASH_LENGTH, then the value of + // TMMH/16 is undefined. Implementations MUST indicate an error if asked to + // hash a message with such a length. Otherwise, the hash value is defined + // to be the length TAG_WORDS sequence of words in which the j-th word in the + // sequence is defined as + // + // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2] + // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16 + // + // where j ranges from 1 to TAG_WORDS. + public void update(byte b) + { + this.update(b, keystream); + } + + public void update(byte[] b, int offset, int len) + { + for (int i = 0; i < len; i++) + { + this.update(b[offset + i], keystream); + } + } + + // For TMMH/16, KEY_LENGTH and TAG_LENGTH MUST be a multiple of two. The key, + // message, and hash value are treated as a sequence of unsigned sixteen bit + // integers in network byte order. (In this section, we call such an integer + // a word.) If MESSAGE_LENGTH is odd, then a zero byte is appended to the + // message to align it on a word boundary, though this process does not + // change the value of MESSAGE_LENGTH. + // + // ... Otherwise, the hash value is defined to be the length TAG_WORDS + // sequence of words in which the j-th word in the sequence is defined as + // + // [ [ K[j] * MESSAGE_LENGTH +32 K[j+1] * M[1] +32 K[j+2] * M[2] + // +32 ... K[j+MSG_WORDS] * M[MSG_WORDS] ] modulo p ] modulo 2^16 + // + // where j ranges from 1 to TAG_WORDS. + // + // Here, TAG_WORDS is equal to TAG_LENGTH / 2, and p is equal to 2^16 + 1. + // The symbol * denotes multiplication and the symbol +32 denotes addition + // modulo 2^32. + public byte[] digest() + { + return this.digest(keystream); + } + + public void reset() + { + msgLength = msgWords = keyWords = 0L; + Mi = 0; + for (int i = 0; i < tagWords; i++) + { + context[i] = 0; + } + } + + public boolean selfTest() + { + if (valid == null) + { + // TODO: compute and test equality with one known vector + + valid = Boolean.TRUE; + } + return valid.booleanValue(); + } + + // Cloneable interface implementation --------------------------------------- + + public Object clone() throws CloneNotSupportedException + { + TMMH16 result = (TMMH16) super.clone(); + + if (this.keystream != null) + result.keystream = (IRandom) this.keystream.clone(); + + if (this.prefix != null) + result.prefix = (byte[]) this.prefix.clone(); + + if (this.context != null) + result.context = (int[]) this.context.clone(); + + if (this.K0 != null) + result.K0 = (int[]) this.K0.clone(); + + if (this.Ki != null) + result.Ki = (int[]) this.Ki.clone(); + + return result; + } + + // own methods ------------------------------------------------------------- + + /** + *

Similar to the same method with one argument, but uses the designated + * random number generator to compute needed keying material.

+ * + * @param b the byte to process. + * @param prng the source of randomness to use. + */ + public void update(byte b, IRandom prng) + { + Mi <<= 8; // update message buffer + Mi |= b & 0xFF; + msgLength++; // update message length (bytes) + if (msgLength % 2 == 0) + { // got a full word + msgWords++; // update message words counter + System.arraycopy(Ki, 1, Ki, 0, tagWords - 1); // 1. shift Ki up by 1 + Ki[tagWords - 1] = getNextKeyWord(prng); // 2. fill last box of Ki + long t; // temp var to allow working in modulo 2^32 + for (int i = 0; i < tagWords; i++) + { // 3. update context + t = context[i] & 0xFFFFFFFFL; + t += Ki[i] * Mi; + context[i] = (int) t; + } + Mi = 0; // reset message buffer + } + } + + /** + *

Similar to the same method with three arguments, but uses the + * designated random number generator to compute needed keying material.

+ * + * @param b the byte array to process. + * @param offset the starting offset in b to start considering + * the bytes to process. + * @param len the number of bytes in b starting from + * offset to process. + * @param prng the source of randomness to use. + */ + public void update(byte[] b, int offset, int len, IRandom prng) + { + for (int i = 0; i < len; i++) + { + this.update(b[offset + i], prng); + } + } + + /** + *

Similar to the same method with no arguments, but uses the designated + * random number generator to compute needed keying material.

+ * + * @param prng the source of randomness to use. + * @return the final result of the algorithm. + */ + public byte[] digest(IRandom prng) + { + doFinalRound(prng); + byte[] result = new byte[tagWords * 2]; + for (int i = 0, j = 0; i < tagWords; i++) + { + result[j] = (byte) ((context[i] >>> 8) ^ prefix[j]); + j++; + result[j] = (byte) (context[i] ^ prefix[j]); + j++; + } + + reset(); + return result; + } + + private int getNextKeyWord(IRandom prng) + { + int result = 0; + try + { + result = (prng.nextByte() & 0xFF) << 8 | (prng.nextByte() & 0xFF); + } + catch (LimitReachedException x) + { + throw new RuntimeException(String.valueOf(x)); + } + + keyWords++; // update key words counter + return result; + } + + private void doFinalRound(IRandom prng) + { + long limit = msgLength; // formula works on real message length + while (msgLength % 2 != 0) + { + update((byte) 0x00, prng); + } + long t; + for (int i = 0; i < tagWords; i++) + { + t = context[i] & 0xFFFFFFFFL; + t += K0[i] * limit; + t %= P; + context[i] = (int) t; + } + } +} diff --git a/gnu/javax/crypto/mac/UHash32.java b/gnu/javax/crypto/mac/UHash32.java new file mode 100644 index 000000000..8abb0255e --- /dev/null +++ b/gnu/javax/crypto/mac/UHash32.java @@ -0,0 +1,957 @@ +/* UHash32.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + *

UHASH is a keyed hash function, which takes as input a string of + * arbitrary length, and produces as output a string of fixed length (such as 8 + * bytes). The actual output length depends on the parameter UMAC-OUTPUT-LEN.

+ * + *

UHASH has been shown to be epsilon-ASU ("Almost Strongly + * Universal"), where epsilon is a small (parameter-dependent) real number. + * Informally, saying that a keyed hash function is epsilon-ASU means + * that for any two distinct fixed input strings, the two outputs of the hash + * function with a random key "look almost like a pair of random strings". The + * number epsilon measures how non-random the output strings may be.

+ * + * UHASH has been designed to be fast by exploiting several architectural + * features of modern commodity processors. It was specifically designed for use + * in UMAC. But UHASH is useful beyond that domain, and can be + * easily adopted for other purposes.

+ * + * UHASH does its work in three layers. First, a hash function called + * NH is used to compress input messages into strings which are + * typically many times smaller than the input message. Second, the compressed + * message is hashed with an optimized polynomial hash function into a + * fixed-length 16-byte string. Finally, the 16-byte string is hashed using an + * inner-product hash into a string of length WORD-LEN bytes. These three + * layers are repeated (with a modified key) until the outputs total + * UMAC-OUTPUT-LEN bytes.

+ * + *

References:

+ * + *
    + *
  1. + * UMAC: Message Authentication Code using Universal Hashing.
    + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.
  2. + *
+ */ +public class UHash32 extends BaseMac +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // UMAC prime values + private static final BigInteger PRIME_19 = BigInteger.valueOf(0x7FFFFL); + + private static final BigInteger PRIME_32 = BigInteger.valueOf(0xFFFFFFFBL); + + private static final BigInteger PRIME_36 = BigInteger.valueOf(0xFFFFFFFFBL); + + private static final BigInteger PRIME_64 = new BigInteger( + 1, + new byte[] { + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xC5 }); + + private static final BigInteger PRIME_128 = new BigInteger( + 1, + new byte[] { + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0xFF, + (byte) 0x61 }); + + static final BigInteger TWO = BigInteger.valueOf(2L); + + static final long BOUNDARY = TWO.shiftLeft(17).longValue(); + + // 2**64 - 2**32 + static final BigInteger LOWER_RANGE = TWO.pow(64).subtract(TWO.pow(32)); + + // 2**128 - 2**96 + static final BigInteger UPPER_RANGE = TWO.pow(128).subtract(TWO.pow(96)); + + static final byte[] ALL_ZEROES = new byte[32]; + + int streams; + + L1Hash32[] l1hash; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public UHash32() + { + super("uhash32"); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param that the instance to clone. + */ + private UHash32(UHash32 that) + { + this(); + + this.streams = that.streams; + if (that.l1hash != null) + { + // this.l1hash = new L1Hash32[that.l1hash.length]; + this.l1hash = new L1Hash32[that.streams]; + // for (int i = 0; i < that.l1hash.length; i++) { + for (int i = 0; i < that.streams; i++) + { + if (that.l1hash[i] != null) + { + this.l1hash[i] = (L1Hash32) that.l1hash[i].clone(); + } + } + } + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

The prime numbers used in UMAC are:

+ *
+   *   +-----+--------------------+---------------------------------------+
+   *   |  x  | prime(x) [Decimal] | prime(x) [Hexadecimal]                |
+   *   +-----+--------------------+---------------------------------------+
+   *   | 19  | 2^19  - 1          | 0x0007FFFF                            |
+   *   | 32  | 2^32  - 5          | 0xFFFFFFFB                            |
+   *   | 36  | 2^36  - 5          | 0x0000000F FFFFFFFB                   |
+   *   | 64  | 2^64  - 59         | 0xFFFFFFFF FFFFFFC5                   |
+   *   | 128 | 2^128 - 159        | 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFF61 |
+   *   +-----+--------------------+---------------------------------------+
+   *
+ * + * @param n a number of bits. + * @return the largest prime number less than 2**n. + */ + static final BigInteger prime(int n) + { + switch (n) + { + case 19: + return PRIME_19; + case 32: + return PRIME_32; + case 36: + return PRIME_36; + case 64: + return PRIME_64; + case 128: + return PRIME_128; + default: + throw new IllegalArgumentException("Undefined prime(" + + String.valueOf(n) + ")"); + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new UHash32(this); + } + + // gnu.crypto.mac.IMac interface implementation ---------------------------- + + public int macSize() + { + return UMac32.OUTPUT_LEN; + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (K == null) + { + throw new InvalidKeyException("Null Key"); + } + if (K.length != UMac32.KEY_LEN) + { + throw new InvalidKeyException("Invalid Key length: " + + String.valueOf(K.length)); + } + + // Calculate iterations needed to make UMAC-OUTPUT-LEN bytes + streams = (UMac32.OUTPUT_LEN + 3) / 4; + + // Define total key needed for all iterations using UMacGenerator. + // L1Key and L3Key1 both reuse most key between iterations. + IRandom kdf1 = new UMacGenerator(); + IRandom kdf2 = new UMacGenerator(); + IRandom kdf3 = new UMacGenerator(); + IRandom kdf4 = new UMacGenerator(); + Map map = new HashMap(); + map.put(IBlockCipher.KEY_MATERIAL, K); + map.put(UMacGenerator.INDEX, new Integer(0)); + kdf1.init(map); + map.put(UMacGenerator.INDEX, new Integer(1)); + kdf2.init(map); + map.put(UMacGenerator.INDEX, new Integer(2)); + kdf3.init(map); + map.put(UMacGenerator.INDEX, new Integer(3)); + kdf4.init(map); + + // need to generate all bytes for use later in a Toepliz construction + byte[] L1Key = new byte[UMac32.L1_KEY_LEN + (streams - 1) * 16]; + try + { + kdf1.nextBytes(L1Key, 0, L1Key.length); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L1Key reached limit"); + } + + l1hash = new L1Hash32[streams]; + for (int i = 0; i < streams; i++) + { + byte[] k1 = new byte[UMac32.L1_KEY_LEN]; + System.arraycopy(L1Key, i * 16, k1, 0, UMac32.L1_KEY_LEN); + byte[] k2 = new byte[24]; + try + { + kdf2.nextBytes(k2, 0, 24); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L2Key reached limit"); + } + + byte[] k31 = new byte[64]; + try + { + kdf3.nextBytes(k31, 0, 64); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L3Key1 reached limit"); + } + + byte[] k32 = new byte[4]; + try + { + kdf4.nextBytes(k32, 0, 4); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException("KDF for L3Key2 reached limit"); + } + + L1Hash32 mac = new L1Hash32(); + mac.init(k1, k2, k31, k32); + l1hash[i] = mac; + } + } + + public void update(byte b) + { + for (int i = 0; i < streams; i++) + { + l1hash[i].update(b); + } + } + + public void update(byte[] b, int offset, int len) + { + for (int i = 0; i < len; i++) + { + this.update(b[offset + i]); + } + } + + public byte[] digest() + { + byte[] result = new byte[UMac32.OUTPUT_LEN]; + for (int i = 0; i < streams; i++) + { + byte[] partialResult = l1hash[i].digest(); + System.arraycopy(partialResult, 0, result, 4 * i, 4); + } + reset(); + return result; + } + + public void reset() + { + for (int i = 0; i < streams; i++) + { + l1hash[i].reset(); + } + } + + public boolean selfTest() + { + return true; + } + + // helper methods ---------------------------------------------------------- + + // Inner classes + // ========================================================================= + + /** + * First hash stage of the UHash32 algorithm. + */ + class L1Hash32 implements Cloneable + { + + // Constants and variables + // ---------------------------------------------------------------------- + + private int[] key; // key material as an array of 32-bit ints + + private byte[] buffer; // work buffer L1_KEY_LEN long + + private int count; // meaningful bytes in buffer + + private ByteArrayOutputStream Y; + + // private byte[] y; + private long totalCount; + + private L2Hash32 l2hash; + + private L3Hash32 l3hash; + + // Constructor(s) + // ---------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + L1Hash32() + { + super(); + + key = new int[UMac32.L1_KEY_LEN / 4]; + buffer = new byte[UMac32.L1_KEY_LEN]; + count = 0; + Y = new ByteArrayOutputStream(); + totalCount = 0L; + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param that the instance to clone. + */ + private L1Hash32(L1Hash32 that) + { + this(); + + System.arraycopy(that.key, 0, this.key, 0, that.key.length); + System.arraycopy(that.buffer, 0, this.buffer, 0, that.count); + this.count = that.count; + byte[] otherY = that.Y.toByteArray(); + this.Y.write(otherY, 0, otherY.length); + this.totalCount = that.totalCount; + if (that.l2hash != null) + { + this.l2hash = (L2Hash32) that.l2hash.clone(); + } + if (that.l3hash != null) + { + this.l3hash = (L3Hash32) that.l3hash.clone(); + } + } + + // Class methods + // ---------------------------------------------------------------------- + + // Instance methods + // ---------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ------------------------- + + public Object clone() + { + return new L1Hash32(this); + } + + // other instance methods ----------------------------------------------- + + public void init(byte[] k1, byte[] k2, byte[] k31, byte[] k32) + { + for (int i = 0, j = 0; i < (UMac32.L1_KEY_LEN / 4); i++) + { + key[i] = k1[j++] << 24 | (k1[j++] & 0xFF) << 16 + | (k1[j++] & 0xFF) << 8 | (k1[j++] & 0xFF); + } + + l2hash = new L2Hash32(k2); + l3hash = new L3Hash32(k31, k32); + } + + public void update(byte b) + { + // Break M into L1_KEY_LEN byte chunks (final chunk may be shorter) + + // Let M_1, M_2, ..., M_t be strings so that M = M_1 || M_2 || .. || + // M_t, and length(M_i) = L1_KEY_LEN for all 0 < i < t. + + // For each chunk, except the last: endian-adjust, NH hash + // and add bit-length. Use results to build Y. + buffer[count] = b; + count++; + totalCount++; + if (count >= UMac32.L1_KEY_LEN) + { + byte[] y = nh32(UMac32.L1_KEY_LEN); + Y.write(y, 0, 8); + + count = 0; + + // For each iteration, extract key and three-layer hash. + // If length(M) <= L1_KEY_LEN, then skip L2-HASH. + if (Y.size() == 16) + { // we already hashed twice L1_KEY_LEN + byte[] A = Y.toByteArray(); + Y.reset(); + l2hash.update(A, 0, 16); + } + } + } + + public byte[] digest() + { + // For the last chunk: pad to 32-byte boundary, endian-adjust, + // NH hash and add bit-length. Concatenate the result to Y. + if (count != 0) + { + if (count % 32 != 0) + { + int limit = 32 * ((count + 31) / 32); + System.arraycopy(ALL_ZEROES, 0, buffer, count, limit - count); + count += limit - count; + } + byte[] y = nh32(count); + Y.write(y, 0, 8); + } + + byte[] A = Y.toByteArray(); + Y.reset(); + byte[] B; + if (totalCount <= UMac32.L1_KEY_LEN) + { + // we might have 'update'd the bytes already. check + if (A.length == 0) + { // we did + B = l2hash.digest(); + } + else + { // did not + B = new byte[16]; + System.arraycopy(A, 0, B, 8, 8); + } + } + else + { + if (A.length != 0) + { + l2hash.update(A, 0, A.length); + } + B = l2hash.digest(); + } + + byte[] result = l3hash.digest(B); + reset(); + return result; + } + + public void reset() + { + count = 0; + Y.reset(); + totalCount = 0L; + if (l2hash != null) + { + l2hash.reset(); + } + } + + // helper methods ------------------------------------------------------- + + /** + * 5.1 NH-32: NH hashing with a 32-bit word size. + * + * @param len count of bytes, divisible by 32, in buffer to process + * @return Y, string of length 8 bytes. + */ + private byte[] nh32(int len) + { + // Break M and K into 4-byte chunks + int t = len / 4; + + // Let M_1, M_2, ..., M_t be 4-byte strings + // so that M = M_1 || M_2 || .. || M_t. + // Let K_1, K_2, ..., K_t be 4-byte strings + // so that K_1 || K_2 || .. || K_t is a prefix of K. + int[] m = new int[t]; + + int i; + int j = 0; + for (i = 0, j = 0; i < t; i++) + { + m[i] = buffer[j++] << 24 | (buffer[j++] & 0xFF) << 16 + | (buffer[j++] & 0xFF) << 8 | (buffer[j++] & 0xFF); + } + + // Perform NH hash on the chunks, pairing words for multiplication + // which are 4 apart to accommodate vector-parallelism. + long result = len * 8L; + for (i = 0; i < t; i += 8) + { + result += ((m[i + 0] + key[i + 0]) & 0xFFFFFFFFL) + * ((m[i + 4] + key[i + 4]) & 0xFFFFFFFFL); + result += ((m[i + 1] + key[i + 1]) & 0xFFFFFFFFL) + * ((m[i + 5] + key[i + 5]) & 0xFFFFFFFFL); + result += ((m[i + 2] + key[i + 2]) & 0xFFFFFFFFL) + * ((m[i + 6] + key[i + 6]) & 0xFFFFFFFFL); + result += ((m[i + 3] + key[i + 3]) & 0xFFFFFFFFL) + * ((m[i + 7] + key[i + 7]) & 0xFFFFFFFFL); + } + + return new byte[] { (byte) (result >>> 56), (byte) (result >>> 48), + (byte) (result >>> 40), (byte) (result >>> 32), + (byte) (result >>> 24), (byte) (result >>> 16), + (byte) (result >>> 8), (byte) result }; + } + } + + // ========================================================================= + + /** + *

Second hash stage of the UHash32 algorithm.

+ * + * 5.4 L2-HASH-32: Second-layer hash.

+ *

    + *
  • Input:
    + * K string of length 24 bytes.
    + * M string of length less than 2^64 bytes.
  • + *
  • Returns:
    + * Y, string of length 16 bytes.
  • + *
+ */ + class L2Hash32 implements Cloneable + { + + // Constants and variables + // ---------------------------------------------------------------------- + + private BigInteger k64, k128; + + private BigInteger y; + + private boolean highBound; + + private long bytesSoFar; + + private ByteArrayOutputStream buffer; + + // Constructor(s) + // ---------------------------------------------------------------------- + + L2Hash32(byte[] K) + { + super(); + + if (K.length != 24) + { + throw new ExceptionInInitializerError("K length is not 24"); + } + + // Extract keys and restrict to special key-sets + // Mask64 = uint2str(0x01FFFFFF01FFFFFF, 8); + // Mask128 = uint2str(0x01FFFFFF01FFFFFF01FFFFFF01FFFFFF, 16); + // k64 = str2uint(K[1..8] and Mask64); + // k128 = str2uint(K[9..24] and Mask128); + int i = 0; + k64 = new BigInteger(1, new byte[] { (byte) (K[i++] & 0x01), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0x01), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF) }); + k128 = new BigInteger(1, new byte[] { (byte) (K[i++] & 0x01), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0x01), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0x01), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0x01), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF), + (byte) (K[i++] & 0xFF) }); + + y = BigInteger.ONE; + highBound = false; + bytesSoFar = 0L; + } + + private L2Hash32(L2Hash32 that) + { + super(); + + this.k64 = that.k64; + this.k128 = that.k128; + this.y = that.y; + this.highBound = that.highBound; + this.bytesSoFar = that.bytesSoFar; + if (that.buffer != null) + { + byte[] thatbuffer = that.buffer.toByteArray(); + this.buffer = new ByteArrayOutputStream(); + this.buffer.write(thatbuffer, 0, thatbuffer.length); + } + } + + // Class methods + // ---------------------------------------------------------------------- + + // Instance methods + // ---------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ------------------------- + + public Object clone() + { + return new L2Hash32(this); + } + + // other instance methods ----------------------------------------------- + + // this is called with either 8-bytes or 16-bytes + void update(byte[] b, int offset, int len) + { + if (len == 0) + { + return; + } + + if (!highBound) + { // do the first (only?) 8-bytes + poly(64, LOWER_RANGE, k64, b, offset, 8); + bytesSoFar += 8L; + highBound = (bytesSoFar > BOUNDARY); + if (highBound) + { // if we just crossed the limit then process y + poly(128, UPPER_RANGE, k128, yTo16bytes(), 0, 16); + buffer = new ByteArrayOutputStream(); + } + // do the rest if any + update(b, offset + 8, len - 8); + } + else + { // we're already beyond the 2**17 bytes size limit + // process in chuncks of 16 + buffer.write(b, offset, len); + if (buffer.size() > 16) + { + byte[] bb = buffer.toByteArray(); + poly(128, UPPER_RANGE, k128, bb, 0, 16); + if (bb.length > 16) + { + buffer.write(bb, 16, bb.length - 16); + } + } + } + } + + byte[] digest() + { + // If M no more than 2^17 bytes, hash under 64-bit prime, + // otherwise, hash first 2^17 bytes under 64-bit prime and + // remainder under 128-bit prime. + if (!highBound) + { // y is up-to-date + // do nothing + } + else + { // we may have some bytes in buffer + byte[] bb = buffer.toByteArray(); + byte[] lastBlock = new byte[16]; + System.arraycopy(bb, 0, lastBlock, 0, bb.length); + lastBlock[bb.length] = (byte) 0x80; + poly(128, UPPER_RANGE, k128, lastBlock, 0, 16); + } + + byte[] result = yTo16bytes(); + reset(); + return result; + } + + void reset() + { + y = BigInteger.ONE; + highBound = false; + bytesSoFar = 0L; + if (buffer != null) + { + buffer.reset(); + } + } + + // helper methods ------------------------------------------------------- + + private byte[] yTo16bytes() + { + byte[] yy = y.toByteArray(); + byte[] result = new byte[16]; + if (yy.length > 16) + { + System.arraycopy(yy, yy.length - 16, result, 0, 16); + } + else + { + System.arraycopy(yy, 0, result, 16 - yy.length, yy.length); + } + + return result; + } + + /** + * 5.3 POLY: Polynomial hash + * Function Name: POLY + * + * @param wordbits positive integer divisible by 8: called with 64 or 128. + * @param maxwordrange positive integer less than 2**wordbits. + * @param k integer in the range 0 .. prime(wordbits) - 1. + * @param M string with length divisible by (wordbits / 8) bytes. + * return y, integer in the range 0 .. prime(wordbits) - 1. + */ + private void poly(int wordbits, BigInteger maxwordrange, BigInteger k, + byte[] M, int off, int len) + { + byte[] mag = new byte[len]; + System.arraycopy(M, off, mag, 0, len); + // Define constants used for fixing out-of-range words + // int wordbytes = wordbits / 8; + + BigInteger p = prime(wordbits); + BigInteger offset = TWO.pow(wordbits).subtract(p); // 2^wordbits - p; + BigInteger marker = p.subtract(BigInteger.ONE); + + // Break M into chunks of length wordbytes bytes + // long n = M.length / wordbytes; + // Let M_1, M_2, ..., M_n be strings of length wordbytes bytes + // so that M = M_1 || M_2 || .. || M_n + + // For each input word, compare it with maxwordrange. If larger + // then hash the words 'marker' and (m - offset), both in range. + // for (int i = 0; i < n; i++) { + BigInteger m = new BigInteger(1, mag); + if (m.compareTo(maxwordrange) >= 0) + { // m >= maxwordrange + y = y.multiply(k).add(marker).mod(p); // (k * y + marker) % p; + y = y.multiply(k).add(m.subtract(offset)).mod(p); // (k * y + (m - offset)) % p; + } + else + { + y = y.multiply(k).add(m).mod(p); // (k * y + m) % p; + } + // } + + // return y; + } + } + + // ========================================================================= + + /** + * Third hash stage of the UHash32 algorithm. + * + * Input: + * K1 string of length 64 bytes. + * K2 string of length 4 bytes. + * M string of length 16 bytes. + * Returns: + * Y, string of length 4 bytes. + */ + class L3Hash32 implements Cloneable + { + + // Constants and variables + // ---------------------------------------------------------------------- + + private static final long PRIME_36 = 0x0000000FFFFFFFFBL; + + private int[] k = new int[9]; + + // Constructor(s) + // ---------------------------------------------------------------------- + + /** + * + * @param K1 string of length 64 bytes. + * @param K2 string of length 4 bytes. + */ + L3Hash32(byte[] K1, byte[] K2) + { + super(); + + // pre-conditions + if (K1.length != 64) + { + throw new ExceptionInInitializerError("K1 length is not 64"); + } + if (K2.length != 4) + { + throw new ExceptionInInitializerError("K2 length is not 4"); + } + + // Break K1 into 8 chunks and convert to integers + // int i = 0; + // for (int j = 0; i < 8; ) { + for (int i = 0, j = 0; i < 8; i++) + { + long kk = (K1[j++] & 0xFFL) << 56 | (K1[j++] & 0xFFL) << 48 + | (K1[j++] & 0xFFL) << 40 | (K1[j++] & 0xFFL) << 32 + | (K1[j++] & 0xFFL) << 24 | (K1[j++] & 0xFFL) << 16 + | (K1[j++] & 0xFFL) << 8 | (K1[j++] & 0xFFL); + // k[i++] = (int)(kk % PRIME_36); + k[i] = (int) (kk % PRIME_36); + } + // k[i] = K2[0] << 24 | (K2[1] & 0xFF) << 16 | (K2[2] & 0xFF) << 8 | (K2[3] & 0xFF); + k[8] = K2[0] << 24 | (K2[1] & 0xFF) << 16 | (K2[2] & 0xFF) << 8 + | (K2[3] & 0xFF); + } + + private L3Hash32(int[] k) + { + super(); + + this.k = k; + } + + // Class methods + // ---------------------------------------------------------------------- + + // Instance methods + // ---------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ------------------------- + + public Object clone() + { + return new L3Hash32((int[]) k.clone()); + } + + // other instance methods ----------------------------------------------- + + /** + * @param M string of length 16 bytes. + * @return Y, string of length 4 bytes. + */ + byte[] digest(byte[] M) + { + if (M.length != 16) + { + throw new IllegalArgumentException("M length is not 16"); + } + + long m, y = 0L; + for (int i = 0, j = 0; i < 8; i++) + { + // Break M into 8 chunks and convert to integers + m = (M[j++] & 0xFFL) << 8 | (M[j++] & 0xFFL); + + // Inner-product hash, extract last 32 bits and affine-translate + // y = (m_1 * k_1 + ... + m_8 * k_8) mod prime(36); + // y = y mod 2^32; + y += (m * (k[i] & 0xFFFFFFFFL)) % PRIME_36; + } + int Y = ((int) y) ^ k[8]; + return new byte[] { (byte) (Y >>> 24), (byte) (Y >>> 16), + (byte) (Y >>> 8), (byte) Y }; + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mac/UMac32.java b/gnu/javax/crypto/mac/UMac32.java new file mode 100644 index 000000000..d20d4f4a9 --- /dev/null +++ b/gnu/javax/crypto/mac/UMac32.java @@ -0,0 +1,491 @@ +/* UMac32.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mac; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.Util; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + *

The implementation of the UMAC (Universal Message Authentication + * Code).

+ * + *

The UMAC algorithms described are parameterized. This means + * that various low-level choices, like the endian convention and the underlying + * cryptographic primitive, have not been fixed. One must choose values for + * these parameters before the authentication tag generated by UMAC (for + * a given message, key, and nonce) becomes fully-defined. In this document + * we provide two collections of parameter settings, and have named the sets + * UMAC16 and UMAC32. The parameter sets have been chosen based on + * experimentation and provide good performance on a wide variety of processors. + * UMAC16 is designed to excel on processors which provide small-scale + * SIMD parallelism of the type found in Intel's MMX and Motorola's AltiVec + * instruction sets, while UMAC32 is designed to do well on processors + * with good 32- and 64- bit support. UMAC32 may take advantage of SIMD + * parallelism in future processors.

+ * + *

UMAC has been designed to allow implementations which accommodate + * on-line authentication. This means that pieces of the message may + * be presented to UMAC at different times (but in correct order) and an + * on-line implementation will be able to process the message correctly without + * the need to buffer more than a few dozen bytes of the message. For + * simplicity, the algorithms in this specification are presented as if the + * entire message being authenticated were available at once.

+ * + *

To authenticate a message, Msg, one first applies the + * universal hash function, resulting in a string which is typically much + * shorter than the original message. The pseudorandom function is applied to a + * nonce, and the result is used in the manner of a Vernam cipher: the + * authentication tag is the xor of the output from the hash function and the + * output from the pseudorandom function. Thus, an authentication tag is + * generated as

+ * + *
+ *    AuthTag = f(Nonce) xor h(Msg)
+ * 
+ * + *

Here f is the pseudorandom function shared between the sender + * and the receiver, and h is a universal hash function shared by the sender and + * the receiver. In UMAC, a shared key is used to key the pseudorandom + * function f, and then f is used for both tag + * generation and internally to generate all of the bits needed by the universal + * hash function.

+ * + *

The universal hash function that we use is called UHASH. It + * combines several software-optimized algorithms into a multi-layered + * structure. The algorithm is moderately complex. Some of this complexity comes + * from extensive speed optimizations.

+ * + *

For the pseudorandom function we use the block cipher of the Advanced + * Encryption Standard (AES).

+ * + *

The UMAC32 parameters, considered in this implementation are:

+ *
+ *                                   UMAC32
+ *                                   ------
+ *        WORD-LEN                        4
+ *        UMAC-OUTPUT-LEN                 8
+ *        L1-KEY-LEN                   1024
+ *        UMAC-KEY-LEN                   16
+ *        ENDIAN-FAVORITE               BIG *
+ *        L1-OPERATIONS-SIGN       UNSIGNED
+ * 
+ * + *

Please note that this UMAC32 differs from the one described in the paper + * by the ENDIAN-FAVORITE value.

+ * + *

References:

+ * + *
    + *
  1. + * UMAC: Message Authentication Code using Universal Hashing.
    + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.
  2. + *
+ */ +public class UMac32 extends BaseMac +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * Property name of the user-supplied Nonce. The value associated to + * this property name is taken to be a byte array. + */ + public static final String NONCE_MATERIAL = "gnu.crypto.umac.nonce.material"; + + /** Known test vector. */ + // private static final String TV1 = "3E5A0E09198B0F94"; + // private static final String TV1 = "5FD764A6D3A9FD9D"; + // private static final String TV1 = "48658DE1D9A70304"; + private static final String TV1 = "455ED214A6909F20"; + + private static final BigInteger MAX_NONCE_ITERATIONS = BigInteger.ONE.shiftLeft(16 * 8); + + // UMAC32 parameters + static final int OUTPUT_LEN = 8; + + static final int L1_KEY_LEN = 1024; + + static final int KEY_LEN = 16; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + private byte[] nonce; + + private UHash32 uhash32; + + private BigInteger nonceReuseCount; + + /** The authentication key for this instance. */ + private transient byte[] K; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public UMac32() + { + super("umac32"); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param that the instance to clone. + */ + private UMac32(UMac32 that) + { + this(); + + if (that.K != null) + { + this.K = (byte[]) that.K.clone(); + } + if (that.nonce != null) + { + this.nonce = (byte[]) that.nonce.clone(); + } + if (that.uhash32 != null) + { + this.uhash32 = (UHash32) that.uhash32.clone(); + } + this.nonceReuseCount = that.nonceReuseCount; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new UMac32(this); + } + + // gnu.crypto.mac.IMac interface implementation ---------------------------- + + public int macSize() + { + return OUTPUT_LEN; + } + + /** + *

Initialising a UMAC instance consists of defining values for + * the following parameters:

+ * + *
    + *
  1. Key Material: as the value of the attribute entry keyed by + * {@link #MAC_KEY_MATERIAL}. The value is taken to be a byte array + * containing the user-specified key material. The length of this array, + * if/when defined SHOULD be exactly equal to {@link #KEY_LEN}.
  2. + * + *
  3. Nonce Material: as the value of the attribute entry keyed by + * {@link #NONCE_MATERIAL}. The value is taken to be a byte array + * containing the user-specified nonce material. The length of this array, + * if/when defined SHOULD be (a) greater than zero, and (b) less or equal + * to 16 (the size of the AES block).
  4. + *
+ * + *

For convenience, this implementation accepts that not both parameters + * be always specified.

+ * + *
    + *
  • If the Key Material is specified, but the Nonce Material + * is not, then this implementation, re-uses the previously set Nonce + * Material after (a) converting the bytes to an unsigned integer, + * (b) incrementing the number by one, and (c) converting it back to 16 + * bytes.
  • + * + *
  • If the Nonce Material is specified, but the Key Material + * is not, then this implementation re-uses the previously set Key + * Material.
  • + *
+ * + *

This method throws an exception if no Key Material is specified + * in the input map, and there is no previously set/defined Key Material + * (from an earlier invocation of this method). If a Key Material can + * be used, but no Nonce Material is defined or previously set/defined, + * then a default value of all-zeroes shall be used.

+ * + * @param attributes one or both of required parameters. + * @throws InvalidKeyException the key material specified is not of the + * correct length. + */ + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + byte[] key = (byte[]) attributes.get(MAC_KEY_MATERIAL); + byte[] n = (byte[]) attributes.get(NONCE_MATERIAL); + + boolean newKey = (key != null); + boolean newNonce = (n != null); + + if (newKey) + { + if (key.length != KEY_LEN) + { + throw new InvalidKeyException("Key length: " + + String.valueOf(key.length)); + } + K = key; + } + else + { + if (K == null) + { + throw new InvalidKeyException("Null Key"); + } + } + + if (newNonce) + { + if (n.length < 1 || n.length > 16) + { + throw new IllegalArgumentException("Invalid Nonce length: " + + String.valueOf(n.length)); + } + + if (n.length < 16) + { // pad with zeroes + byte[] newN = new byte[16]; + System.arraycopy(n, 0, newN, 0, n.length); + nonce = newN; + } + else + { + nonce = n; + } + + nonceReuseCount = BigInteger.ZERO; + } + else if (nonce == null) + { // use all-0 nonce if 1st time + nonce = new byte[16]; + nonceReuseCount = BigInteger.ZERO; + } + else if (!newKey) + { // increment nonce if still below max count + nonceReuseCount = nonceReuseCount.add(BigInteger.ONE); + if (nonceReuseCount.compareTo(MAX_NONCE_ITERATIONS) >= 0) + { + // limit reached. we SHOULD have a key + throw new InvalidKeyException("Null Key and unusable old Nonce"); + } + BigInteger N = new BigInteger(1, nonce); + N = N.add(BigInteger.ONE).mod(MAX_NONCE_ITERATIONS); + n = N.toByteArray(); + if (n.length == 16) + { + nonce = n; + } + else if (n.length < 16) + { + nonce = new byte[16]; + System.arraycopy(n, 0, nonce, 16 - n.length, n.length); + } + else + { + nonce = new byte[16]; + System.arraycopy(n, n.length - 16, nonce, 0, 16); + } + } + else + { // do nothing, re-use old nonce value + nonceReuseCount = BigInteger.ZERO; + } + + if (uhash32 == null) + { + uhash32 = new UHash32(); + } + + Map map = new HashMap(); + map.put(MAC_KEY_MATERIAL, K); + uhash32.init(map); + } + + public void update(byte b) + { + uhash32.update(b); + } + + public void update(byte[] b, int offset, int len) + { + uhash32.update(b, offset, len); + } + + public byte[] digest() + { + byte[] result = uhash32.digest(); + byte[] pad = pdf(); // pdf(K, nonce); + for (int i = 0; i < OUTPUT_LEN; i++) + { + result[i] = (byte) (result[i] ^ pad[i]); + } + + return result; + } + + public void reset() + { + if (uhash32 != null) + { + uhash32.reset(); + } + } + + public boolean selfTest() + { + if (valid == null) + { + byte[] key; + try + { + key = "abcdefghijklmnop".getBytes("ASCII"); + } + catch (UnsupportedEncodingException x) + { + throw new RuntimeException("ASCII not supported"); + } + byte[] nonce = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; + UMac32 mac = new UMac32(); + Map attributes = new HashMap(); + attributes.put(MAC_KEY_MATERIAL, key); + attributes.put(NONCE_MATERIAL, nonce); + try + { + mac.init(attributes); + } + catch (InvalidKeyException x) + { + x.printStackTrace(System.err); + return false; + } + + byte[] data = new byte[128]; + data[0] = (byte) 0x80; + + mac.update(data, 0, 128); + byte[] result = mac.digest(); + // System.out.println("UMAC test vector: "+Util.toString(result)); + valid = new Boolean(TV1.equals(Util.toString(result))); + } + return valid.booleanValue(); + } + + // helper methods ---------------------------------------------------------- + + /** + * + * @return byte array of length 8 (or OUTPUT_LEN) bytes. + */ + private byte[] pdf() + { + // Make Nonce 16 bytes by prepending zeroes. done (see init()) + + // one AES invocation is enough for more than one PDF invocation + // number of index bits needed = 1 + + // Extract index bits and zero low bits of Nonce + BigInteger Nonce = new BigInteger(1, nonce); + int nlowbitsnum = Nonce.testBit(0) ? 1 : 0; + Nonce = Nonce.clearBit(0); + + // Generate subkey, AES and extract indexed substring + IRandom kdf = new UMacGenerator(); + Map map = new HashMap(); + map.put(IBlockCipher.KEY_MATERIAL, K); + // map.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(128/8)); + map.put(UMacGenerator.INDEX, new Integer(128)); + // map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + kdf.init(map); + byte[] Kp = new byte[KEY_LEN]; + try + { + kdf.nextBytes(Kp, 0, KEY_LEN); + } + catch (IllegalStateException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + catch (LimitReachedException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + IBlockCipher aes = CipherFactory.getInstance(Registry.AES_CIPHER); + map.put(IBlockCipher.KEY_MATERIAL, Kp); + try + { + aes.init(map); + } + catch (InvalidKeyException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + catch (IllegalStateException x) + { + x.printStackTrace(System.err); + throw new RuntimeException(String.valueOf(x)); + } + byte[] T = new byte[16]; + aes.encryptBlock(nonce, 0, T, 0); + byte[] result = new byte[OUTPUT_LEN]; + System.arraycopy(T, nlowbitsnum, result, 0, OUTPUT_LEN); + + return result; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/BaseMode.java b/gnu/javax/crypto/mode/BaseMode.java new file mode 100644 index 000000000..0a9ab2dab --- /dev/null +++ b/gnu/javax/crypto/mode/BaseMode.java @@ -0,0 +1,352 @@ +/* BaseMode.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.security.InvalidKeyException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + *

A basic abstract class to facilitate implementing block cipher modes of + * operations.

+ */ +public abstract class BaseMode implements IMode +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The canonical name prefix of this mode. */ + protected String name; + + /** The state indicator of this instance. */ + protected int state; + + /** The underlying block cipher implementation. */ + protected IBlockCipher cipher; + + /** The block size, in bytes, to operate the underlying block cipher in. */ + protected int cipherBlockSize; + + /** The block size, in bytes, in which to operate the mode instance. */ + protected int modeBlockSize; + + /** The initialisation vector value. */ + protected byte[] iv; + + /** The instance lock. */ + protected Object lock = new Object(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial constructor for use by concrete subclasses.

+ * + * @param name the canonical name prefix of this mode. + * @param underlyingCipher the implementation of the underlying cipher. + * @param cipherBlockSize the block size, in bytes, in which to operate the + * underlying cipher. + */ + protected BaseMode(String name, IBlockCipher underlyingCipher, + int cipherBlockSize) + { + super(); + + this.name = name; + this.cipher = underlyingCipher; + this.cipherBlockSize = cipherBlockSize; + state = -1; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IMode interface implementation ------------------------------------------ + + public void update(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException + { + synchronized (lock) + { + switch (state) + { + case ENCRYPTION: + encryptBlock(in, inOffset, out, outOffset); + break; + case DECRYPTION: + decryptBlock(in, inOffset, out, outOffset); + break; + default: + throw new IllegalStateException(); + } + } + } + + // IBlockCipher interface implementation ----------------------------------- + + public String name() + { + return new StringBuffer().append(name).append('(').append(cipher.name()).append( + ')').toString(); + } + + /** + *

Returns the default value, in bytes, of the mode's block size. This + * value is part of the construction arguments passed to the Factory methods + * in {@link ModeFactory}. Unless changed by an invocation of any of the + * init() methods, a Mode instance would operate with + * the same block size as its underlying block cipher. As mentioned earlier, + * the block size of the underlying block cipher itself is specified in one + * of the method(s) available in the factory class.

+ * + * @return the default value, in bytes, of the mode's block size. + * @see gnu.crypto.mode.ModeFactory + */ + public int defaultBlockSize() + { + return cipherBlockSize; + } + + /** + *

Returns the default value, in bytes, of the underlying block cipher + * key size.

+ * + * @return the default value, in bytes, of the underlying cipher's key size. + */ + public int defaultKeySize() + { + return cipher.defaultKeySize(); + } + + /** + *

Returns an {@link Iterator} over the supported block sizes. Each + * element returned by this object is an {@link Integer}.

+ * + *

The default behaviour is to return an iterator with just one value, + * which is that currently configured for the underlying block cipher. + * Concrete implementations may override this behaviour to signal their + * ability to support other values.

+ * + * @return an {@link Iterator} over the supported block sizes. + */ + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(new Integer(cipherBlockSize)); + + return Collections.unmodifiableList(al).iterator(); + } + + /** + *

Returns an {@link Iterator} over the supported underlying block cipher + * key sizes. Each element returned by this object is an instance of + * {@link Integer}.

+ * + * @return an {@link Iterator} over the supported key sizes. + */ + public Iterator keySizes() + { + return cipher.keySizes(); + } + + public void init(Map attributes) throws InvalidKeyException, + IllegalStateException + { + synchronized (lock) + { + if (state != -1) + { + throw new IllegalStateException(); + } + + Integer want = (Integer) attributes.get(STATE); + if (want != null) + { + switch (want.intValue()) + { + case ENCRYPTION: + state = ENCRYPTION; + break; + case DECRYPTION: + state = DECRYPTION; + break; + default: + throw new IllegalArgumentException(); + } + } + + Integer bs = (Integer) attributes.get(MODE_BLOCK_SIZE); + modeBlockSize = (bs == null ? cipherBlockSize : bs.intValue()); + + byte[] iv = (byte[]) attributes.get(IV); + if (iv != null) + { + this.iv = (byte[]) iv.clone(); + } + else + { + this.iv = new byte[modeBlockSize]; + } + + cipher.init(attributes); + setup(); + } + } + + public int currentBlockSize() + { + if (state == -1) + { + throw new IllegalStateException(); + } + return modeBlockSize; + } + + public void reset() + { + synchronized (lock) + { + state = -1; + iv = null; + cipher.reset(); + + teardown(); + } + } + + public boolean selfTest() + { + int ks; + Iterator bit; + for (Iterator kit = keySizes(); kit.hasNext();) + { + ks = ((Integer) kit.next()).intValue(); + for (bit = blockSizes(); bit.hasNext();) + { + if (!testSymmetry(ks, ((Integer) bit.next()).intValue())) + { + return false; + } + } + } + + return true; + } + + // methods to be implemented by concrete subclasses ------------------------ + + public abstract Object clone(); + + /** The initialisation phase of the concrete mode implementation. */ + public abstract void setup(); + + /** The termination phase of the concrete mode implementation. */ + public abstract void teardown(); + + public abstract void encryptBlock(byte[] in, int i, byte[] out, int o); + + public abstract void decryptBlock(byte[] in, int i, byte[] out, int o); + + // own methods ------------------------------------------------------------- + + private boolean testSymmetry(int ks, int bs) + { + try + { + IMode mode = (IMode) this.clone(); + byte[] iv = new byte[cipherBlockSize]; // all zeroes + byte[] k = new byte[ks]; + int i; + for (i = 0; i < ks; i++) + { + k[i] = (byte) i; + } + + int blockCount = 5; + int limit = blockCount * bs; + byte[] pt = new byte[limit]; + for (i = 0; i < limit; i++) + { + pt[i] = (byte) i; + } + byte[] ct = new byte[limit]; + byte[] cpt = new byte[limit]; + + Map map = new HashMap(); + map.put(KEY_MATERIAL, k); + map.put(CIPHER_BLOCK_SIZE, new Integer(cipherBlockSize)); + map.put(STATE, new Integer(ENCRYPTION)); + map.put(IV, iv); + map.put(MODE_BLOCK_SIZE, new Integer(bs)); + + mode.reset(); + mode.init(map); + for (i = 0; i < blockCount; i++) + { + mode.update(pt, i * bs, ct, i * bs); + } + + mode.reset(); + map.put(STATE, new Integer(DECRYPTION)); + mode.init(map); + for (i = 0; i < blockCount; i++) + { + mode.update(ct, i * bs, cpt, i * bs); + } + + return Arrays.equals(pt, cpt); + + } + catch (Exception x) + { + x.printStackTrace(System.err); + return false; + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/CBC.java b/gnu/javax/crypto/mode/CBC.java new file mode 100644 index 000000000..10578a6ef --- /dev/null +++ b/gnu/javax/crypto/mode/CBC.java @@ -0,0 +1,143 @@ +/* CBC.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The Cipher Block Chaining mode. This mode introduces feedback into + * the cipher by XORing the previous ciphertext block with the plaintext + * block before encipherment. That is, encrypting looks like this:

+ * + *

Ci = EK(Pi ^ + * Ci-1

+ * + *

Similarly, decrypting is:

+ * + *

Pi = Ci-1 ^ + * DK(Ci)

+ */ +public class CBC extends BaseMode implements Cloneable +{ + + // Constants and Variables + //------------------------------------------------------------------ + + /** The last (de|en)crypted block */ + private byte[] lastBlock; + + /** An intermediate buffer. */ + private byte[] scratch; + + // Constructors + // ----------------------------------------------------------------- + + /** + * Package-private constructor for the factory class. + * + * @param underlyingCipher The cipher implementation. + * @param cipherBlockSize The cipher's block size. + */ + CBC(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.CBC_MODE, underlyingCipher, cipherBlockSize); + } + + /** Our constructor for cloning. */ + private CBC(CBC that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + // Cloneable interface implementation + // ----------------------------------------------------------------- + + public Object clone() + { + return new CBC(this); + } + + // Implementation of abstract methods in BaseMode + // ----------------------------------------------------------------- + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + { + throw new IllegalArgumentException(); + } + scratch = new byte[cipherBlockSize]; + lastBlock = new byte[cipherBlockSize]; + + // lastBlock gets initialized to the initialization vector. + for (int i = 0; i < lastBlock.length && i < iv.length; i++) + { + lastBlock[i] = iv[i]; + } + } + + public void teardown() + { + lastBlock = null; + scratch = null; + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + for (int k = 0; k < scratch.length; k++) + { + scratch[k] = (byte) (lastBlock[k] ^ in[k + i]); + } + cipher.encryptBlock(scratch, 0, out, o); + System.arraycopy(out, o, lastBlock, 0, cipherBlockSize); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + byte[] buf = new byte[cipherBlockSize]; + System.arraycopy(in, i, buf, 0, cipherBlockSize); + cipher.decryptBlock(in, i, scratch, 0); + for (int k = 0; k < scratch.length; k++) + { + out[o + k] = (byte) (lastBlock[k] ^ scratch[k]); + } + System.arraycopy(buf, 0, lastBlock, 0, cipherBlockSize); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/CFB.java b/gnu/javax/crypto/mode/CFB.java new file mode 100644 index 000000000..fef2b634c --- /dev/null +++ b/gnu/javax/crypto/mode/CFB.java @@ -0,0 +1,175 @@ +/* CFB.java -- + Copyright (C) 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + * The cipher feedback mode. CFB mode is a stream mode that operates on + * s bit blocks, where 1 <= s <= b, if + * b is the underlying cipher's block size. Encryption is: + * +
+ I[1] = IV
+ I[j] = LSB(b-s, I[j-1]) | C[j-1]   for j = 2...n
+ O[j] = CIPH(K, I[j])               for j = 1,2...n
+ C[j] = P[j] ^ MSB(s, O[j])         for j = 1,2...n
+ 
+ * + *

And decryption is:

+ * +
+ I[1] = IV
+ I[j] = LSB(b-s, I[j-1]) | C[j-1]   for j = 2...n
+ O[j] = CIPH(K, I[j])               for j = 1,2...n
+ P[j] = C[j] ^ MSB(s, O[j])         for j = 1,2...n
+ 
+ * + *

CFB mode requires an initialization vector, which need not be kept + * secret.

+ * + *

References:

+ *
    + *
  1. Bruce Schneier, Applied Cryptography: Protocols, Algorithms, + * and Source Code in C, Second Edition. (1996 John Wiley and Sons) + * ISBN 0-471-11709-9.
  2. + * + *
  3. + * Recommendation for Block Cipher Modes of Operation Methods and Techniques, + * Morris Dworkin.
  4. + *
+ */ +public class CFB extends BaseMode +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** The shift register, the input block to the block cipher. */ + private byte[] shiftRegister; + + /** The output block from the block cipher. */ + private byte[] scratch; + + // Constructors. + // ----------------------------------------------------------------------- + + /** + * Package-private constructor for the factory class. + * + * @param underlyingCipher The cipher implementation. + * @param cipherBlockSize The cipher's block size. + */ + CFB(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.CFB_MODE, underlyingCipher, cipherBlockSize); + } + + /** + * Cloneing constructor. + * + * @param that The instance being cloned. + */ + private CFB(CFB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + // Instance methods implementing BaseMode. + // ----------------------------------------------------------------------- + + public Object clone() + { + return new CFB(this); + } + + public void setup() + { + if (modeBlockSize > cipherBlockSize) + { + throw new IllegalArgumentException( + "CFB block size cannot be larger than the cipher block size"); + } + shiftRegister = new byte[cipherBlockSize]; + scratch = new byte[cipherBlockSize]; + System.arraycopy(iv, 0, shiftRegister, 0, Math.min(iv.length, + cipherBlockSize)); + } + + public void teardown() + { + if (shiftRegister != null) + { + for (int i = 0; i < shiftRegister.length; i++) + { + shiftRegister[i] = 0; + } + } + shiftRegister = null; + } + + public void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + { + cipher.encryptBlock(shiftRegister, 0, scratch, 0); + for (int i = 0; i < modeBlockSize; i++) + { + out[outOffset + i] = (byte) (in[inOffset + i] ^ scratch[i]); + } + System.arraycopy(shiftRegister, modeBlockSize, shiftRegister, 0, + cipherBlockSize - modeBlockSize); + System.arraycopy(out, outOffset, shiftRegister, cipherBlockSize + - modeBlockSize, + modeBlockSize); + } + + public void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) + { + cipher.encryptBlock(shiftRegister, 0, scratch, 0); + for (int i = 0; i < modeBlockSize; i++) + { + out[outOffset + i] = (byte) (in[inOffset + i] ^ scratch[i]); + } + System.arraycopy(shiftRegister, modeBlockSize, shiftRegister, 0, + cipherBlockSize - modeBlockSize); + System.arraycopy(in, inOffset, shiftRegister, cipherBlockSize + - modeBlockSize, + modeBlockSize); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/CTR.java b/gnu/javax/crypto/mode/CTR.java new file mode 100644 index 000000000..49f4b9f3c --- /dev/null +++ b/gnu/javax/crypto/mode/CTR.java @@ -0,0 +1,221 @@ +/* CTR.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.java.security.util.Sequence; + +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Iterator; + +/** + *

The implementation of the Counter Mode.

+ * + *

The algorithm steps are formally described as follows:

+ * + *
+ *    CTR Encryption: O[j] = E(K)(T[j]); for j = 1, 2...n;
+ *                    C[j] = P[j] ^ O[j]; for j = 1, 2...n.
+ *    CTR Decryption: O[j] = E(K)(T[j]); for j = 1, 2...n;
+ *                    P[j] = C[j] ^ O[j]; for j = 1, 2...n.
+ * 
+ * + *

where P is the plaintext, C is the ciphertext, + * E(K) is the underlying block cipher encryption function + * parametrised with the session key K, and T is the + * Counter.

+ * + *

This implementation, uses a standard incrementing function with a step of + * 1, and an initial value similar to that described in the NIST document.

+ * + *

References:

+ * + *
    + *
  1. + * Recommendation for Block Cipher Modes of Operation Methods and Techniques, + * Morris Dworkin.
  2. + *
+ */ +public class CTR extends BaseMode implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The current counter. */ + // private BigInteger T; + private int off; + + private byte[] counter, enc; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial package-private constructor for use by the Factory class.

+ * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + CTR(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.CTR_MODE, underlyingCipher, cipherBlockSize); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param that the instance to clone. + */ + private CTR(CTR that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Cloneable interface implementation + // ------------------------------------------------------------------------- + + public Object clone() + { + return new CTR(this); + } + + // Implementation of abstract methods in BaseMode + // ------------------------------------------------------------------------- + + public void setup() + { + if (modeBlockSize > cipherBlockSize) + { + throw new IllegalArgumentException( + "mode size exceeds cipher block size"); + } + off = 0; + counter = new byte[cipherBlockSize]; + int i = cipherBlockSize - 1; + int j = iv.length - 1; + while (i >= 0 && j >= 0) + { + counter[i--] = iv[j--]; + } + enc = new byte[cipherBlockSize]; + cipher.encryptBlock(counter, 0, enc, 0); + // if (modeBlockSize != cipherBlockSize) { + // throw new IllegalArgumentException(); + // } + + // byte[] tBytes = new byte[modeBlockSize+1]; + // tBytes[0] = (byte) 0x80; + // for (int i = 0; i < modeBlockSize; i++) { + // tBytes[i+1] = (byte)(256 - modeBlockSize + i); + // } + + // T = new BigInteger(1, tBytes); + } + + public void teardown() + { + if (counter != null) + { + Arrays.fill(counter, (byte) 0); + } + if (enc != null) + { + Arrays.fill(enc, (byte) 0); + } + // T = null; + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + ctr(in, i, out, o); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + ctr(in, i, out, o); + } + + public Iterator blockSizes() + { + return new Sequence(1, cipherBlockSize).iterator(); + } + + // own methods + // ------------------------------------------------------------------------- + + private void ctr(byte[] in, int inOffset, byte[] out, int outOffset) + { + // T = T.add(BigInteger.ONE); + // byte[] O = T.toByteArray(); + // int ndx = O.length - modeBlockSize; + // cipher.encryptBlock(O, ndx, O, ndx); + // for (int i = 0; i < modeBlockSize; i++) { + // out[outOffset++] = (byte)(in[inOffset++] ^ O[ndx++]); + // } + for (int i = 0; i < modeBlockSize; i++) + { + out[outOffset++] = (byte) (in[inOffset++] ^ enc[off++]); + if (off == cipherBlockSize) + { + int j; + for (j = cipherBlockSize - 1; j >= 0; j--) + { + counter[j]++; + if ((counter[j] & 0xFF) != 0) + { + break; + } + } + if (j == 0) + { + counter[cipherBlockSize - 1]++; + } + off = 0; + cipher.encryptBlock(counter, 0, enc, 0); + } + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/EAX.java b/gnu/javax/crypto/mode/EAX.java new file mode 100644 index 000000000..bf2609898 --- /dev/null +++ b/gnu/javax/crypto/mode/EAX.java @@ -0,0 +1,352 @@ +/* EAX.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; + +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.InvalidKeyException; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + *

A conventional two-pass authenticated-encrypted mode, EAX. EAX is a + * Authenticated Encryption with Additional Data (AEAD) scheme, + * which provides protection and authentication for the message, and provides + * authentication of an (optional) header. EAX is composed of the counter mode + * (CTR) and the one-key CBC MAC (OMAC). + * + *

This class makes full use of the {@link IAuthenticatedMode} interface, + * that is, all methods of both {@link IMode} and {@link IMac} can be used + * as specified in the {@link IAuthenticatedMode} interface. + * + *

References:

+ *
    + *
  1. M. Bellare, P. Rogaway, and D. Wagner; A + * Conventional Authenticated-Encryption Mode.
  2. + *
+ */ +public class EAX implements IAuthenticatedMode +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + /** The tag size, in bytes. */ + private int tagSize; + + /** The nonce OMAC instance. */ + private IMac nonceOmac; + + /** The header OMAC instance. */ + private IMac headerOmac; + + /** The message OMAC instance. */ + private IMac msgOmac; + + /** The CTR instance. */ + private IMode ctr; + + /** The direction state (encrypting or decrypting). */ + private int state; + + /** Whether we're initialized or not. */ + private boolean init; + + /** The cipher block size. */ + private int cipherBlockSize; + + /** The cipher. */ + private IBlockCipher cipher; + + /** The [t]_n array. */ + private byte[] t_n; + + private static boolean valid = false; + + // Constructor. + // ------------------------------------------------------------------------ + + public EAX(IBlockCipher cipher, int cipherBlockSize) + { + this.cipher = cipher; + this.cipherBlockSize = cipherBlockSize; + String name = cipher.name(); + int i = name.indexOf('-'); + if (i >= 0) + { + name = name.substring(0, i); + } + String omacname = Registry.OMAC_PREFIX + name; + nonceOmac = MacFactory.getInstance(omacname); + headerOmac = MacFactory.getInstance(omacname); + msgOmac = MacFactory.getInstance(omacname); + ctr = ModeFactory.getInstance(Registry.CTR_MODE, cipher, cipherBlockSize); + t_n = new byte[cipherBlockSize]; + init = false; + } + + // IMode instance methods. + // ------------------------------------------------------------------------ + + public Object clone() + { + return new EAX((IBlockCipher) cipher.clone(), cipherBlockSize); + } + + public String name() + { + return Registry.EAX_MODE + "(" + cipher.name() + ")"; + } + + public int defaultBlockSize() + { + return ctr.defaultBlockSize(); + } + + public int defaultKeySize() + { + return ctr.defaultKeySize(); + } + + public Iterator blockSizes() + { + return ctr.blockSizes(); + } + + public Iterator keySizes() + { + return ctr.keySizes(); + } + + public void init(Map attrib) throws InvalidKeyException + { + byte[] nonce = (byte[]) attrib.get(IV); + if (nonce == null) + { + throw new IllegalArgumentException("no nonce provided"); + } + byte[] key = (byte[]) attrib.get(KEY_MATERIAL); + if (key == null) + { + throw new IllegalArgumentException("no key provided"); + } + + Arrays.fill(t_n, (byte) 0); + + nonceOmac.reset(); + nonceOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key)); + nonceOmac.update(t_n, 0, t_n.length); + nonceOmac.update(nonce, 0, nonce.length); + byte[] N = nonceOmac.digest(); + nonceOmac.reset(); + nonceOmac.update(t_n, 0, t_n.length); + nonceOmac.update(nonce, 0, nonce.length); + + t_n[t_n.length - 1] = 1; + headerOmac.reset(); + headerOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key)); + headerOmac.update(t_n, 0, t_n.length); + + t_n[t_n.length - 1] = 2; + msgOmac.reset(); + msgOmac.init(Collections.singletonMap(MAC_KEY_MATERIAL, key)); + msgOmac.update(t_n, 0, t_n.length); + + Integer modeSize = (Integer) attrib.get(MODE_BLOCK_SIZE); + if (modeSize == null) + { + modeSize = new Integer(cipherBlockSize); + } + HashMap ctrAttr = new HashMap(); + ctrAttr.put(KEY_MATERIAL, key); + ctrAttr.put(IV, N); + ctrAttr.put(STATE, new Integer(ENCRYPTION)); + ctrAttr.put(MODE_BLOCK_SIZE, modeSize); + ctr.reset(); + ctr.init(ctrAttr); + + Integer st = (Integer) attrib.get(STATE); + if (st != null) + { + state = st.intValue(); + if (state != ENCRYPTION && state != DECRYPTION) + { + throw new IllegalArgumentException("invalid state"); + } + } + else + { + state = ENCRYPTION; + } + + Integer ts = (Integer) attrib.get(TRUNCATED_SIZE); + if (ts != null) + { + tagSize = ts.intValue(); + } + else + { + tagSize = cipherBlockSize; + } + if (tagSize < 0 || tagSize > cipherBlockSize) + { + throw new IllegalArgumentException("tag size out of range"); + } + init = true; + } + + public int currentBlockSize() + { + return ctr.currentBlockSize(); + } + + public void encryptBlock(byte[] in, int inOff, byte[] out, int outOff) + { + if (!init) + { + throw new IllegalStateException("not initialized"); + } + if (state != ENCRYPTION) + { + throw new IllegalStateException("not encrypting"); + } + ctr.update(in, inOff, out, outOff); + msgOmac.update(out, outOff, ctr.currentBlockSize()); + } + + public void decryptBlock(byte[] in, int inOff, byte[] out, int outOff) + { + if (!init) + { + throw new IllegalStateException("not initialized"); + } + if (state != DECRYPTION) + { + throw new IllegalStateException("not decrypting"); + } + msgOmac.update(in, inOff, ctr.currentBlockSize()); + ctr.update(in, inOff, out, outOff); + } + + public void update(byte[] in, int inOff, byte[] out, int outOff) + { + switch (state) + { + case ENCRYPTION: + encryptBlock(in, inOff, out, outOff); + break; + case DECRYPTION: + decryptBlock(in, inOff, out, outOff); + break; + default: + throw new IllegalStateException("impossible state " + state); + } + } + + public void reset() + { + nonceOmac.reset(); + headerOmac.reset(); + msgOmac.reset(); + ctr.reset(); + } + + public boolean selfTest() + { + return true; // XXX + } + + // IMac instance methods. + // ------------------------------------------------------------------------ + + public int macSize() + { + return tagSize; + } + + public byte[] digest() + { + byte[] tag = new byte[tagSize]; + digest(tag, 0); + return tag; + } + + public void digest(byte[] out, int outOffset) + { + if (outOffset < 0 || outOffset + tagSize > out.length) + { + throw new IndexOutOfBoundsException(); + } + byte[] N = nonceOmac.digest(); + byte[] H = headerOmac.digest(); + byte[] M = msgOmac.digest(); + for (int i = 0; i < tagSize; i++) + { + out[outOffset + i] = (byte) (N[i] ^ H[i] ^ M[i]); + } + reset(); + } + + public void update(byte b) + { + if (!init) + { + throw new IllegalStateException("not initialized"); + } + headerOmac.update(b); + } + + public void update(byte[] buf, int off, int len) + { + if (!init) + { + throw new IllegalStateException("not initialized"); + } + headerOmac.update(buf, off, len); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/ECB.java b/gnu/javax/crypto/mode/ECB.java new file mode 100644 index 000000000..3b33a1848 --- /dev/null +++ b/gnu/javax/crypto/mode/ECB.java @@ -0,0 +1,137 @@ +/* ECB.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + *

The implementation of the Electronic Codebook mode.

+ * + *

The Electronic Codebook (ECB) mode is a confidentiality mode that is + * defined as follows:

+ * + *
    + *
  • ECB Encryption: Cj = CIPHK(Pj) for j = 1...n
  • + *
  • ECB Decryption: Pj = CIPH-1K(Cj) for j = 1...n
  • + *
+ * + *

In ECB encryption, the forward cipher function is applied directly, and + * independently, to each block of the plaintext. The resulting sequence of + * output blocks is the ciphertext.

+ * + *

In ECB decryption, the inverse cipher function is applied directly, and + * independently, to each block of the ciphertext. The resulting sequence of + * output blocks is the plaintext.

+ * + *

References:

+ * + *
    + *
  1. + * Recommendation for Block Cipher Modes of Operation Methods and Techniques, + * Morris Dworkin.
  2. + *
+ */ +public class ECB extends BaseMode implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial package-private constructor for use by the Factory class.

+ * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + ECB(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.ECB_MODE, underlyingCipher, cipherBlockSize); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param that the mode to clone. + */ + private ECB(ECB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new ECB(this); + } + + // Implementation of abstract methods in BaseMode -------------------------- + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + { + throw new IllegalArgumentException(IMode.MODE_BLOCK_SIZE); + } + } + + public void teardown() + { + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + cipher.encryptBlock(in, i, out, o); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + cipher.decryptBlock(in, i, out, o); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/IAuthenticatedMode.java b/gnu/javax/crypto/mode/IAuthenticatedMode.java new file mode 100644 index 000000000..9ca23933c --- /dev/null +++ b/gnu/javax/crypto/mode/IAuthenticatedMode.java @@ -0,0 +1,60 @@ +/* IAuthenticatedMode.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.javax.crypto.mac.IMac; + +/** + * The interface for encryption modes that also produce a message authentication + * tag. + * + *

This interface is merely the conjuction of the {@link IMode} and + * {@link IMac} interfaces. Encryption and decryption is done via the + * {@link IMode#update(byte[],int,byte[],int)} method, tag generation + * is done via the {@link IMac#digest()} method, and header updating + * (if supported by the mode) is done via the {@link + * IMac#update(byte[],int,int)} method. + * + * @version $Revision: 1.1.4.1 $ + */ +public interface IAuthenticatedMode extends IMode, IMac +{ + + // Trivial conjunction of IMode and IMac. +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/ICM.java b/gnu/javax/crypto/mode/ICM.java new file mode 100644 index 000000000..d37908b5d --- /dev/null +++ b/gnu/javax/crypto/mode/ICM.java @@ -0,0 +1,228 @@ +/* ICM.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.math.BigInteger; + +/** + *

An implementation of David McGrew Integer Counter Mode (ICM) as an + * {@link IMode}.

+ * + *

ICM is a way to define a pseudorandom keystream generator using a block + * cipher. The keystream can be used for additive encryption, key derivation, + * or any other application requiring pseudorandom data. In the case of this + * class, it is used as additive encryption, XOR-ing the keystream with the + * input text --for both encryption and decryption.

+ * + *

In ICM, the keystream is logically broken into segments. Each segment is + * identified with a segment index, and the segments have equal lengths. This + * segmentation makes ICM especially appropriate for securing packet-based + * protocols. ICM also allows a variety of configurations based, among other + * things, on two parameters: the block index length and the + * segment index length. A constraint on those two values exists: The sum + * of segment index length and block index length must not + * half the block size of the underlying cipher. This requirement protects + * the ICM keystream generator from potentially failing to be pseudorandom.

+ * + *

For simplicity, this implementation, fixes these two values to the + * following:

+ * + *
    + *
  • block index length: is half the underlying cipher block size, and
  • + *
  • segment index length: is zero.
  • + *
+ * + *

For a 128-bit block cipher, the above values imply a maximum keystream + * length of 295,147,905,179,352,825,856 octets, since in ICM, each segment must + * not exceed the value (256 ^ block index length) * block length + * octets.

+ * + *

Finally, for this implementation of the ICM, the IV placeholder will be + * used to pass the value of the Offset in the keystream segment.

+ * + *

References:

+ * + *
    + *
  1. + * Integer Counter Mode, David A. McGrew.
  2. + *
+ */ +public class ICM extends BaseMode implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The integer value 256 as a BigInteger. */ + private static final BigInteger TWO_FIFTY_SIX = new BigInteger("256"); + + /** Maximum number of blocks per segment. */ + private BigInteger maxBlocksPerSegment; + + /** A work constant. */ + private BigInteger counterRange; + + /** The initial counter for a given keystream segment. */ + private BigInteger C0; + + /** The index of the next block for a given keystream segment. */ + private BigInteger blockNdx; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial package-private constructor for use by the Factory class.

+ * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + ICM(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.ICM_MODE, underlyingCipher, cipherBlockSize); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param that the instance to clone. + */ + private ICM(ICM that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Cloneable interface implementation + // ------------------------------------------------------------------------- + + public Object clone() + { + return new ICM(this); + } + + // Implementation of abstract methods in BaseMode + // ------------------------------------------------------------------------- + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + { + throw new IllegalArgumentException(); + } + + counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize); + maxBlocksPerSegment = TWO_FIFTY_SIX.pow(cipherBlockSize / 2); + BigInteger r = new BigInteger(1, iv); + C0 = maxBlocksPerSegment.add(r).modPow(BigInteger.ONE, counterRange); + blockNdx = BigInteger.ZERO; + } + + public void teardown() + { + counterRange = null; + maxBlocksPerSegment = null; + C0 = null; + blockNdx = null; + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + icm(in, i, out, o); + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + icm(in, i, out, o); + } + + // Instance methods + // ------------------------------------------------------------------------- + + private void icm(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (blockNdx.compareTo(maxBlocksPerSegment) >= 0) + throw new RuntimeException("Maximum blocks for segment reached"); + + // encrypt the counter for the current blockNdx + // C[i] = (C[0] + i) modulo (256^BLOCK_LENGTH). + + BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange); + byte[] result = Ci.toByteArray(); + int limit = result.length; + // if (limit < cipherBlockSize) { + // byte[] data = new byte[cipherBlockSize]; + // System.arraycopy(result, 0, data, cipherBlockSize-limit, limit); + // result = data; + // } else if (limit > cipherBlockSize) { + // byte[] data = new byte[cipherBlockSize]; + // System.arraycopy(result, limit-cipherBlockSize, data, 0, cipherBlockSize); + // result = data; + // } + // + // cipher.encryptBlock(result, 0, result, 0); + // blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx + // for (int i = 0; i < modeBlockSize; ) { // xor result with input block + // out[outOffset++] = (byte)(in[inOffset++] ^ result[i++]); + // } + int ndx = 0; + if (limit < cipherBlockSize) + { + byte[] data = new byte[cipherBlockSize]; + System.arraycopy(result, 0, data, cipherBlockSize - limit, limit); + result = data; + } + else if (limit > cipherBlockSize) + { + ndx = limit - cipherBlockSize; + } + + cipher.encryptBlock(result, ndx, result, ndx); + blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx + for (int i = 0; i < modeBlockSize; i++) + { // xor result with input block + out[outOffset++] = (byte) (in[inOffset++] ^ result[ndx++]); + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/IMode.java b/gnu/javax/crypto/mode/IMode.java new file mode 100644 index 000000000..4cb6ca64b --- /dev/null +++ b/gnu/javax/crypto/mode/IMode.java @@ -0,0 +1,145 @@ +/* IMode.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + *

The basic visible methods of any block cipher mode.

+ * + *

Block ciphers encrypt plaintext in fixed size n-bit blocks. For messages + * larger than n bits, the simplest approach is to segment the message into + * n-bit blocks and process (encrypt and/or decrypt) each one separately + * (Electronic Codebook or ECB mode). But this approach has disadvantages in + * most applications. The block cipher modes of operations are one way of + * working around those disadvantages.

+ * + *

A Mode always employs an underlying block cipher for processing its + * input. For all intents and purposes, a Mode appears to behave as any + * other block cipher with the following differences:

+ * + *
    + *
  • Depending on the specifications of the mode, the block size may be + * different that that of the underlying cipher.
  • + * + *
  • While some modes of operations allow operations on block sizes that + * can be 1-bit long, this library will only deal with sizes that are + * multiple of 8 bits. This is because the byte is the smallest, + * easy to handle, primitive type in Java.
  • + * + *
  • Some modes need an Initialisation Vector (IV) to be properly + * initialised.
  • + *
+ * + *

Possible additional initialisation values for an instance of that type + * are:

+ * + *
    + *
  • The block size in which to operate this mode instance. This + * value is optional, if unspecified, the underlying block cipher's + * configured block size shall be used.
  • + * + *
  • Whether this mode will be used for encryption or decryption. This + * value is mandatory and should be included in the initialisation + * parameters. If it isn't, a {@link java.lang.IllegalStateException} will + * be thrown if any method, other than reset() is invoked on the + * instance.
  • + * + *
  • The byte array containing the initialisation vector, if + * required by this type of mode.
  • + *
+ */ +public interface IMode extends IBlockCipher +{ + + // Constants + // ------------------------------------------------------------------------- + + /** + *

Property name of the state in which to operate this mode. The value + * associated to this property name is taken to be an {@link Integer} which + * value is either ENCRYPTION or DECRYPTION.

+ */ + String STATE = "gnu.crypto.mode.state"; + + /** + *

Property name of the block size in which to operate this mode. The + * value associated with this property name is taken to be an {@link Integer}. + * If it is not specified, the value of the block size of the underlying + * block cipher, used to construct the mode instance, shall be used.

+ */ + String MODE_BLOCK_SIZE = "gnu.crypto.mode.block.size"; + + /** + *

Property name of the initialisation vector to use, if required, with + * this instance. The value associated with this property name is taken to + * be a byte array. If the concrete instance needs such a parameter, and it + * has not been specified as part of the initialissation parameters, an + * all-zero byte array of the appropriate size shall be used.

+ */ + String IV = "gnu.crypto.mode.iv"; + + /** + *

Constant indicating the instance is being used for encryption.

+ */ + int ENCRYPTION = 1; + + /** + *

Constant indicating the instance is being used for decryption.

+ */ + int DECRYPTION = 2; + + // Methods + // ------------------------------------------------------------------------- + + /** + *

A convenience method. Effectively invokes the encryptBlock() + * or decryptBlock() method depending on the operational state + * of the instance.

+ * + * @param in the plaintext. + * @param inOffset index of in from which to start considering + * data. + * @param out the ciphertext. + * @param outOffset index of out from which to store result. + * @exception IllegalStateException if the instance is not initialised. + */ + void update(byte[] in, int inOffset, byte[] out, int outOffset) + throws IllegalStateException; +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/ModeFactory.java b/gnu/javax/crypto/mode/ModeFactory.java new file mode 100644 index 000000000..0e949ed9e --- /dev/null +++ b/gnu/javax/crypto/mode/ModeFactory.java @@ -0,0 +1,192 @@ +/* ModeFactory.java -- + Copyright (C) 2001, 2002, 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + *

A Factory to instantiate block cipher modes of operations.

+ */ +public class ModeFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private ModeFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a block cipher mode of operations given its name + * and characteristics of the underlying block cipher.

+ * + * @param mode the case-insensitive name of the mode of operations. + * @param cipher the case-insensitive name of the block cipher. + * @param cipherBlockSize the block size, in bytes, of the underlying cipher. + * @return an instance of the block cipher algorithm, operating in a given + * mode of operations, or null if none found. + * @exception InternalError if either the mode or the underlying block cipher + * implementation does not pass its self-test. + */ + public static IMode getInstance(String mode, String cipher, + int cipherBlockSize) + { + if (mode == null || cipher == null) + { + return null; + } + + mode = mode.trim(); + cipher = cipher.trim(); + + IBlockCipher cipherImpl = CipherFactory.getInstance(cipher); + if (cipherImpl == null) + { + return null; + } + + return getInstance(mode, cipherImpl, cipherBlockSize); + } + + public static IMode getInstance(String mode, IBlockCipher cipher, + int cipherBlockSize) + { + // ensure that cipherBlockSize is valid for the chosen underlying cipher + boolean ok = false; + for (Iterator it = cipher.blockSizes(); it.hasNext();) + { + ok = (cipherBlockSize == ((Integer) it.next()).intValue()); + if (ok) + { + break; + } + } + + if (!ok) + { + throw new IllegalArgumentException("cipherBlockSize"); + } + + IMode result = null; + if (mode.equalsIgnoreCase(ECB_MODE)) + { + result = new ECB(cipher, cipherBlockSize); + } + else if (mode.equalsIgnoreCase(CTR_MODE)) + { + result = new CTR(cipher, cipherBlockSize); + } + else if (mode.equalsIgnoreCase(ICM_MODE)) + { + result = new ICM(cipher, cipherBlockSize); + } + else if (mode.equalsIgnoreCase(OFB_MODE)) + { + result = new OFB(cipher, cipherBlockSize); + } + else if (mode.equalsIgnoreCase(CBC_MODE)) + { + result = new CBC(cipher, cipherBlockSize); + } + else if (mode.equalsIgnoreCase(CFB_MODE)) + { + result = new CFB(cipher, cipherBlockSize); + } + else if (mode.equalsIgnoreCase(EAX_MODE)) + { + result = new EAX(cipher, cipherBlockSize); + } + + if (result != null && !result.selfTest()) + { + throw new InternalError(result.name()); + } + + return result; + } + + /** + *

Returns a {@link java.util.Set} of names of mode supported by this + * Factory.

+ * + * @return a {@link java.util.Set} of mode names (Strings). + */ + public static final Set getNames() + { + synchronized (ModeFactory.class) + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(ECB_MODE); + hs.add(CTR_MODE); + hs.add(ICM_MODE); + hs.add(OFB_MODE); + hs.add(CBC_MODE); + hs.add(CFB_MODE); + hs.add(EAX_MODE); + + names = Collections.unmodifiableSet(hs); + } + } + return names; + } + + private static Set names; + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/mode/OFB.java b/gnu/javax/crypto/mode/OFB.java new file mode 100644 index 000000000..68065d10b --- /dev/null +++ b/gnu/javax/crypto/mode/OFB.java @@ -0,0 +1,194 @@ +/* OFB.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.mode; + +import gnu.java.security.Registry; + +import gnu.javax.crypto.cipher.IBlockCipher; + +/** + *

The Output Feedback (OFB) mode is a confidentiality mode that requires a + * unique IV for every message that is ever encrypted under the + * given key. The OFB mode is defined as follows:

+ * + *
    + *
  • OFB Encryption: + *
      + *
    • I1 = IV;
    • + *
    • Ij = Oj -1 for j = 2...n;
    • + *
    • Oj = CIPHK(Ij) for j = 1, 2...n;
    • + *
    • Cj = Pj XOR Oj for j = 1, 2...n.
    • + *
  • + *
  • OFB Decryption: + *
      + *
    • I1 = IV;
    • + *
    • Ij = Oj -1 for j = 2...n;
    • + *
    • Oj = CIPHK(Ij) for j = 1, 2...n;
    • + *
    • Pj = Cj XOR Oj for j = 1, 2...n.
    • + *
  • + *
+ * + *

In OFB encryption, the IV is transformed by the forward + * cipher function to produce the first output block. The first output block is + * exclusive-ORed with the first plaintext block to produce the first ciphertext + * block. The first output block is then transformed by the forward cipher + * function to produce the second output block. The second output block is + * exclusive-ORed with the second plaintext block to produce the second + * ciphertext block, and the second output block is transformed by the forward + * cipher function to produce the third output block. Thus, the successive + * output blocks are produced from enciphering the previous output blocks, and + * the output blocks are exclusive-ORed with the corresponding plaintext blocks + * to produce the ciphertext blocks.

+ * + *

In OFB decryption, the IV is transformed by the forward cipher + * function to produce the first output block. The first output block is + * exclusive-ORed with the first ciphertext block to recover the first plaintext + * block. The first output block is then transformed by the forward cipher + * function to produce the second output block. The second output block is + * exclusive-ORed with the second ciphertext block to produce the second + * plaintext block, and the second output block is also transformed by the + * forward cipher function to produce the third output block. Thus, the + * successive output blocks are produced from enciphering the previous output + * blocks, and the output blocks are exclusive-ORed with the corresponding + * ciphertext blocks to recover the plaintext blocks.

+ * + *

In both OFB encryption and OFB decryption, each forward cipher function + * (except the first) depends on the results of the previous forward cipher + * function; therefore, multiple forward cipher functions cannot be performed + * in parallel. However, if the IV is known, the output blocks can + * be generated prior to the availability of the plaintext or ciphertext data.

+ * + *

The OFB mode requires a unique IV for every message that is + * ever encrypted under the given key. If, contrary to this requirement, the + * same IV is used for the encryption of more than one message, + * then the confidentiality of those messages may be compromised. In particular, + * if a plaintext block of any of these messages is known, say, the jth + * plaintext block, then the jth output of the forward cipher + * function can be determined easily from the jth ciphertext block of + * the message. This information allows the jth plaintext block of + * any other message that is encrypted using the same IV to be + * easily recovered from the jth ciphertext block of that message.

+ * + *

Confidentiality may similarly be compromised if any of the input blocks to + * the forward cipher function for the encryption of a message is used as the + * IV for the encryption of another message under the given key.

+ * + *

References:

+ * + *
    + *
  1. + * Recommendation for Block Cipher Modes of Operation Methods and Techniques, + * Morris Dworkin.
  2. + *
+ */ +public class OFB extends BaseMode implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private byte[] outputBlock; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial package-private constructor for use by the Factory class.

+ * + * @param underlyingCipher the underlying cipher implementation. + * @param cipherBlockSize the underlying cipher block size to use. + */ + OFB(IBlockCipher underlyingCipher, int cipherBlockSize) + { + super(Registry.OFB_MODE, underlyingCipher, cipherBlockSize); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param that the mode to clone. + */ + private OFB(OFB that) + { + this((IBlockCipher) that.cipher.clone(), that.cipherBlockSize); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() + { + return new OFB(this); + } + + // Implementation of abstract methods in BaseMode -------------------------- + + public void setup() + { + if (modeBlockSize != cipherBlockSize) + { + throw new IllegalArgumentException(IMode.MODE_BLOCK_SIZE); + } + + outputBlock = (byte[]) iv.clone(); + } + + public void teardown() + { + } + + public void encryptBlock(byte[] in, int i, byte[] out, int o) + { + cipher.encryptBlock(outputBlock, 0, outputBlock, 0); + for (int j = 0; j < cipherBlockSize;) + { + out[o++] = (byte) (in[i++] ^ outputBlock[j++]); + } + } + + public void decryptBlock(byte[] in, int i, byte[] out, int o) + { + this.encryptBlock(in, i, out, o); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/pad/BasePad.java b/gnu/javax/crypto/pad/BasePad.java new file mode 100644 index 000000000..49c5d050a --- /dev/null +++ b/gnu/javax/crypto/pad/BasePad.java @@ -0,0 +1,153 @@ +/* BasePad.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +/** + *

An abstract class to facilitate implementing padding algorithms.

+ */ +public abstract class BasePad implements IPad +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The canonical name prefix of the padding algorithm. */ + protected String name; + + /** The block size, in bytes, for this instance. */ + protected int blockSize; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor for use by concrete subclasses. */ + protected BasePad(final String name) + { + super(); + + this.name = name; + blockSize = -1; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IPad interface implementation ------------------------------------------- + + public String name() + { + final StringBuffer sb = new StringBuffer(name); + if (blockSize != -1) + { + sb.append('-').append(String.valueOf(8 * blockSize)); + } + return sb.toString(); + } + + public void init(final int bs) throws IllegalStateException + { + if (blockSize != -1) + { + throw new IllegalStateException(); + } + blockSize = bs; + setup(); + } + + public void reset() + { + blockSize = -1; + } + + public boolean selfTest() + { + byte[] padBytes; + final int offset = 5; + final int limit = 1024; + final byte[] in = new byte[limit]; + for (int bs = 2; bs < 256; bs++) + { + this.init(bs); + for (int i = 0; i < limit - offset - blockSize; i++) + { + padBytes = pad(in, offset, i); + if (((i + padBytes.length) % blockSize) != 0) + { + new RuntimeException(name()).printStackTrace(System.err); + return false; + } + + System.arraycopy(padBytes, 0, in, offset + i, padBytes.length); + try + { + if (padBytes.length != unpad(in, offset, i + padBytes.length)) + { + new RuntimeException(name()).printStackTrace(System.err); + return false; + } + } + catch (WrongPaddingException x) + { + x.printStackTrace(System.err); + return false; + } + } + this.reset(); + } + + return true; + } + + // abstract methods to implement by subclasses ----------------------------- + + /** + *

If any additional checks or resource setup must be done by the + * subclass, then this is the hook for it. This method will be called before + * the {@link #init(int)} method returns.

+ */ + public abstract void setup(); + + public abstract byte[] pad(byte[] in, int off, int len); + + public abstract int unpad(byte[] in, int off, int len) + throws WrongPaddingException; +} \ No newline at end of file diff --git a/gnu/javax/crypto/pad/IPad.java b/gnu/javax/crypto/pad/IPad.java new file mode 100644 index 000000000..4b4c925e6 --- /dev/null +++ b/gnu/javax/crypto/pad/IPad.java @@ -0,0 +1,110 @@ +/* IPad.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +/** + *

The basic visible methods of any padding algorithm.

+ * + *

Padding algorithms serve to pad and unpad byte arrays usually + * as the last step in an encryption or respectively a decryption + * operation. Their input buffers are usually those processed by instances of + * {@link gnu.crypto.mode.IMode} and/or {@link gnu.crypto.cipher.IBlockCipher}.

+ */ +public interface IPad +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** @return the canonical name of this instance. */ + String name(); + + /** + * Initialises the padding scheme with a designated block size. + * + * @param bs the designated block size. + * @exception IllegalStateException if the instance is already initialised. + * @exception IllegalArgumentException if the block size value is invalid. + */ + void init(int bs) throws IllegalStateException; + + /** + * Returns the byte sequence that should be appended to the designated input. + * + * @param in the input buffer containing the bytes to pad. + * @param offset the starting index of meaningful data in in. + * @param length the number of meaningful bytes in in. + * @return the possibly 0-byte long sequence to be appended to the designated + * input. + */ + byte[] pad(byte[] in, int offset, int length); + + /** + * Returns the number of bytes to discard from a designated input buffer. + * + * @param in the input buffer containing the bytes to unpad. + * @param offset the starting index of meaningful data in in. + * @param length the number of meaningful bytes in in. + * @return the number of bytes to discard, to the left of index position + * offset + length in in. In other words, if the return + * value of a successful invocation of this method is result, then + * the unpadded byte sequence will be offset + length - result bytes + * in in, starting from index position offset. + * @exception WrongPaddingException if the data is not terminated with the + * expected padding bytes. + */ + int unpad(byte[] in, int offset, int length) throws WrongPaddingException; + + /** + * Resets the scheme instance for re-initialisation and use with other + * characteristics. This method always succeeds. + */ + void reset(); + + /** + * A basic symmetric pad/unpad test. + * + * @return true if the implementation passes a basic symmetric + * self-test. Returns false otherwise. + */ + boolean selfTest(); +} \ No newline at end of file diff --git a/gnu/javax/crypto/pad/PKCS1_V1_5.java b/gnu/javax/crypto/pad/PKCS1_V1_5.java new file mode 100644 index 000000000..03c3d61a3 --- /dev/null +++ b/gnu/javax/crypto/pad/PKCS1_V1_5.java @@ -0,0 +1,184 @@ +/* PKCS1_V1_5.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.EME_PKCS1_V1_5; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; + +import java.io.PrintWriter; + +/** + *

A padding algorithm implementation of the EME-PKCS1-V1.5 encoding/decoding + * algorithm as described in section 7.2 of RFC-3447. This is effectively an + * Adapter over an instance of {@link EME_PKCS1_V1_5} initialised with + * the RSA public shared modulus length (in bytes).

+ * + *

References:

+ *
    + *
  1. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ * + * @see EME_PKCS1_V1_5 + */ +public class PKCS1_V1_5 extends BasePad +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = Registry.EME_PKCS1_V1_5_PAD; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(final String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + private EME_PKCS1_V1_5 codec; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial package-private constructor for use by the Factory class. + *

+ * + * @see gnu.crypto.pad.PadFactory + */ + PKCS1_V1_5() + { + super(Registry.EME_PKCS1_V1_5_PAD); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BasePad + // ------------------------------------------------------------------------- + + public void setup() + { + codec = EME_PKCS1_V1_5.getInstance(blockSize); + } + + public byte[] pad(final byte[] in, final int offset, final int length) + { + final byte[] M = new byte[length]; + System.arraycopy(in, offset, M, 0, length); + final byte[] EM = codec.encode(M); + final byte[] result = new byte[blockSize - length]; + System.arraycopy(EM, 0, result, 0, result.length); + if (DEBUG && debuglevel > 8) + { + debug("padding: 0x" + Util.toString(result)); + } + return result; + } + + public int unpad(final byte[] in, final int offset, final int length) + throws WrongPaddingException + { + final byte[] EM = new byte[length]; + System.arraycopy(in, offset, EM, 0, length); + final int result = length - codec.decode(EM).length; + if (DEBUG && debuglevel > 8) + { + debug("padding length: " + String.valueOf(result)); + } + return result; + } + + // overloaded methods ------------------------------------------------------ + + public boolean selfTest() + { + final int[] mLen = new int[] { 16, 20, 32, 48, 64 }; + final byte[] M = new byte[mLen[mLen.length - 1]]; + PRNG.getInstance().nextBytes(M); + final byte[] EM = new byte[1024]; + byte[] p; + int bs, i, j; + for (bs = 256; bs < 1025; bs += 256) + { + init(bs); + for (i = 0; i < mLen.length; i++) + { + j = mLen[i]; + p = pad(M, 0, j); + if (j + p.length != blockSize) + { + new RuntimeException(name()).printStackTrace(System.err); + return false; + } + + System.arraycopy(p, 0, EM, 0, p.length); + System.arraycopy(M, 0, EM, p.length, j); + try + { + if (p.length != unpad(EM, 0, blockSize)) + { + new RuntimeException(name()).printStackTrace(System.err); + return false; + } + } + catch (WrongPaddingException x) + { + x.printStackTrace(System.err); + return false; + } + } + reset(); + } + + return true; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/pad/PKCS7.java b/gnu/javax/crypto/pad/PKCS7.java new file mode 100644 index 000000000..5697aff27 --- /dev/null +++ b/gnu/javax/crypto/pad/PKCS7.java @@ -0,0 +1,149 @@ +/* PKCS7.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.io.PrintWriter; + +/** + *

The implementation of the PKCS7 padding algorithm.

+ * + *

This algorithm is described for 8-byte blocks in [RFC-1423] and extended to + * block sizes of up to 256 bytes in [PKCS-7].

+ * + * References:
+ * RFC-1423: Privacy + * Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, and + * Identifiers.
+ * IETF. + * [PKCS-7]PKCS #7: + * Cryptographic Message Syntax Standard - An RSA Laboratories Technical Note.
+ * RSA Security.

+ */ +public final class PKCS7 extends BasePad +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "pkcs7"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial package-private constructor for use by the Factory class.

+ * + * @see gnu.crypto.pad.PadFactory + */ + PKCS7() + { + super(Registry.PKCS7_PAD); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BasePad + // ------------------------------------------------------------------------- + + public void setup() + { + if (blockSize < 2 || blockSize > 256) + { + throw new IllegalArgumentException(); + } + } + + public byte[] pad(byte[] in, int offset, int length) + { + int padLength = blockSize; + if (length % blockSize != 0) + { + padLength = blockSize - length % blockSize; + } + byte[] result = new byte[padLength]; + for (int i = 0; i < padLength;) + { + result[i++] = (byte) padLength; + } + + if (DEBUG && debuglevel > 8) + { + debug("padding: 0x" + Util.toString(result)); + } + return result; + } + + public int unpad(byte[] in, int offset, int length) + throws WrongPaddingException + { + int limit = offset + length; + int result = in[limit - 1] & 0xFF; + for (int i = 0; i < result; i++) + { + if (result != (in[--limit] & 0xFF)) + { + throw new WrongPaddingException(); + } + } + + if (DEBUG && debuglevel > 8) + { + debug("padding length: " + String.valueOf(result)); + } + return result; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/pad/PadFactory.java b/gnu/javax/crypto/pad/PadFactory.java new file mode 100644 index 000000000..e122719b6 --- /dev/null +++ b/gnu/javax/crypto/pad/PadFactory.java @@ -0,0 +1,136 @@ +/* PadFactory.java -- + Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + *

A Factory to instantiate padding schemes.

+ */ +public class PadFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private PadFactory() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a padding algorithm given its name.

+ * + * @param pad the case-insensitive name of the padding algorithm. + * @return an instance of the padding algorithm, operating with a given + * block size, or null if none found. + * @throws InternalError if the implementation does not pass its self-test. + */ + public static final IPad getInstance(String pad) + { + if (pad == null) + { + return null; + } + + pad = pad.trim().toLowerCase(); + if (pad.endsWith("padding")) + pad = pad.substring(0, pad.length() - "padding".length()); + IPad result = null; + if (pad.equals(PKCS7_PAD)) + { + result = new PKCS7(); + } + else if (pad.equals(TBC_PAD)) + { + result = new TBC(); + } + else if (pad.equals(EME_PKCS1_V1_5_PAD)) + { + result = new PKCS1_V1_5(); + } + else if (pad.equals(SSL3_PAD)) + { + result = new SSL3(); + } + else if (pad.equals(TLS1_PAD)) + { + result = new TLS1(); + } + + if (result != null && !result.selfTest()) + { + throw new InternalError(result.name()); + } + + return result; + } + + /** + *

Returns a {@link java.util.Set} of names of padding algorithms + * supported by this Factory.

+ * + * @return a {@link Set} of padding algorithm names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(PKCS7_PAD); + hs.add(TBC_PAD); + hs.add(EME_PKCS1_V1_5_PAD); + hs.add(SSL3_PAD); + hs.add(TLS1_PAD); + + return Collections.unmodifiableSet(hs); + } + + // Instance methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/pad/SSL3.java b/gnu/javax/crypto/pad/SSL3.java new file mode 100644 index 000000000..25aeefa13 --- /dev/null +++ b/gnu/javax/crypto/pad/SSL3.java @@ -0,0 +1,98 @@ +/* SSL3.java -- SSLv3 padding scheme. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +/** + * The padding scheme used by the Secure Sockets Layer, version 3. This + * padding scheme is used in the block-ciphered struct, e.g.: + * + *
+ * block-ciphered struct {
+ *   opaque content[SSLCompressed.length];
+ *   opaque MAC[CipherSpec.hash_size];
+ *   uint8 padding[GenericBlockCipher.padding_length];
+ *   uint8 padding_length;
+ * } GenericBlockCipher;
+ * 
+ * + *

Where padding_length is cipher_block_size - + * ((SSLCompressed.length + CipherSpec.hash_size) + * % cipher_block_size) - 1. That is, the padding is enough bytes + * to make the plaintext a multiple of the block size minus one, plus one + * additional byte for the padding length. The padding can be any arbitrary + * data.

+ */ +public class SSL3 extends BasePad +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public SSL3() + { + super("ssl3"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void setup() + { + if (blockSize <= 0 || blockSize > 255) + throw new IllegalArgumentException("invalid block size: " + blockSize); + } + + public byte[] pad(final byte[] in, final int off, final int len) + { + int padlen = blockSize - (len % blockSize); + byte[] pad = new byte[padlen]; + for (int i = 0; i < padlen; i++) + pad[i] = (byte) (padlen - 1); + return pad; + } + + public int unpad(final byte[] in, final int off, final int len) + throws WrongPaddingException + { + int padlen = in[off + len - 1] & 0xFF; + if (padlen >= blockSize) + throw new WrongPaddingException(); + return padlen + 1; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/pad/TBC.java b/gnu/javax/crypto/pad/TBC.java new file mode 100644 index 000000000..25c3e4286 --- /dev/null +++ b/gnu/javax/crypto/pad/TBC.java @@ -0,0 +1,156 @@ +/* TBC.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.io.PrintWriter; + +/** + *

The implementation of the Trailing Bit Complement (TBC) padding algorithm.

+ * + *

In this mode, "...the data string is padded at the trailing end with the + * complement of the trailing bit of the unpadded message: if the trailing bit + * is 1, then 0 bits are appended, and if the trailing bit is + * 0, then 1 bits are appended. As few bits are added as are + * necessary to meet the formatting size requirement."

+ * + * References:
+ * + * Recommendation for Block Cipher Modes of Operation Methods and Techniques, + * Morris Dworkin.

+ */ +public final class TBC extends BasePad +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "tbc"; + + private static final boolean DEBUG = false; + + private static final int debuglevel = 9; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String s) + { + err.println(">>> " + NAME + ": " + s); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Trivial package-private constructor for use by the Factory class.

+ * + * @see gnu.crypto.pad.PadFactory + */ + TBC() + { + super(Registry.TBC_PAD); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BasePad + // ------------------------------------------------------------------------- + + public void setup() + { + if (blockSize < 1 || blockSize > 256) + { + throw new IllegalArgumentException(); + } + } + + public byte[] pad(byte[] in, int offset, int length) + { + int padLength = blockSize; + if (length % blockSize != 0) + { + padLength = blockSize - length % blockSize; + } + byte[] result = new byte[padLength]; + int lastBit = in[offset + length - 1] & 0x01; + if (lastBit == 0) + { + for (int i = 0; i < padLength;) + { + result[i++] = 0x01; + } + } // else it's already set to zeroes by virtue of initialisation + + if (DEBUG && debuglevel > 8) + { + debug("padding: 0x" + Util.toString(result)); + } + return result; + } + + public int unpad(byte[] in, int offset, int length) + throws WrongPaddingException + { + int limit = offset + length - 1; + int lastBit = in[limit] & 0xFF; + int result = 0; + while (lastBit == (in[limit] & 0xFF)) + { + result++; + limit--; + } + + if (result > length) + { + throw new WrongPaddingException(); + } + + if (DEBUG && debuglevel > 8) + { + debug("padding length: " + String.valueOf(result)); + } + return result; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/pad/TLS1.java b/gnu/javax/crypto/pad/TLS1.java new file mode 100644 index 000000000..00a538f88 --- /dev/null +++ b/gnu/javax/crypto/pad/TLS1.java @@ -0,0 +1,105 @@ +/* TLS1.java -- TLSv1 padding scheme. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +import gnu.java.security.util.Util; + +/** + * The padding scheme used by the Transport Layer Security protocol, + * version 1. This padding scheme is used in the block-ciphered struct, + * e.g.: + * + *

+ * block-ciphered struct {
+ *   opaque content[TLSCompressed.length];
+ *   opaque MAC[CipherSpec.hash_size];
+ *   uint8 padding[GenericBlockCipher.padding_length];
+ *   uint8 padding_length;
+ * } GenericBlockCipher;
+ * 
+ * + *

Where padding_length is any multiple of cipher_block_size - + * ((SSLCompressed.length + CipherSpec.hash_size) + * % cipher_block_size) - 1 that is less than 255. Every byte of the + * padding must be equal to padding_length. That is, the end of the + * plaintext is n + 1 copies of the unsigned byte n.

+ */ +public class TLS1 extends BasePad +{ + + // Constructors. + // ------------------------------------------------------------------------- + + public TLS1() + { + super("tls1"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void setup() + { + if (blockSize <= 0 || blockSize > 255) + throw new IllegalArgumentException("invalid block size: " + blockSize); + } + + public byte[] pad(final byte[] in, final int off, final int len) + { + int padlen = blockSize - (len % blockSize); + byte[] pad = new byte[padlen]; + for (int i = 0; i < padlen; i++) + { + pad[i] = (byte) (padlen - 1); + } + return pad; + } + + public int unpad(final byte[] in, final int off, final int len) + throws WrongPaddingException + { + int padlen = in[off + len - 1] & 0xFF; + for (int i = off + (len - padlen - 1); i < off + len - 1; i++) + { + if ((in[i] & 0xFF) != padlen) + throw new WrongPaddingException(); + } + return padlen + 1; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/pad/WrongPaddingException.java b/gnu/javax/crypto/pad/WrongPaddingException.java new file mode 100644 index 000000000..4317a5c18 --- /dev/null +++ b/gnu/javax/crypto/pad/WrongPaddingException.java @@ -0,0 +1,63 @@ +/* WrongPaddingException.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.pad; + +/** + *

A checked exception that indicates that a padding algorithm did not find the + * expected padding bytes when unpadding some data.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public class WrongPaddingException extends Exception +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instant methods + // ------------------------------------------------------------------------- +} \ No newline at end of file diff --git a/gnu/javax/crypto/prng/ARCFour.java b/gnu/javax/crypto/prng/ARCFour.java new file mode 100644 index 000000000..22316ec8b --- /dev/null +++ b/gnu/javax/crypto/prng/ARCFour.java @@ -0,0 +1,161 @@ +/* ARCFour.java -- + Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; + +import java.util.Map; + +/** + * RC4 is a stream cipher developed by Ron Rivest. Until 1994 RC4 was a + * trade secret of RSA Data Security, Inc., when it was released + * anonymously to a mailing list. This version is a descendent of that + * code, and since there is no proof that the leaked version was in fact + * RC4 and because "RC4" is a trademark, it is called "ARCFOUR", short for + * "Allegedly RC4". + * + *

This class only implements the keystream of ARCFOUR. To use + * this as a stream cipher, one would say:

+ * + *
    out = in ^ arcfour.nextByte();
+ * + *

This operation works for encryption and decryption.

+ * + *

References:

+ * + *
    + *
  1. Schneier, Bruce: Applied Cryptography: Protocols, Algorithms, + * and Source Code in C, Second Edition. (1996 John Wiley and Sons), + * pp. 397--398. ISBN 0-471-11709-9
  2. + *
  3. K. Kaukonen and R. Thayer, "A Stream Cipher Encryption Algorithm + * 'Arcfour'", Internet Draft (expired), draft-kaukonen-cipher-arcfour-03.txt
  4. + *
+ */ +public class ARCFour extends BasePRNG implements Cloneable +{ + + // Constants and variables. + // ----------------------------------------------------------------------- + + /** The attributes property name for the key bytes. */ + public static final String ARCFOUR_KEY_MATERIAL = "gnu.crypto.prng.arcfour.key-material"; + + /** The size of the internal S-box. */ + public static final int ARCFOUR_SBOX_SIZE = 256; + + /** The S-box. */ + private byte[] s; + + private byte m, n; + + // Constructors. + // ----------------------------------------------------------------------- + + /** Default 0-arguments constructor. */ + public ARCFour() + { + super(Registry.ARCFOUR_PRNG); + } + + // Methods implementing BasePRNG. + // ----------------------------------------------------------------------- + + public void setup(Map attributes) + { + byte[] kb = (byte[]) attributes.get(ARCFOUR_KEY_MATERIAL); + + if (kb == null) + { + throw new IllegalArgumentException("ARCFOUR needs a key"); + } + + s = new byte[ARCFOUR_SBOX_SIZE]; + m = n = 0; + byte[] k = new byte[ARCFOUR_SBOX_SIZE]; + + for (int i = 0; i < ARCFOUR_SBOX_SIZE; i++) + { + s[i] = (byte) i; + } + + if (kb.length > 0) + { + for (int i = 0, j = 0; i < ARCFOUR_SBOX_SIZE; i++) + { + k[i] = kb[j++]; + if (j >= kb.length) + j = 0; + } + } + + for (int i = 0, j = 0; i < ARCFOUR_SBOX_SIZE; i++) + { + j = j + s[i] + k[i]; + byte temp = s[i]; + s[i] = s[j & 0xff]; + s[j & 0xff] = temp; + } + + buffer = new byte[ARCFOUR_SBOX_SIZE]; + try + { + fillBlock(); + } + catch (LimitReachedException wontHappen) + { + } + } + + public void fillBlock() throws LimitReachedException + { + for (int i = 0; i < buffer.length; i++) + { + m++; + n = (byte) (n + s[m & 0xff]); + byte temp = s[m & 0xff]; + s[m & 0xff] = s[n & 0xff]; + s[n & 0xff] = temp; + temp = (byte) (s[m & 0xff] + s[n & 0xff]); + buffer[i] = s[temp & 0xff]; + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/prng/CSPRNG.java b/gnu/javax/crypto/prng/CSPRNG.java new file mode 100644 index 000000000..197009232 --- /dev/null +++ b/gnu/javax/crypto/prng/CSPRNG.java @@ -0,0 +1,1268 @@ +/* CSPRNG.java -- continuously-seeded pseudo-random number generator. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Properties; +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.EntropySource; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.SimpleList; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.PrintStream; + +import java.net.MalformedURLException; +import java.net.URL; + +import java.security.AccessController; +import java.security.InvalidKeyException; +import java.security.PrivilegedAction; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +/** + *

An entropy pool-based pseudo-random number generator based on the PRNG + * in Peter Gutmann's cryptlib (http://www.cs.auckland.ac.nz/~pgut001/cryptlib/).

+ * + *

The basic properties of this generator are:

+ * + *
    + *
  1. The internal state cannot be determined by knowledge of the input.
  2. + *
  3. It is resistant to bias introduced by specific inputs.
  4. + *
  5. The output does not reveal the state of the generator.
  6. + *
+ */ +public class CSPRNG extends BasePRNG +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + + private static void debug(String msg) + { + System.err.print(">>> CSPRNG: "); + System.err.println(msg); + } + + /** + * Property name for the list of files to read for random values. The + * mapped value is a list with the following values: + * + *
    + *
  1. A {@link Double}, indicating the suggested quality of this + * source. This value must be between 0 and 100.
  2. + *
  3. An {@link Integer}, indicating the number of bytes to skip in the file + * before reading bytes. This can be any nonnegative value.
  4. + *
  5. An {@link Integer}, indicating the number of bytes to read.
  6. + *
  7. A {@link String}, indicating the path to the file.
  8. + *
+ * + * @see gnu.crypto.util.SimpleList + */ + public static final String FILE_SOURCES = "gnu.crypto.prng.pool.files"; + + /** + * Property name for the list of URLs to poll for random values. The + * mapped value is a list formatted similarly as in {@link #FILE_SOURCES}, + * but the fourth member is a {@link URL}. + */ + public static final String URL_SOURCES = "gnu.crypto.prng.pool.urls"; + + /** + * Property name for the list of programs to execute, and use the output + * as new random bytes. The mapped property is formatted similarly an in + * {@link #FILE_SOURCES} and {@link #URL_SOURCES}, except the fourth + * member is a {@link String} of the program to execute. + */ + public static final String PROGRAM_SOURCES = "gnu.crypto.prng.pool.programs"; + + /** + * Property name for a list of other sources of entropy. The mapped + * value must be a list of {@link EntropySource} objects. + */ + public static final String OTHER_SOURCES = "gnu.crypto.prng.pool.other"; + + /** + * Property name for whether or not to wait for the slow poll to + * complete, passed as a {@link Boolean}. The default value is true. + */ + public static final String BLOCKING = "gnu.crypto.prng.pool.blocking"; + + private static final String FILES = "gnu.crypto.csprng.file."; + + private static final String URLS = "gnu.crypto.csprng.url."; + + private static final String PROGS = "gnu.crypto.csprng.program."; + + private static final String OTHER = "gnu.crypto.csprng.other."; + + private static final String BLOCK = "gnu.crypto.csprng.blocking"; + + private static final int POOL_SIZE = 256; + + private static final int ALLOC_SIZE = 260; + + private static final int OUTPUT_SIZE = POOL_SIZE / 2; + + private static final int X917_POOL_SIZE = 16; + + private static final String HASH_FUNCTION = Registry.SHA160_HASH; + + private static final String CIPHER = Registry.AES_CIPHER; + + private static final int MIX_COUNT = 10; + + private static final int X917_LIFETIME = 8192; + + // FIXME this should be configurable. + private static final int SPINNER_COUNT = 8; + + /** + * The spinner group singleton. We use this to add a small amount of + * randomness (in addition to the current time and the amount of + * free memory) based on the randomness (if any) present due to + * system load and thread scheduling. + */ + private static final Spinner[] SPINNERS = new Spinner[SPINNER_COUNT]; + + private static final Thread[] SPINNER_THREADS = new Thread[SPINNER_COUNT]; + static + { + for (int i = 0; i < SPINNER_COUNT; i++) + { + SPINNER_THREADS[i] = new Thread(SPINNERS[i] = new Spinner(), + "spinner-" + i); + SPINNER_THREADS[i].setDaemon(true); + SPINNER_THREADS[i].setPriority(Thread.MIN_PRIORITY); + SPINNER_THREADS[i].start(); + } + } + + /** + * The message digest (SHA-1) used in the mixing function. + */ + private final IMessageDigest hash; + + /** + * The cipher (AES) used in the output masking function. + */ + private final IBlockCipher cipher; + + /** + * The number of times the pool has been mixed. + */ + private int mixCount; + + /** + * The entropy pool. + */ + private final byte[] pool; + + /** + * The quality of the random pool (percentage). + */ + private double quality; + + /** + * The index of the next byte in the entropy pool. + */ + private int index; + + /** + * The pool for the X9.17-like generator. + */ + private byte[] x917pool; + + /** + * The number of iterations of the X9.17-like generators. + */ + private int x917count; + + /** + * Whether or not the X9.17-like generator is initialized. + */ + private boolean x917init; + + /** + * The list of file soures. + */ + private final List files; + + /** + * The list of URL sources. + */ + private final List urls; + + /** + * The list of program sources. + */ + private final List progs; + + /** + * The list of other sources. + */ + private final List other; + + /** + * Whether or not to wait for the slow poll to complete. + */ + private boolean blocking; + + /** + * The thread that polls for random data. + */ + private Poller poller; + + private Thread pollerThread; + + // Constructor. + // ------------------------------------------------------------------------- + + public CSPRNG() + { + super("CSPRNG"); + pool = new byte[ALLOC_SIZE]; + x917pool = new byte[X917_POOL_SIZE]; + x917count = 0; + x917init = false; + quality = 0.0; + hash = HashFactory.getInstance(HASH_FUNCTION); + cipher = CipherFactory.getInstance(CIPHER); + buffer = new byte[OUTPUT_SIZE]; + ndx = 0; + initialised = false; + files = new LinkedList(); + urls = new LinkedList(); + progs = new LinkedList(); + other = new LinkedList(); + } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + *

Create and initialize a CSPRNG instance with the "system" parameters; + * the files, URLs, programs, and {@link EntropySource} sources used by + * the instance are derived from properties set in the system {@link + * Properties}.

+ * + *

All properties are of the from name.N, where name + * is the name of the source, and N is an integer (staring at 1) that + * indicates the preference number for that source.

+ * + *

The following vales for name are used here:

+ * + *
+ *
gnu.crypto.csprng.file
+ *

These properties are file sources, passed as the {@link #FILE_SOURCES} + * parameter of the instance. The property value is a 4-tuple formatted as:

+ * + *
quality ; offset ; count ; path
+ * + *

The parameters are mapped to the parameters defined for {@link + * #FILE_SOURCES}. Leading or trailing spaces on any item are trimmed + * off.

+ * + *
gnu.crypto.csprng.url
+ *

These properties are URL sources, passed as the {@link #URL_SOURCES} + * parameter of the instance. The property is formatted the same way as file + * sources, but the path argument must be a valid URL.

+ * + *
gnu.crypto.csprng.program
+ *

These properties are program sources, passed as the {@link + * #PROGRAM_SOURCES} parameter of the instance. This property is formatted + * the same way as file and URL sources, but the last argument is a program + * and its arguments.

+ * + *
gnu.crypto.cspring.other
+ *

These properties are other sources, passed as the {@link OTHER_SOURCES} + * parameter of the instance. The property value must be the full name + * of a class that implements the {@link EntropySource} interface and has a + * public no-argument constructor.

+ *
+ * + *

Finally, a boolean property "gnu.crypto.csprng.blocking" can be set to + * the desired value of {@link #BLOCKING}.

+ * + *

An example of valid properties would be:

+ * + *
+   * gnu.crypto.csprng.blocking=true
+   *
+   * gnu.crypto.csprng.file.1=75.0;0;256;/dev/random
+   * gnu.crypto.csprng.file.2=10.0;0;100;/home/user/file
+   *
+   * gnu.crypto.csprng.url.1=5.0;0;256;http://www.random.org/cgi-bin/randbyte?nbytes=256
+   * gnu.crypto.csprng.url.2=0;256;256;http://slashdot.org/
+   *
+   * gnu.crypto.csprng.program.1=0.5;0;10;last -n 50
+   * gnu.crypto.csprng.program.2=0.5;0;10;tcpdump -c 5
+   *
+   * gnu.crypto.csprng.other.1=foo.bar.MyEntropySource
+   * gnu.crypto.csprng.other.2=com.company.OtherEntropySource
+   * 
+ */ + public static IRandom getSystemInstance() throws ClassNotFoundException, + MalformedURLException, NumberFormatException + { + CSPRNG instance = new CSPRNG(); + HashMap attrib = new HashMap(); + attrib.put(BLOCKING, new Boolean(getProperty(BLOCK))); + String s = null; + + // Get each file source "gnu.crypto.csprng.file.N". + List l = new LinkedList(); + for (int i = 0; (s = getProperty(FILES + i)) != null; i++) + { + try + { + l.add(parseString(s.trim())); + } + catch (NumberFormatException nfe) + { + } + } + attrib.put(FILE_SOURCES, l); + + l = new LinkedList(); + for (int i = 0; (s = getProperty(URLS + i)) != null; i++) + { + try + { + l.add(parseURL(s.trim())); + } + catch (NumberFormatException nfe) + { + } + catch (MalformedURLException mue) + { + } + } + attrib.put(URL_SOURCES, l); + + l = new LinkedList(); + for (int i = 0; (s = getProperty(PROGS + i)) != null; i++) + { + try + { + l.add(parseString(s.trim())); + } + catch (NumberFormatException nfe) + { + } + } + attrib.put(PROGRAM_SOURCES, l); + + l = new LinkedList(); + for (int i = 0; (s = getProperty(OTHER + i)) != null; i++) + { + try + { + Class c = Class.forName(s.trim()); + l.add(c.newInstance()); + } + catch (ClassNotFoundException cnfe) + { + } + catch (InstantiationException ie) + { + } + catch (IllegalAccessException iae) + { + } + } + attrib.put(OTHER_SOURCES, l); + + instance.init(attrib); + return instance; + } + + private static String getProperty(final String name) + { + return (String) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return Properties.getProperty(name); + } + }); + } + + private static List parseString(String s) throws NumberFormatException + { + StringTokenizer tok = new StringTokenizer(s, ";"); + if (tok.countTokens() != 4) + { + throw new IllegalArgumentException("malformed property"); + } + Double quality = new Double(tok.nextToken()); + Integer offset = new Integer(tok.nextToken()); + Integer length = new Integer(tok.nextToken()); + String str = tok.nextToken(); + return new SimpleList(quality, offset, length, str); + } + + private static List parseURL(String s) throws MalformedURLException, + NumberFormatException + { + StringTokenizer tok = new StringTokenizer(s, ";"); + if (tok.countTokens() != 4) + { + throw new IllegalArgumentException("malformed property"); + } + Double quality = new Double(tok.nextToken()); + Integer offset = new Integer(tok.nextToken()); + Integer length = new Integer(tok.nextToken()); + URL url = new URL(tok.nextToken()); + return new SimpleList(quality, offset, length, url); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() + { + return new CSPRNG(); + } + + public void setup(Map attrib) + { + List list = null; + + if (DEBUG) + { + debug(String.valueOf(attrib)); + } + try + { + list = (List) attrib.get(FILE_SOURCES); + if (DEBUG) + { + debug(String.valueOf(list)); + } + if (list != null) + { + files.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (DEBUG) + { + debug("l=" + l); + } + if (l.size() != 4) + { + if (DEBUG) + { + debug("file list too small: " + l.size()); + } + throw new IllegalArgumentException("invalid file list"); + } + Double quality = (Double) l.get(0); + Integer offset = (Integer) l.get(1); + Integer length = (Integer) l.get(2); + String source = (String) l.get(3); + files.add(new SimpleList(quality, offset, length, source)); + } + } + } + catch (ClassCastException cce) + { + if (DEBUG) + { + debug("bad file list: " + cce.getMessage()); + cce.printStackTrace(); + } + throw new IllegalArgumentException("invalid file list"); + } + + try + { + list = (List) attrib.get(URL_SOURCES); + if (DEBUG) + { + debug(String.valueOf(list)); + } + if (list != null) + { + urls.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (DEBUG) + { + debug("l=" + l); + } + if (l.size() != 4) + { + if (DEBUG) + { + debug("URL list too small: " + l.size()); + } + throw new IllegalArgumentException("invalid URL list"); + } + Double quality = (Double) l.get(0); + Integer offset = (Integer) l.get(1); + Integer length = (Integer) l.get(2); + URL source = (URL) l.get(3); + urls.add(new SimpleList(quality, offset, length, source)); + } + } + } + catch (ClassCastException cce) + { + if (DEBUG) + { + debug("bad URL list: " + cce.getMessage()); + cce.printStackTrace(); + } + throw new IllegalArgumentException("invalid URL list"); + } + + try + { + list = (List) attrib.get(PROGRAM_SOURCES); + if (DEBUG) + { + debug(String.valueOf(list)); + } + if (list != null) + { + progs.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (DEBUG) + { + debug("l=" + l); + } + if (l.size() != 4) + { + if (DEBUG) + { + debug("program list too small: " + l.size()); + } + throw new IllegalArgumentException("invalid program list"); + } + Double quality = (Double) l.get(0); + Integer offset = (Integer) l.get(1); + Integer length = (Integer) l.get(2); + String source = (String) l.get(3); + progs.add(new SimpleList(quality, offset, length, source)); + } + } + } + catch (ClassCastException cce) + { + if (DEBUG) + { + debug("bad program list: " + cce.getMessage()); + cce.printStackTrace(); + } + throw new IllegalArgumentException("invalid program list"); + } + + try + { + list = (List) attrib.get(OTHER_SOURCES); + if (DEBUG) + { + debug(String.valueOf(list)); + } + if (list != null) + { + other.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + EntropySource src = (EntropySource) it.next(); + if (DEBUG) + { + debug("src=" + src); + } + if (src == null) + { + throw new NullPointerException("null source in source list"); + } + other.add(src); + } + } + } + catch (ClassCastException cce) + { + throw new IllegalArgumentException("invalid source list"); + } + + try + { + Boolean block = (Boolean) attrib.get(BLOCKING); + if (block != null) + { + blocking = block.booleanValue(); + } + else + { + blocking = true; + } + } + catch (ClassCastException cce) + { + throw new IllegalArgumentException("invalid blocking parameter"); + } + + poller = new Poller(files, urls, progs, other, this); + try + { + fillBlock(); + } + catch (LimitReachedException lre) + { + throw new RuntimeException("bootstrapping CSPRNG failed"); + } + } + + public void fillBlock() throws LimitReachedException + { + if (DEBUG) + { + debug("fillBlock"); + } + if (getQuality() < 100.0) + { + if (DEBUG) + { + debug("doing slow poll"); + } + slowPoll(); + } + + do + { + fastPoll(); + mixRandomPool(); + } + while (mixCount < MIX_COUNT); + + if (!x917init || x917count >= X917_LIFETIME) + { + mixRandomPool(pool); + Map attr = new HashMap(); + byte[] key = new byte[32]; + System.arraycopy(pool, 0, key, 0, 32); + cipher.reset(); + attr.put(IBlockCipher.KEY_MATERIAL, key); + try + { + cipher.init(attr); + } + catch (InvalidKeyException ike) + { + throw new Error(ike.toString()); + } + + mixRandomPool(pool); + generateX917(pool); + mixRandomPool(pool); + generateX917(pool); + + if (x917init) + { + quality = 0.0; + } + x917init = true; + x917count = 0; + } + + byte[] export = new byte[ALLOC_SIZE]; + for (int i = 0; i < ALLOC_SIZE; i++) + { + export[i] = (byte) (pool[i] ^ 0xFF); + } + + mixRandomPool(); + mixRandomPool(export); + + generateX917(export); + + for (int i = 0; i < OUTPUT_SIZE; i++) + { + buffer[i] = (byte) (export[i] ^ export[i + OUTPUT_SIZE]); + } + Arrays.fill(export, (byte) 0); + } + + /** + * Add an array of bytes into the randomness pool. Note that this method + * will not increment the pool's quality counter (this can only be + * done via a source provided to the setup method). + * + * @param buf The byte array. + * @param off The offset from whence to start reading bytes. + * @param len The number of bytes to add. + * @throws ArrayIndexOutOfBoundsException If off or len are + * out of the range of buf. + */ + public synchronized void addRandomBytes(byte[] buf, int off, int len) + { + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + if (DEBUG) + { + debug("adding random bytes:"); + debug(Util.toString(buf, off, len)); + } + final int count = off + len; + for (int i = off; i < count; i++) + { + pool[index++] ^= buf[i]; + if (index == pool.length) + { + mixRandomPool(); + index = 0; + } + } + } + + /** + * Add a single random byte to the randomness pool. Note that this method + * will not increment the pool's quality counter (this can only be + * done via a source provided to the setup method). + * + * @param b The byte to add. + */ + public synchronized void addRandomByte(byte b) + { + if (DEBUG) + { + debug("adding byte " + Integer.toHexString(b)); + } + pool[index++] ^= b; + if (index >= pool.length) + { + mixRandomPool(); + index = 0; + } + } + + // Package methods. + // ------------------------------------------------------------------------- + + synchronized void addQuality(double quality) + { + if (DEBUG) + { + debug("adding quality " + quality); + } + if (this.quality < 100) + { + this.quality += quality; + } + if (DEBUG) + { + debug("quality now " + this.quality); + } + } + + synchronized double getQuality() + { + return quality; + } + + // Own methods. + // ------------------------------------------------------------------------- + + /** + * The mix operation. This method will, for every 20-byte block in the + * random pool, hash that block, the previous 20 bytes, and the next + * 44 bytes with SHA-1, writing the result back into that block. + */ + private void mixRandomPool(byte[] buf) + { + int hashSize = hash.hashSize(); + for (int i = 0; i < buf.length; i += hashSize) + { + // First update the bytes [p-19..p-1]. + if (i == 0) + { + hash.update(buf, buf.length - hashSize, hashSize); + } + else + { + hash.update(buf, i - hashSize, hashSize); + } + + // Now the next 64 bytes. + if (i + 64 < buf.length) + { + hash.update(buf, i, 64); + } + else + { + hash.update(buf, i, buf.length - i); + hash.update(buf, 0, 64 - (buf.length - i)); + } + + byte[] digest = hash.digest(); + System.arraycopy(digest, 0, buf, i, hashSize); + } + } + + private void mixRandomPool() + { + mixRandomPool(pool); + mixCount++; + } + + private void generateX917(byte[] buf) + { + int off = 0; + for (int i = 0; i < buf.length; i += X917_POOL_SIZE) + { + int copy = Math.min(buf.length - i, X917_POOL_SIZE); + for (int j = 0; j < copy; j++) + { + x917pool[j] ^= pool[off + j]; + } + + cipher.encryptBlock(x917pool, 0, x917pool, 0); + System.arraycopy(x917pool, 0, buf, off, copy); + cipher.encryptBlock(x917pool, 0, x917pool, 0); + + off += copy; + x917count++; + } + } + + /** + * Add random data always immediately available into the random pool, such + * as the values of the eight asynchronous counters, the current time, the + * current memory usage, the calling thread name, and the current stack + * trace. + * + *

This method does not alter the quality counter, and is provided more + * to maintain randomness, not to seriously improve the current random + * state. + */ + private void fastPoll() + { + byte b = 0; + for (int i = 0; i < SPINNER_COUNT; i++) + b ^= SPINNERS[i].counter; + addRandomByte(b); + addRandomByte((byte) System.currentTimeMillis()); + addRandomByte((byte) Runtime.getRuntime().freeMemory()); + + String s = Thread.currentThread().getName(); + if (s != null) + { + byte[] buf = s.getBytes(); + addRandomBytes(buf, 0, buf.length); + } + + ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); + PrintStream pout = new PrintStream(bout); + Throwable t = new Throwable(); + t.printStackTrace(pout); + pout.flush(); + byte[] buf = bout.toByteArray(); + addRandomBytes(buf, 0, buf.length); + } + + private void slowPoll() throws LimitReachedException + { + if (DEBUG) + { + debug("poller is alive? " + + (pollerThread == null ? false : pollerThread.isAlive())); + } + if (pollerThread == null || !pollerThread.isAlive()) + { + boolean interrupted = false; + pollerThread = new Thread(poller); + pollerThread.setDaemon(true); + pollerThread.setPriority(Thread.NORM_PRIORITY - 1); + pollerThread.start(); + if (blocking) + { + try + { + pollerThread.join(); + } + catch (InterruptedException ie) + { + interrupted = true; + } + } + + // If the full slow poll has completed after we waited for it, + // and there in insufficient randomness, throw an exception. + if (!interrupted && blocking && quality < 100.0) + { + if (DEBUG) + { + debug("insufficient quality: " + quality); + } + throw new LimitReachedException( + "insufficient randomness was polled"); + } + } + } + + protected void finalize() throws Throwable + { + if (poller != null && pollerThread != null && pollerThread.isAlive()) + { + pollerThread.interrupt(); + poller.stopUpdating(); + pollerThread.interrupt(); + } + Arrays.fill(pool, (byte) 0); + Arrays.fill(x917pool, (byte) 0); + Arrays.fill(buffer, (byte) 0); + } + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * A simple thread that constantly updates a byte counter. This class is + * used in a group of lowest-priority threads and the values of their + * counters (updated in competition with all other threads) is used as a + * source of entropy bits. + */ + private static class Spinner implements Runnable + { + + // Field. + // ----------------------------------------------------------------------- + + private byte counter; + + // Constructor. + // ----------------------------------------------------------------------- + + private Spinner() + { + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public void run() + { + while (true) + { + counter++; + try + { + Thread.sleep(100); + } + catch (InterruptedException ie) + { + } + } + } + } + + private final class Poller implements Runnable + { + + // Fields. + // ----------------------------------------------------------------------- + + private final List files; + + private final List urls; + + private final List progs; + + private final List other; + + private final CSPRNG pool; + + private boolean running; + + // Constructor. + // ----------------------------------------------------------------------- + + Poller(List files, List urls, List progs, List other, CSPRNG pool) + { + super(); + this.files = Collections.unmodifiableList(files); + this.urls = Collections.unmodifiableList(urls); + this.progs = Collections.unmodifiableList(progs); + this.other = Collections.unmodifiableList(other); + this.pool = pool; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public void run() + { + running = true; + if (DEBUG) + { + debug("files: " + files); + debug("URLs: " + urls); + debug("progs: " + progs); + } + Iterator files_it = files.iterator(); + Iterator urls_it = urls.iterator(); + Iterator prog_it = progs.iterator(); + Iterator other_it = other.iterator(); + + while (files_it.hasNext() || urls_it.hasNext() || prog_it.hasNext() + || other_it.hasNext()) + { + + // There is enough random data. Go away. + if (pool.getQuality() >= 100.0 || !running) + { + return; + } + + if (files_it.hasNext()) + { + try + { + List l = (List) files_it.next(); + if (DEBUG) + { + debug(l.toString()); + } + double qual = ((Double) l.get(0)).doubleValue(); + int offset = ((Integer) l.get(1)).intValue(); + int count = ((Integer) l.get(2)).intValue(); + String src = (String) l.get(3); + InputStream in = new FileInputStream(src); + byte[] buf = new byte[count]; + if (offset > 0) + { + in.skip(offset); + } + int len = in.read(buf); + if (len >= 0) + { + pool.addRandomBytes(buf, 0, len); + pool.addQuality(qual * ((double) len / (double) count)); + } + if (DEBUG) + { + debug("got " + len + " bytes from " + src); + } + } + catch (Exception x) + { + if (DEBUG) + { + debug(x.toString()); + x.printStackTrace(); + } + } + } + + if (pool.getQuality() >= 100.0 || !running) + { + return; + } + + if (urls_it.hasNext()) + { + try + { + List l = (List) urls_it.next(); + if (DEBUG) + { + debug(l.toString()); + } + double qual = ((Double) l.get(0)).doubleValue(); + int offset = ((Integer) l.get(1)).intValue(); + int count = ((Integer) l.get(2)).intValue(); + URL src = (URL) l.get(3); + InputStream in = src.openStream(); + byte[] buf = new byte[count]; + if (offset > 0) + { + in.skip(offset); + } + int len = in.read(buf); + if (len >= 0) + { + pool.addRandomBytes(buf, 0, len); + pool.addQuality(qual * ((double) len / (double) count)); + } + if (DEBUG) + { + debug("got " + len + " bytes from " + src); + } + } + catch (Exception x) + { + if (DEBUG) + { + debug(x.toString()); + x.printStackTrace(); + } + } + } + + if (pool.getQuality() >= 100.0 || !running) + { + return; + } + + Process proc = null; + if (prog_it.hasNext()) + { + try + { + List l = (List) prog_it.next(); + if (DEBUG) + { + debug(l.toString()); + } + double qual = ((Double) l.get(0)).doubleValue(); + int offset = ((Integer) l.get(1)).intValue(); + int count = ((Integer) l.get(2)).intValue(); + String src = (String) l.get(3); + proc = null; + proc = Runtime.getRuntime().exec(src); + InputStream in = proc.getInputStream(); + byte[] buf = new byte[count]; + if (offset > 0) + { + in.skip(offset); + } + int len = in.read(buf); + if (len >= 0) + { + pool.addRandomBytes(buf, 0, len); + pool.addQuality(qual * ((double) len / (double) count)); + } + proc.destroy(); + proc.waitFor(); + if (DEBUG) + { + debug("got " + len + " bytes from " + src); + } + } + catch (Exception x) + { + if (DEBUG) + { + debug(x.toString()); + x.printStackTrace(); + } + try + { + if (proc != null) + { + proc.destroy(); + proc.waitFor(); + } + } + catch (Exception ignored) + { + } + } + } + + if (pool.getQuality() >= 100.0 || !running) + { + return; + } + + if (other_it.hasNext()) + { + try + { + EntropySource src = (EntropySource) other_it.next(); + byte[] buf = src.nextBytes(); + if (pool == null) + { + return; + } + pool.addRandomBytes(buf, 0, buf.length); + pool.addQuality(src.quality()); + if (DEBUG) + { + debug("got " + buf.length + " bytes from " + src); + } + } + catch (Exception x) + { + if (DEBUG) + { + debug(x.toString()); + x.printStackTrace(); + } + } + } + } + } + + public void stopUpdating() + { + running = false; + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/prng/Fortuna.java b/gnu/javax/crypto/prng/Fortuna.java new file mode 100644 index 000000000..6453a9d02 --- /dev/null +++ b/gnu/javax/crypto/prng/Fortuna.java @@ -0,0 +1,366 @@ +/* Fortuna.java -- The Fortuna PRNG. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.prng.RandomEvent; +import gnu.java.security.prng.RandomEventListener; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import java.security.InvalidKeyException; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; + +/** + * The Fortuna continuously-seeded pseudo-random number generator. This + * generator is composed of two major pieces: the entropy accumulator + * and the generator function. The former takes in random bits and + * incorporates them into the generator's state. The latter takes this + * base entropy and generates pseudo-random bits from it. + * + *

There are some things users of this class must be aware of: + * + *

+ *
Adding Random Data
+ *
This class does not do any polling of random sources, but rather + * provides an interface for adding random events. Applications that use + * this code must provide this mechanism. We use this design + * because an application writer who knows the system he is targeting + * is in a better position to judge what random data is available.
+ * + *
Storing the Seed
+ *
This class implements {@link Serializable} in such a way that it + * writes a 64 byte seed to the stream, and reads it back again when being + * deserialized. This is the extent of seed file management, however, and + * those using this class are encouraged to think deeply about when, how + * often, and where to store the seed.
+ *
+ * + *

References:

+ * + *
    + *
  • Niels Ferguson and Bruce Schneier, Practical Cryptography, + * pp. 155--184. Wiley Publishing, Indianapolis. (2003 Niels Ferguson and + * Bruce Schneier). ISBN 0-471-22357-3.
  • + *
+ */ +public class Fortuna extends BasePRNG implements Serializable, + RandomEventListener +{ + + private static final long serialVersionUID = 0xFACADE; + + private static final int SEED_FILE_SIZE = 64; + + private static final int NUM_POOLS = 32; + + private static final int MIN_POOL_SIZE = 64; + + private final Generator generator; + + private final IMessageDigest[] pools; + + private long lastReseed; + + private int pool; + + private int pool0Count; + + private int reseedCount; + + public static final String SEED = "gnu.crypto.prng.fortuna.seed"; + + public Fortuna() + { + super(Registry.FORTUNA_PRNG); + generator = new Generator( + CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER), + HashFactory.getInstance(Registry.SHA256_HASH)); + pools = new IMessageDigest[NUM_POOLS]; + for (int i = 0; i < NUM_POOLS; i++) + pools[i] = HashFactory.getInstance(Registry.SHA256_HASH); + lastReseed = 0; + pool = 0; + pool0Count = 0; + buffer = new byte[256]; + } + + public void setup(Map attributes) + { + lastReseed = 0; + reseedCount = 0; + pool = 0; + pool0Count = 0; + generator.init(attributes); + } + + public void fillBlock() throws LimitReachedException + { + if (pool0Count >= MIN_POOL_SIZE + && System.currentTimeMillis() - lastReseed > 100) + { + reseedCount++; + byte[] seed = new byte[0]; + for (int i = 0; i < NUM_POOLS; i++) + { + if (reseedCount % (1 << i) == 0) + generator.addRandomBytes(pools[i].digest()); + } + lastReseed = System.currentTimeMillis(); + pool0Count = 0; + } + generator.nextBytes(buffer); + } + + public void addRandomByte(byte b) + { + pools[pool].update(b); + if (pool == 0) + pool0Count++; + pool = (pool + 1) % NUM_POOLS; + } + + public void addRandomBytes(byte[] buf, int offset, int length) + { + pools[pool].update(buf, offset, length); + if (pool == 0) + pool0Count += length; + pool = (pool + 1) % NUM_POOLS; + } + + public void addRandomEvent(RandomEvent event) + { + if (event.getPoolNumber() < 0 || event.getPoolNumber() >= pools.length) + throw new IllegalArgumentException("pool number out of range: " + + event.getPoolNumber()); + pools[event.getPoolNumber()].update(event.getSourceNumber()); + pools[event.getPoolNumber()].update((byte) event.getData().length); + pools[event.getPoolNumber()].update(event.getData()); + if (event.getPoolNumber() == 0) + pool0Count += event.getData().length; + } + + // Reading and writing this object is equivalent to storing and retrieving + // the seed. + + private void writeObject(ObjectOutputStream out) throws IOException + { + byte[] seed = new byte[SEED_FILE_SIZE]; + try + { + generator.nextBytes(seed); + } + catch (LimitReachedException shouldNeverHappen) + { + throw new Error(shouldNeverHappen); + } + out.write(seed); + } + + private void readObject(ObjectInputStream in) throws IOException + { + byte[] seed = new byte[SEED_FILE_SIZE]; + in.readFully(seed); + generator.addRandomBytes(seed); + } + + /** + * The Fortuna generator function. The generator is a PRNG in its own + * right; Fortuna itself is basically a wrapper around this generator + * that manages reseeding in a secure way. + */ + public static class Generator extends BasePRNG implements Cloneable + { + + private static final int LIMIT = 1 << 20; + + private final IBlockCipher cipher; + + private final IMessageDigest hash; + + private final byte[] counter; + + private final byte[] key; + + private boolean seeded; + + public Generator(final IBlockCipher cipher, final IMessageDigest hash) + { + super(Registry.FORTUNA_GENERATOR_PRNG); + this.cipher = cipher; + this.hash = hash; + counter = new byte[cipher.defaultBlockSize()]; + buffer = new byte[cipher.defaultBlockSize()]; + int keysize = 0; + for (Iterator it = cipher.keySizes(); it.hasNext();) + { + int ks = ((Integer) it.next()).intValue(); + if (ks > keysize) + keysize = ks; + if (keysize >= 32) + break; + } + key = new byte[keysize]; + } + + public byte nextByte() + { + byte[] b = new byte[1]; + nextBytes(b, 0, 1); + return b[0]; + } + + public void nextBytes(byte[] out, int offset, int length) + { + if (!seeded) + throw new IllegalStateException("generator not seeded"); + + int count = 0; + do + { + int amount = Math.min(LIMIT, length - count); + try + { + super.nextBytes(out, offset + count, amount); + } + catch (LimitReachedException shouldNeverHappen) + { + throw new Error(shouldNeverHappen); + } + count += amount; + + for (int i = 0; i < key.length; i += counter.length) + { + fillBlock(); + int l = Math.min(key.length - i, cipher.currentBlockSize()); + System.arraycopy(buffer, 0, key, i, l); + } + resetKey(); + } + while (count < length); + fillBlock(); + ndx = 0; + } + + public void addRandomByte(byte b) + { + addRandomBytes(new byte[] { b }); + } + + public void addRandomBytes(byte[] seed, int offset, int length) + { + hash.update(key); + hash.update(seed, offset, length); + byte[] newkey = hash.digest(); + System.arraycopy(newkey, 0, key, 0, Math.min(key.length, newkey.length)); + resetKey(); + incrementCounter(); + seeded = true; + } + + public void fillBlock() + { + if (!seeded) + throw new IllegalStateException("generator not seeded"); + cipher.encryptBlock(counter, 0, buffer, 0); + incrementCounter(); + } + + public void setup(Map attributes) + { + seeded = false; + Arrays.fill(key, (byte) 0); + Arrays.fill(counter, (byte) 0); + byte[] seed = (byte[]) attributes.get(SEED); + if (seed != null) + addRandomBytes(seed); + } + + /** + * Resets the cipher's key. This is done after every reseed, which + * combines the old key and the seed, and processes that throigh the + * hash function. + */ + private void resetKey() + { + try + { + cipher.reset(); + cipher.init(Collections.singletonMap(IBlockCipher.KEY_MATERIAL, key)); + } + // We expect to never get an exception here. + catch (InvalidKeyException ike) + { + throw new Error(ike); + } + catch (IllegalArgumentException iae) + { + throw new Error(iae); + } + } + + /** + * Increment `counter' as a sixteen-byte little-endian unsigned integer + * by one. + */ + private void incrementCounter() + { + for (int i = 0; i < counter.length; i++) + { + counter[i]++; + if (counter[i] != 0) + break; + } + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/prng/ICMGenerator.java b/gnu/javax/crypto/prng/ICMGenerator.java new file mode 100644 index 000000000..541003a97 --- /dev/null +++ b/gnu/javax/crypto/prng/ICMGenerator.java @@ -0,0 +1,379 @@ +/* ICMGenerator.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; + +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.cipher.CipherFactory; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +/** + *

Counter Mode is a way to define a pseudorandom keystream generator using + * a block cipher. The keystream can be used for additive encryption, key + * derivation, or any other application requiring pseudorandom data.

+ * + *

In ICM, the keystream is logically broken into segments. Each segment is + * identified with a segment index, and the segments have equal lengths. This + * segmentation makes ICM especially appropriate for securing packet-based + * protocols.

+ * + *

This implementation adheres to the definition of the ICM keystream + * generation function that allows for any symetric key block cipher algorithm + * (initialisation parameter gnu.crypto.prng.icm.cipher.name taken + * to be an instance of {@link java.lang.String}) to be used. If such a + * parameter is not defined/included in the initialisation Map, + * then the "Rijndael" algorithm is used. Furthermore, if the initialisation + * parameter gnu.crypto.cipher.block.size (taken to be a instance + * of {@link java.lang.Integer}) is missing or undefined in the initialisation + * Map, then the cipher's default block size is used.

+ * + *

The practical limits and constraints of such generator are:

+ *
    + *
  • The number of blocks in any segment MUST NOT exceed + * 256 ** BLOCK_INDEX_LENGTH. The number of segments MUST NOT + * exceed 256 ** SEGMENT_INDEX_LENGTH. These restrictions ensure + * the uniqueness of each block cipher input.
  • + * + *
  • Each segment contains SEGMENT_LENGTH octets; this value + * MUST NOT exceed the value (256 ** BLOCK_INDEX_LENGTH) * + * BLOCK_LENGTH.
  • + * + *
  • The sum of SEGMENT_INDEX_LENGTH and + * BLOCK_INDEX_LENGTH MUST NOT exceed BLOCK_LENGTH + * / 2. This requirement protects the ICM keystream generator from + * potentially failing to be pseudorandom.
  • + *
+ * + *

NOTE: Rijndael is used as the default symmetric key block cipher + * algorithm because, with its default block and key sizes, it is the AES. Yet + * being Rijndael, the algorithm offers more versatile block and key sizes which + * may prove to be useful for generating longer key streams.

+ * + *

References:

+ * + *
    + *
  1. + * Integer Counter Mode, David A. McGrew.
  2. + *
+ * + * @version $Revision: 1.1.4.1 $ + */ +public class ICMGenerator extends BasePRNG implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Property name of underlying block cipher for this ICM generator. */ + public static final String CIPHER = "gnu.crypto.prng.icm.cipher.name"; + + /** Property name of ICM's block index length. */ + public static final String BLOCK_INDEX_LENGTH = "gnu.crypto.prng.icm.block.index.length"; + + /** Property name of ICM's segment index length. */ + public static final String SEGMENT_INDEX_LENGTH = "gnu.crypto.prng.icm.segment.index.length"; + + /** Property name of ICM's offset. */ + public static final String OFFSET = "gnu.crypto.prng.icm.offset"; + + /** Property name of ICM's segment index. */ + public static final String SEGMENT_INDEX = "gnu.crypto.prng.icm.segment.index"; + + /** The integer value 256 as a BigInteger. */ + private static final BigInteger TWO_FIFTY_SIX = new BigInteger("256"); + + /** The underlying cipher implementation. */ + private IBlockCipher cipher; + + /** This keystream block index length in bytes. */ + private int blockNdxLength = -1; + + /** This keystream segment index length in bytes. */ + private int segmentNdxLength = -1; + + /** The index of the next block for a given keystream segment. */ + private BigInteger blockNdx = BigInteger.ZERO; + + /** The segment index for this keystream. */ + private BigInteger segmentNdx; + + /** The initial counter for a given keystream segment. */ + private BigInteger C0; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public ICMGenerator() + { + super(Registry.ICM_PRNG); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BasePRNG -------------------------- + + // Conceptually, ICM is a keystream generator that takes a secret key + // and a segment index as an input and then outputs a keystream + // segment. The segmentation lends itself to packet encryption, as + // each keystream segment can be used to encrypt a distinct packet. + // + // An ICM key consists of the block cipher key and an Offset. The + // Offset is an integer with BLOCK_LENGTH octets... + // + public void setup(Map attributes) + { + // find out which cipher algorithm to use + boolean newCipher = true; + String underlyingCipher = (String) attributes.get(CIPHER); + if (underlyingCipher == null) + { + if (cipher == null) + { // happy birthday + // ensure we have a reliable implementation of this cipher + cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER); + } + else + { // we already have one. use it as is + newCipher = false; + } + } + else + { // ensure we have a reliable implementation of this cipher + cipher = CipherFactory.getInstance(underlyingCipher); + } + + // find out what block size we should use it in + int cipherBlockSize = 0; + Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE); + if (bs != null) + { + cipherBlockSize = bs.intValue(); + } + else + { + if (newCipher) + { // assume we'll use its default block size + cipherBlockSize = cipher.defaultBlockSize(); + } // else use as is + } + + // get the key material + byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL); + if (key == null) + { + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + } + + // now initialise the cipher + HashMap map = new HashMap(); + if (cipherBlockSize != 0) + { // only needed if new or changed + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(cipherBlockSize)); + } + map.put(IBlockCipher.KEY_MATERIAL, key); + try + { + cipher.init(map); + } + catch (InvalidKeyException x) + { + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + } + + // at this point we have an initialised (new or otherwise) cipher + // ensure that remaining params make sense + + cipherBlockSize = cipher.currentBlockSize(); + BigInteger counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize); + + // offset, like the underlying cipher key is not cloneable + // always look for it and throw an exception if it's not there + Object obj = attributes.get(OFFSET); + // allow either a byte[] or a BigInteger + BigInteger r; + if (obj instanceof BigInteger) + { + r = (BigInteger) obj; + } + else + { // assume byte[]. should be same length as cipher block size + byte[] offset = (byte[]) obj; + if (offset.length != cipherBlockSize) + { + throw new IllegalArgumentException(OFFSET); + } + + r = new BigInteger(1, offset); + } + + int wantBlockNdxLength = -1; // number of octets in the block index + Integer i = (Integer) attributes.get(BLOCK_INDEX_LENGTH); + if (i != null) + { + wantBlockNdxLength = i.intValue(); + if (wantBlockNdxLength < 1) + { + throw new IllegalArgumentException(BLOCK_INDEX_LENGTH); + } + } + + int wantSegmentNdxLength = -1; // number of octets in the segment index + i = (Integer) attributes.get(SEGMENT_INDEX_LENGTH); + if (i != null) + { + wantSegmentNdxLength = i.intValue(); + if (wantSegmentNdxLength < 1) + { + throw new IllegalArgumentException(SEGMENT_INDEX_LENGTH); + } + } + + // if both are undefined check if it's a reuse + if ((wantBlockNdxLength == -1) && (wantSegmentNdxLength == -1)) + { + if (blockNdxLength == -1) + { // new instance + throw new IllegalArgumentException(BLOCK_INDEX_LENGTH + ", " + + SEGMENT_INDEX_LENGTH); + } // else reuse old values + } + else + { // only one is undefined, set it to BLOCK_LENGTH/2 minus the other + int limit = cipherBlockSize / 2; + if (wantBlockNdxLength == -1) + { + wantBlockNdxLength = limit - wantSegmentNdxLength; + } + else if (wantSegmentNdxLength == -1) + { + wantSegmentNdxLength = limit - wantBlockNdxLength; + } + else if ((wantSegmentNdxLength + wantBlockNdxLength) > limit) + { + throw new IllegalArgumentException(BLOCK_INDEX_LENGTH + ", " + + SEGMENT_INDEX_LENGTH); + } + // save new values + blockNdxLength = wantBlockNdxLength; + segmentNdxLength = wantSegmentNdxLength; + } + + // get the segment index as a BigInteger + BigInteger s = (BigInteger) attributes.get(SEGMENT_INDEX); + if (s == null) + { + if (segmentNdx == null) + { // segment index was never set + throw new IllegalArgumentException(SEGMENT_INDEX); + } + // reuse; check if still valid + if (segmentNdx.compareTo(TWO_FIFTY_SIX.pow(segmentNdxLength)) > 0) + { + throw new IllegalArgumentException(SEGMENT_INDEX); + } + } + else + { + if (s.compareTo(TWO_FIFTY_SIX.pow(segmentNdxLength)) > 0) + { + throw new IllegalArgumentException(SEGMENT_INDEX); + } + segmentNdx = s; + } + + // The initial counter of the keystream segment with segment index s is + // defined as follows, where r denotes the Offset: + // + // C[0] = (s * (256^BLOCK_INDEX_LENGTH) + r) modulo (256^BLOCK_LENGTH) + // + C0 = segmentNdx.multiply(TWO_FIFTY_SIX.pow(blockNdxLength)).add(r).modPow( + BigInteger.ONE, + counterRange); + } + + public void fillBlock() throws LimitReachedException + { + if (C0 == null) + { + throw new IllegalStateException(); + } + if (blockNdx.compareTo(TWO_FIFTY_SIX.pow(blockNdxLength)) >= 0) + { + throw new LimitReachedException(); + } + + int cipherBlockSize = cipher.currentBlockSize(); + BigInteger counterRange = TWO_FIFTY_SIX.pow(cipherBlockSize); + + // encrypt the counter for the current blockNdx + // C[i] = (C[0] + i) modulo (256^BLOCK_LENGTH). + + BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange); + buffer = Ci.toByteArray(); + int limit = buffer.length; + if (limit < cipherBlockSize) + { + byte[] data = new byte[cipherBlockSize]; + System.arraycopy(buffer, 0, data, cipherBlockSize - limit, limit); + buffer = data; + } + else if (limit > cipherBlockSize) + { + byte[] data = new byte[cipherBlockSize]; + System.arraycopy(buffer, limit - cipherBlockSize, data, 0, + cipherBlockSize); + buffer = data; + } + + cipher.encryptBlock(buffer, 0, buffer, 0); + blockNdx = blockNdx.add(BigInteger.ONE); // increment blockNdx + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/prng/IPBE.java b/gnu/javax/crypto/prng/IPBE.java new file mode 100644 index 000000000..69ff493fb --- /dev/null +++ b/gnu/javax/crypto/prng/IPBE.java @@ -0,0 +1,69 @@ +/* IPBE.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +/** + *

Trivial interface to group Password-based encryption property names.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public interface IPBE +{ + + // Constants + // ------------------------------------------------------------------------- + + /** + * Property name for the iteration count in a PBE algorithm. The property + * associated with this is expected to be an {@link Integer}. + */ + public static final String ITERATION_COUNT = "gnu.crypto.pbe.iteration.count"; + + /** + * Property name for the password in a PBE algorithm. The property associated + * with this is expected to be a char array. + */ + public static final String PASSWORD = "gnu.crypto.pbe.password"; + + /** + * Property name for the salt in a PBE algorithm. The property associated + * with this is expected to be a byte array. + */ + public static final String SALT = "gnu.crypto.pbe.salt"; +} \ No newline at end of file diff --git a/gnu/javax/crypto/prng/PBKDF2.java b/gnu/javax/crypto/prng/PBKDF2.java new file mode 100644 index 000000000..87bbd1e89 --- /dev/null +++ b/gnu/javax/crypto/prng/PBKDF2.java @@ -0,0 +1,216 @@ +/* PBKDF2.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.mac.HMac; +import gnu.javax.crypto.mac.IMac; + +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + *

An implementation of the key derivation function KDF2 from PKCS #5: + * Password-Based Cryptography (PBE). This KDF is essentially a way to + * transform a password and a salt into a stream of random bytes, which may then + * be used to initialize a cipher or a MAC.

+ * + *

This version uses a MAC as its pseudo-random function, and the password is + * used as the key.

+ * + *

References:

+ *
    + *
  1. B. Kaliski, RFC 2898: + * Password-Based Cryptography Specification, Version 2.0
  2. + *
+ * + * @version $Revision: 1.1.4.1 $ + */ +public class PBKDF2 extends BasePRNG implements Cloneable +{ + + // Contstants and variables + // ------------------------------------------------------------------------- + + /** + * The bytes fed into the MAC. This is initially the concatenation of the + * salt and the block number. + */ + private byte[] in; + + /** The iteration count. */ + private int iterationCount; + + /** The salt. */ + private byte[] salt; + + /** The MAC (the pseudo-random function we use). */ + private IMac mac; + + /** The number of hLen-sized blocks generated. */ + private long count; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Creates a new PBKDF2 object. The argument is the MAC that will serve as + * the pseudo-random function. The MAC does not need to be initialized.

+ * + * @param mac The pseudo-random function. + */ + public PBKDF2(IMac mac) + { + super("PBKDF2-" + mac.name()); + this.mac = mac; + iterationCount = -1; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public void setup(Map attributes) + { + Map macAttrib = new HashMap(); + macAttrib.put(HMac.USE_WITH_PKCS5_V2, Boolean.TRUE); + + byte[] s = (byte[]) attributes.get(IPBE.SALT); + if (s == null) + { + if (salt == null) + { + throw new IllegalArgumentException("no salt specified"); + } // Otherwise re-use. + } + else + { + salt = s; + } + + char[] password = (char[]) attributes.get(IPBE.PASSWORD); + if (password != null) + { + try + { + macAttrib.put(IMac.MAC_KEY_MATERIAL, + new String(password).getBytes("UTF-8")); + } + catch (UnsupportedEncodingException uee) + { + throw new Error(uee.getMessage()); + } + } + else if (!initialised) + { + throw new IllegalArgumentException("no password specified"); + } // otherwise re-use previous password. + + try + { + mac.init(macAttrib); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.getMessage()); + } + + Integer ic = (Integer) attributes.get(IPBE.ITERATION_COUNT); + if (ic != null) + { + iterationCount = ic.intValue(); + } + if (iterationCount <= 0) + { + throw new IllegalArgumentException("bad iteration count"); + } + + count = 0L; + buffer = new byte[mac.macSize()]; + try + { + fillBlock(); + // } catch (Exception x) { + } + catch (LimitReachedException x) + { + // x.printStackTrace(System.err); + throw new Error(x.getMessage()); + } + } + + public void fillBlock() throws LimitReachedException + { + if (++count > ((1L << 32) - 1)) + { + throw new LimitReachedException(); + } + // for (int i = 0; i < buffer.length; i++) { + // buffer[i] = 0; + // } + Arrays.fill(buffer, (byte) 0x00); + int limit = salt.length; + // in = new byte[salt.length + 4]; + in = new byte[limit + 4]; + System.arraycopy(salt, 0, in, 0, salt.length); + // in[salt.length ] = (byte)(count >>> 24); + // in[salt.length+1] = (byte)(count >>> 16); + // in[salt.length+2] = (byte)(count >>> 8); + // in[salt.length+3] = (byte) count; + in[limit++] = (byte) (count >>> 24); + in[limit++] = (byte) (count >>> 16); + in[limit++] = (byte) (count >>> 8); + in[limit] = (byte) count; + for (int i = 0; i < iterationCount; i++) + { + mac.reset(); + mac.update(in, 0, in.length); + in = mac.digest(); + for (int j = 0; j < buffer.length; j++) + { + buffer[j] ^= in[j]; + } + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/prng/PRNGFactory.java b/gnu/javax/crypto/prng/PRNGFactory.java new file mode 100644 index 000000000..9ff6558b0 --- /dev/null +++ b/gnu/javax/crypto/prng/PRNGFactory.java @@ -0,0 +1,143 @@ +/* PRNGFactory.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; + + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.HMacFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + *

A Factory to instantiate pseudo random number generators.

+ */ +public class PRNGFactory implements Registry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private PRNGFactory() + { + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a padding algorithm given its name.

+ * + * @param prng the case-insensitive name of the PRNG. + * @return an instance of the pseudo-random number generator. + * @exception InternalError if the implementation does not pass its self- + * test. + */ + public static IRandom getInstance(String prng) + { + if (prng == null) + { + return null; + } + + prng = prng.trim(); + IRandom result = null; + if (prng.equalsIgnoreCase(ARCFOUR_PRNG) || prng.equalsIgnoreCase(RC4_PRNG)) + { + result = new ARCFour(); + } + else if (prng.equalsIgnoreCase(ICM_PRNG)) + { + result = new ICMGenerator(); + } + else if (prng.equalsIgnoreCase(UMAC_PRNG)) + { + result = new UMacGenerator(); + } + else if (prng.toLowerCase().startsWith(PBKDF2_PRNG_PREFIX)) + { + String macName = prng.substring(PBKDF2_PRNG_PREFIX.length()); + IMac mac = MacFactory.getInstance(macName); + if (mac == null) + { + return null; + } + result = new PBKDF2(mac); + } + + if (result != null) + return result; + + return gnu.java.security.prng.PRNGFactory.getInstance (prng); + } + + /** + *

Returns a {@link Set} of names of padding algorithms supported by this + * Factory.

+ * + * @return a {@link Set} of pseudo-random number generator algorithm names + * (Strings). + */ + public static Set getNames() + { + HashSet hs = new HashSet (gnu.java.security.prng.PRNGFactory.getNames ()); + hs.add(ICM_PRNG); + hs.add(UMAC_PRNG); + // add all hmac implementations as candidate PBKDF2 ones too + for (Iterator it = HMacFactory.getNames().iterator(); it.hasNext();) + { + hs.add(PBKDF2_PRNG_PREFIX + ((String) it.next())); + } + + return Collections.unmodifiableSet(hs); + } + + // Instance methods + // ------------------------------------------------------------------------- +} diff --git a/gnu/javax/crypto/prng/UMacGenerator.java b/gnu/javax/crypto/prng/UMacGenerator.java new file mode 100644 index 000000000..0e3725ce9 --- /dev/null +++ b/gnu/javax/crypto/prng/UMacGenerator.java @@ -0,0 +1,228 @@ +/* UMacGenerator.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.prng; + +import gnu.java.security.Registry; +import gnu.java.security.prng.BasePRNG; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.security.InvalidKeyException; + +/** + *

KDFs (Key Derivation Functions) are used to stretch user-supplied + * key material to specific size(s) required by high level cryptographic + * primitives. Described in the UMAC + * paper, this function basically operates an underlying symmetric key block + * cipher instance in output feedback mode (OFB), as a strong + * pseudo-random number generator.

+ * + *

UMacGenerator requires an index parameter + * (initialisation parameter gnu.crypto.prng.umac.kdf.index taken + * to be an instance of {@link java.lang.Integer} with a value between + * 0 and 255). Using the same key, but different + * indices, generates different pseudorandom outputs.

+ * + *

This implementation generalises the definition of the + * UmacGenerator algorithm to allow for other than the AES symetric + * key block cipher algorithm (initialisation parameter + * gnu.crypto.prng.umac.cipher.name taken to be an instance of + * {@link java.lang.String}). If such a parameter is not defined/included in the + * initialisation Map, then the "Rijndael" algorithm is used. + * Furthermore, if the initialisation parameter + * gnu.crypto.cipher.block.size (taken to be a instance of {@link + * java.lang.Integer}) is missing or undefined in the initialisation Map + * , then the cipher's default block size is used.

+ * + *

NOTE: Rijndael is used as the default symmetric key block cipher + * algorithm because, with its default block and key sizes, it is the AES. Yet + * being Rijndael, the algorithm offers more versatile block and key sizes which + * may prove to be useful for generating "longer" key streams.

+ * + *

References:

+ * + *
    + *
  1. + * UMAC: Message Authentication Code using Universal Hashing.
    + * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.
  2. + *
+ */ +public class UMacGenerator extends BasePRNG implements Cloneable +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + *

Property name of the KDF index value to use in this + * instance. The value is taken to be an {@link Integer} less than + * 256.

+ */ + public static final String INDEX = "gnu.crypto.prng.umac.index"; + + /** The name of the underlying symmetric key block cipher algorithm. */ + public static final String CIPHER = "gnu.crypto.prng.umac.cipher.name"; + + /** The generator's underlying block cipher. */ + private IBlockCipher cipher; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public UMacGenerator() + { + super(Registry.UMAC_PRNG); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Implementation of abstract methods in BasePRNG -------------------------- + + public void setup(Map attributes) + { + boolean newCipher = true; + String cipherName = (String) attributes.get(CIPHER); + if (cipherName == null) + { + if (cipher == null) + { // happy birthday + cipher = CipherFactory.getInstance(Registry.RIJNDAEL_CIPHER); + } + else + { // we already have one. use it as is + newCipher = false; + } + } + else + { + cipher = CipherFactory.getInstance(cipherName); + } + + // find out what block size we should use it in + int cipherBlockSize = 0; + Integer bs = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE); + if (bs != null) + { + cipherBlockSize = bs.intValue(); + } + else + { + if (newCipher) + { // assume we'll use its default block size + cipherBlockSize = cipher.defaultBlockSize(); + } // else use as is + } + + // get the key material + byte[] key = (byte[]) attributes.get(IBlockCipher.KEY_MATERIAL); + if (key == null) + { + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + } + + int keyLength = key.length; + // ensure that keyLength is valid for the chosen underlying cipher + boolean ok = false; + for (Iterator it = cipher.keySizes(); it.hasNext();) + { + ok = (keyLength == ((Integer) it.next()).intValue()); + if (ok) + { + break; + } + } + if (!ok) + { + throw new IllegalArgumentException("key length"); + } + + // ensure that remaining params make sense + int index = -1; + Integer i = (Integer) attributes.get(INDEX); + if (i != null) + { + index = i.intValue(); + if (index < 0 || index > 255) + { + throw new IllegalArgumentException(INDEX); + } + } + + // now initialise the underlying cipher + Map map = new HashMap(); + if (cipherBlockSize != 0) + { // only needed if new or changed + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(cipherBlockSize)); + } + map.put(IBlockCipher.KEY_MATERIAL, key); + try + { + cipher.init(map); + } + catch (InvalidKeyException x) + { + throw new IllegalArgumentException(IBlockCipher.KEY_MATERIAL); + } + + buffer = new byte[cipher.currentBlockSize()]; + buffer[cipher.currentBlockSize() - 1] = (byte) index; + try + { + fillBlock(); + } + catch (LimitReachedException impossible) + { + } + } + + public void fillBlock() throws LimitReachedException + { + cipher.encryptBlock(buffer, 0, buffer, 0); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/AuthInfo.java b/gnu/javax/crypto/sasl/AuthInfo.java new file mode 100644 index 000000000..1e942559d --- /dev/null +++ b/gnu/javax/crypto/sasl/AuthInfo.java @@ -0,0 +1,143 @@ +/* AuthInfo.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.StringTokenizer; + +/** + * A static class for creating {@link IAuthInfoProvider} providers. It + * transparently locates and uses any provider instances, based on the value + * assigned to the System property with the key + * gnu.crypto.sasl.auth.info.provider.pkgs. If more than one is + * specified they SHOULD be separated with a vertical bar character. Please note + * that the GNU provider is always added last to the list, disregarding whether + * it was mentioned or not in the value of that property, or if it that property + * was not defined. + */ +public class AuthInfo +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final ArrayList factories = new ArrayList(); + static + { + IAuthInfoProviderFactory ours = new AuthInfoProviderFactory(); + // if SASL_AUTH_INFO_PROVIDER_PKGS is defined then parse it + String clazz; + String pkgs = System.getProperty(Registry.SASL_AUTH_INFO_PROVIDER_PKGS, + null); + if (pkgs != null) + { + for (StringTokenizer st = new StringTokenizer(pkgs, "|"); st.hasMoreTokens();) + { + clazz = st.nextToken(); + if (!"gnu.crypto.sasl".equals(clazz)) + { + clazz += ".AuthInfoProviderFactory"; + try + { + IAuthInfoProviderFactory factory = (IAuthInfoProviderFactory) Class.forName( + clazz).newInstance(); + factories.add(factory); + } + catch (ClassCastException ignored) + { + } + catch (ClassNotFoundException ignored) + { + } + catch (InstantiationException ignored) + { + } + catch (IllegalAccessException ignored) + { + } + } + } + } + // always add ours last; unless it's already there + if (!factories.contains(ours)) + { + factories.add(ours); + } + } + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial constructor to enforce Singleton pattern. */ + private AuthInfo() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + * A convenience method to return the authentication information provider + * for a designated SASL mechnanism. It goes through all the installed + * provider factories, one at a time, and attempts to return a new instance + * of the provider for the designated mechanism. It stops at the first + * factory returning a non-null provider. + * + * @param mechanism the name of a SASL mechanism. + * @return an implementation that provides {@link IAuthInfoProvider} for that + * mechanism; or null if none found. + */ + public static IAuthInfoProvider getProvider(String mechanism) + { + for (Iterator it = factories.iterator(); it.hasNext();) + { + IAuthInfoProviderFactory factory = (IAuthInfoProviderFactory) it.next(); + IAuthInfoProvider result = factory.getInstance(mechanism); + if (result != null) + { + return result; + } + } + return null; + } +} diff --git a/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java b/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java new file mode 100644 index 000000000..6ba5fc562 --- /dev/null +++ b/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java @@ -0,0 +1,89 @@ +/* AuthInfoProviderFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.crammd5.CramMD5AuthInfoProvider; +import gnu.javax.crypto.sasl.plain.PlainAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; + +/** + * The concrete SASL authentication information provider factory. + */ +public class AuthInfoProviderFactory implements IAuthInfoProviderFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-args constructor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IAuthInfoProviderFactory interface implementation ----------------------- + + public IAuthInfoProvider getInstance(String mechanism) + { + if (mechanism == null) + { + return null; + } + mechanism = mechanism.trim().toUpperCase(); + if (mechanism.startsWith(Registry.SASL_SRP_MECHANISM)) + { + return new SRPAuthInfoProvider(); + } + if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM)) + { + return new CramMD5AuthInfoProvider(); + } + if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM)) + { + return new PlainAuthInfoProvider(); + } + return null; + } +} diff --git a/gnu/javax/crypto/sasl/ClientFactory.java b/gnu/javax/crypto/sasl/ClientFactory.java new file mode 100644 index 000000000..ef184632c --- /dev/null +++ b/gnu/javax/crypto/sasl/ClientFactory.java @@ -0,0 +1,210 @@ +/* ClientFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.anonymous.AnonymousClient; +import gnu.javax.crypto.sasl.crammd5.CramMD5Client; +import gnu.javax.crypto.sasl.plain.PlainClient; +import gnu.javax.crypto.sasl.srp.SRPClient; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.HashMap; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslException; + +/** + * The implementation of {@link SaslClientFactory}. + */ +public class ClientFactory implements SaslClientFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + public static final Set getNames() + { + return Collections.unmodifiableSet(new HashSet( + Arrays.asList(getNamesInternal(null)))); + } + + private static final String[] getNamesInternal(Map props) + { + String[] all = new String[] { Registry.SASL_SRP_MECHANISM, + Registry.SASL_CRAM_MD5_MECHANISM, + Registry.SASL_PLAIN_MECHANISM, + Registry.SASL_ANONYMOUS_MECHANISM }; + + if (props == null) + { + return all; + } + if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props)) + { + return new String[0]; + } + + List result = new ArrayList(all.length); + ; + for (int i = 0; i < all.length;) + { + result.add(all[i++]); + } + + if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props)) + { + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NOACTIVE, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NODICTIONARY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NOANONYMOUS, props)) + { + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_FORWARD_SECRECY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + return (String[]) result.toArray(new String[0]); + } + + public static final ClientMechanism getInstance(String mechanism) + { + if (mechanism == null) + { + return null; + } + mechanism = mechanism.trim().toUpperCase(); + if (mechanism.equals(Registry.SASL_SRP_MECHANISM)) + { + return new SRPClient(); + } + if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM)) + { + return new CramMD5Client(); + } + if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM)) + { + return new PlainClient(); + } + if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM)) + { + return new AnonymousClient(); + } + return null; + } + + // Instance methods + // ------------------------------------------------------------------------- + + public SaslClient createSaslClient(String[] mechanisms, + String authorisationID, String protocol, + String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + ClientMechanism result = null; + String mechanism; + for (int i = 0; i < mechanisms.length; i++) + { + mechanism = mechanisms[i]; + result = getInstance(mechanism); + if (result != null) + { + break; + } + } + + if (result != null) + { + HashMap attributes = new HashMap(); + if (props != null) + { + attributes.putAll(props); + } + attributes.put(Registry.SASL_AUTHORISATION_ID, authorisationID); + attributes.put(Registry.SASL_PROTOCOL, protocol); + attributes.put(Registry.SASL_SERVER_NAME, serverName); + attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh); + + result.init(attributes); + return result; + } + + throw new SaslException( + "No supported mechanism found in given mechanism list"); + } + + public String[] getMechanismNames(Map props) + { + return getNamesInternal(props); + } + + private static boolean hasPolicy(String propertyName, Map props) + { + return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName))); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/ClientMechanism.java b/gnu/javax/crypto/sasl/ClientMechanism.java new file mode 100644 index 000000000..45873ae6b --- /dev/null +++ b/gnu/javax/crypto/sasl/ClientMechanism.java @@ -0,0 +1,365 @@ +/* ClientMechanism.java -- + Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; + +import java.util.HashMap; +import java.util.Map; +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + *

A base class to facilitate implementing SASL client-side mechanisms.

+ */ +public abstract class ClientMechanism implements SaslClient +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Name of this mechanism. */ + protected String mechanism; + + /** The authorisation identity. */ + protected String authorizationID; + + /** Name of protocol using this mechanism. */ + protected String protocol; + + /** Name of server to authenticate to. */ + protected String serverName; + + /** Properties of qualities desired for this mechanism. */ + protected Map properties; + + /** Callback handler to use with this mechanism instance. */ + protected CallbackHandler handler; + + /** Channel binding data to use with this mechanism instance. */ + protected byte[] channelBinding; + + /** Whether authentication phase is completed (true) or not (false). */ + protected boolean complete = false; + + /** The state of the authentication automaton. */ + protected int state = -1; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected ClientMechanism(final String mechanism) + { + super(); + + this.mechanism = mechanism; + this.state = -1; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods to be implemented by concrete subclasses --------------- + + protected abstract void initMechanism() throws SaslException; + + protected abstract void resetMechanism() throws SaslException; + + // javax.security.sasl.SaslClient interface implementation ----------------- + + public abstract byte[] evaluateChallenge(byte[] challenge) + throws SaslException; + + public abstract boolean hasInitialResponse(); + + public boolean isComplete() + { + return complete; + } + + public byte[] unwrap(final byte[] incoming, final int offset, final int len) + throws SaslException + { + if (!isComplete()) + { + throw new IllegalMechanismStateException(); + } + return this.engineUnwrap(incoming, offset, len); + } + + public byte[] wrap(final byte[] outgoing, final int offset, final int len) + throws SaslException + { + if (!isComplete()) + { + throw new IllegalMechanismStateException(); + } + return this.engineWrap(outgoing, offset, len); + } + + public String getMechanismName() + { + return mechanism; + } + + public Object getNegotiatedProperty(final String propName) + { + if (!isComplete()) + { + throw new IllegalStateException(); + } + if (Sasl.QOP.equals(propName)) + { + return getNegotiatedQOP(); + } + if (Sasl.STRENGTH.equals(propName)) + { + return getNegotiatedStrength(); + } + if (Sasl.SERVER_AUTH.equals(propName)) + { + return getNegotiatedServerAuth(); + } + if (Sasl.MAX_BUFFER.equals(propName)) + { + return getNegotiatedMaxBuffer(); + } + if (Sasl.RAW_SEND_SIZE.equals(propName)) + { + return getNegotiatedRawSendSize(); + } + if (Sasl.POLICY_NOPLAINTEXT.equals(propName)) + { + return getNegotiatedPolicyNoPlainText(); + } + if (Sasl.POLICY_NOACTIVE.equals(propName)) + { + return getNegotiatedPolicyNoActive(); + } + if (Sasl.POLICY_NODICTIONARY.equals(propName)) + { + return getNegotiatedPolicyNoDictionary(); + } + if (Sasl.POLICY_NOANONYMOUS.equals(propName)) + { + return getNegotiatedPolicyNoAnonymous(); + } + if (Sasl.POLICY_FORWARD_SECRECY.equals(propName)) + { + return getNegotiatedPolicyForwardSecrecy(); + } + if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName)) + { + return getNegotiatedPolicyPassCredentials(); + } + if (Sasl.REUSE.equals(propName)) + { + return getReuse(); + } + return null; + } + + public void dispose() throws SaslException + { + } + + // other Instance methods -------------------------------------------------- + + public String getAuthorizationID() + { + return authorizationID; + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedServerAuth() + { + return Registry.SERVER_AUTH_FALSE; + } + + protected String getNegotiatedMaxBuffer() + { + return null; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(Registry.SASL_BUFFER_MAX_LIMIT); + } + + protected String getNegotiatedPolicyNoPlainText() + { + return null; + } + + protected String getNegotiatedPolicyNoActive() + { + return null; + } + + protected String getNegotiatedPolicyNoDictionary() + { + return null; + } + + protected String getNegotiatedPolicyNoAnonymous() + { + return null; + } + + protected String getNegotiatedPolicyForwardSecrecy() + { + return null; + } + + protected String getNegotiatedPolicyPassCredentials() + { + return null; + } + + protected String getReuse() + { + return Registry.REUSE_FALSE; + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(incoming, offset, result, 0, len); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(outgoing, offset, result, 0, len); + return result; + } + + /** + *

Initialises the mechanism with designated attributes. Permissible names + * and values are mechanism specific.

+ * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalMechanismStateException if the instance is already + * initialised. + * @throws SaslException if an exception occurs during the process. + */ + public void init(final Map attributes) throws SaslException + { + if (state != -1) + { + throw new IllegalMechanismStateException("init()"); + } + + if (properties == null) + { + properties = new HashMap(); + } + else + { + properties.clear(); + } + if (attributes != null) + { + authorizationID = (String) attributes.get(Registry.SASL_AUTHORISATION_ID); + protocol = (String) attributes.get(Registry.SASL_PROTOCOL); + serverName = (String) attributes.get(Registry.SASL_SERVER_NAME); + handler = (CallbackHandler) attributes.get(Registry.SASL_CALLBACK_HANDLER); + channelBinding = (byte[]) attributes.get(Registry.SASL_CHANNEL_BINDING); + properties.putAll(attributes); + } + else + { + handler = null; + } + + if (authorizationID == null) + { + authorizationID = ""; + } + if (protocol == null) + { + protocol = ""; + } + if (serverName == null) + { + serverName = ""; + } + if (channelBinding == null) + { + channelBinding = new byte[0]; + } + initMechanism(); + complete = false; + state = 0; + } + + /** + *

Resets the mechanism instance for re-initialisation and use with other + * characteristics.

+ * + * @throws SaslException if an exception occurs during the process. + */ + public void reset() throws SaslException + { + resetMechanism(); + properties.clear(); + authorizationID = protocol = serverName = null; + channelBinding = null; + complete = false; + state = -1; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/ConfidentialityException.java b/gnu/javax/crypto/sasl/ConfidentialityException.java new file mode 100644 index 000000000..b77e4d110 --- /dev/null +++ b/gnu/javax/crypto/sasl/ConfidentialityException.java @@ -0,0 +1,84 @@ +/* ConfidentialityException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * Used by mechanisms that offer a security services layer, this checked + * exception is thrown to indicate that a violation has occured during the + * processing of a confidentiality protection filter. + * + * @version $Revision: 1.1.4.1 $ + */ +public class ConfidentialityException extends SaslException +{ + + /** + * Constructs a new instance of ConfidentialityException with no + * detail message. + */ + public ConfidentialityException() + { + super(); + } + + /** + * Constructs a new instance of ConfidentialityException with + * the specified detail message. + * + * @param s the detail message. + */ + public ConfidentialityException(String s) + { + super(s); + } + + /** + * Constructs a new instance of ConfidentialityException with a + * detailed message and a root exception. + * + * @param s possibly null additional detail about the exception. + * @param x a possibly null root exception that caused this one. + */ + public ConfidentialityException(String s, Throwable x) + { + super(s, x); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/IAuthInfoProvider.java b/gnu/javax/crypto/sasl/IAuthInfoProvider.java new file mode 100644 index 000000000..2b913a137 --- /dev/null +++ b/gnu/javax/crypto/sasl/IAuthInfoProvider.java @@ -0,0 +1,117 @@ +/* IAuthInfoProvider.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The visible methods of any authentication information provider. + */ +public interface IAuthInfoProvider +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + * Activates (initialises) this provider instance. SHOULD be the first method + * invoked on the provider. + * + * @param context a collection of name-value bindings describing the + * activation context. + * @throws AuthenticationException if an exception occurs during the operation. + */ + void activate(Map context) throws AuthenticationException; + + /** + * Passivates (releases) this provider instance. SHOULD be the last method + * invoked on the provider. Once it is done, no other method may be invoked + * on the same instance before it is activated agains. + * + * @throws AuthenticationException if an exception occurs during the operation. + */ + void passivate() throws AuthenticationException; + + /** + * Checks if a user with a designated name is known to this provider. + * + * @param userName the name of a user to check. + * @return true if the user with the designated name is known to + * this provider; false otherwise. + * @throws AuthenticationException if an exception occurs during the operation. + */ + boolean contains(String userName) throws AuthenticationException; + + /** + * Returns a collection of information about a designated user. The contents + * of the returned map is provider-specific of name-to-value mappings. + * + * @param userID a map of name-to-value bindings that fully describe a user. + * @return a collection of information about the designated user. + * @throws AuthenticationException if an exception occurs during the operation. + */ + Map lookup(Map userID) throws AuthenticationException; + + /** + * Updates the credentials of a designated user. + * + * @param userCredentials a map of name-to-value bindings that fully describe + * a user, including per new credentials. + * @throws AuthenticationException if an exception occurs during the operation. + */ + void update(Map userCredentials) throws AuthenticationException; + + /** + * A provider may operate in more than mode; e.g. SRP-II caters for user + * credentials computed in more than one message digest algorithm. This + * method returns the set of name-to-value bindings describing the mode of + * the provider. + * + * @param mode a unique identifier describing the operational mode. + * @return a collection of name-to-value bindings describing the designated + * mode. + * @throws AuthenticationException if an exception occurs during the operation. + */ + Map getConfiguration(String mode) throws AuthenticationException; +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java b/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java new file mode 100644 index 000000000..e630b8da1 --- /dev/null +++ b/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java @@ -0,0 +1,62 @@ +/* IAuthInfoProviderFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +/** + * The visible method of every authentication information provider factory. + */ +public interface IAuthInfoProviderFactory +{ + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + * Returns an implementation of a provider for a designated mechanism + * capable of honouring {@link IAuthInfoProvider} requests. + * + * @param mechanism the unique name of a mechanism. + * @return an implementation of {@link IAuthInfoProvider} for that mechanism + * or null if none found. + */ + IAuthInfoProvider getInstance(String mechanism); +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/IllegalMechanismStateException.java b/gnu/javax/crypto/sasl/IllegalMechanismStateException.java new file mode 100644 index 000000000..00baceaa4 --- /dev/null +++ b/gnu/javax/crypto/sasl/IllegalMechanismStateException.java @@ -0,0 +1,86 @@ +/* IllegalMechanismStateException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.AuthenticationException; + +/** + * A checked exception thrown to indicate that an operation that should be + * invoked on a completed mechanism was invoked but the authentication phase of + * that mechanism was not completed yet, or that an operation that should be + * invoked on incomplete mechanisms was invoked but the authentication phase of + * that mechanism was already completed. + * + * @version $Revision: 1.1.4.1 $ + */ +public class IllegalMechanismStateException extends AuthenticationException +{ + + /** + * Constructs a new instance of IllegalMechanismStateException + * with no detail message. + */ + public IllegalMechanismStateException() + { + super(); + } + + /** + * Constructs a new instance of IllegalMechanismStateException + * with the specified detail message. + * + * @param detail the detail message. + */ + public IllegalMechanismStateException(String detail) + { + super(detail); + } + + /** + * Constructs a new instance of IllegalMechanismStateException + * with the specified detail message, and cause. + * + * @param detail the detail message. + * @param ex the original cause. + */ + public IllegalMechanismStateException(String detail, Throwable ex) + { + super(detail, ex); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/InputBuffer.java b/gnu/javax/crypto/sasl/InputBuffer.java new file mode 100644 index 000000000..a64ea3e0e --- /dev/null +++ b/gnu/javax/crypto/sasl/InputBuffer.java @@ -0,0 +1,339 @@ +/* InputBuffer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; + +/** + *

The implementation of an incoming SASL buffer.

+ * + *

The data elements this class caters for are described in [1].

+ * + *

References:

+ *
    + *
  1. + * Secure Remote Password Authentication Mechanism;
    + * draft-burdis-cat-srp-sasl-09,
    + * Keith Burdis and + * Raïf S. Naffah.
  2. + *
+ */ +public class InputBuffer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The internal buffer stream containing the buffer's contents. */ + protected ByteArrayInputStream in; + + /** The length of the buffer, according to its header. */ + protected int length; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Constructs a SASL buffer given the buffer's encoded form, including its + * header bytes.

+ * + * @param frame the encoded form, including the header bytes, of a SASL buffer. + * @throws SaslEncodingException if the buffer is malformed. + */ + public InputBuffer(byte[] frame) throws SaslEncodingException + { + this(); + + if (frame.length < 4) + { + throw new SaslEncodingException("SASL buffer header too short"); + } + + length = (frame[0] & 0xFF) << 24 | (frame[1] & 0xFF) << 16 + | (frame[2] & 0xFF) << 8 | (frame[3] & 0xFF); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + { + throw new SaslEncodingException("SASL buffer size limit exceeded"); + } + + in = new ByteArrayInputStream(frame, 4, length); + } + + /** Trivial private constructor for use by the class method. */ + private InputBuffer() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a SASL buffer given the buffer's encoded contents, + * excluding the buffer's header bytes.

+ * + *

Calls the method with the same name and three arguments as: + * getInstance(raw, 0, raw.length). + * + * @param raw the encoded form, excluding the header bytes, of a SASL buffer. + * @return a new instance of {@link InputBuffer}. + */ + public static InputBuffer getInstance(byte[] raw) + { + return getInstance(raw, 0, raw.length); + } + + /** + *

Returns an instance of a SASL buffer given the buffer's encoded + * contents, excluding the buffer's header bytes.

+ * + * @param raw the encoded form, excluding the header bytes, of a SASL buffer. + * @param offset offset where to start using raw bytes from. + * @param len number of bytes to use. + * @return a new instance of {@link InputBuffer}. + */ + public static InputBuffer getInstance(byte[] raw, int offset, int len) + { + InputBuffer result = new InputBuffer(); + result.in = new ByteArrayInputStream(raw, offset, len); + return result; + } + + /** + *

Converts four octets into the number that they represent.

+ * + * @param b the four octets. + * @return the length. + */ + // public static int fourBytesToLength(byte[] b) throws SaslEncodingException { + // int result = b[0] << 24 | (b[1] & 0xFF) << 16 | (b[2] & 0xFF) << 8 | (b[3] & 0xFF); + // if (result > Registry.SASL_FOUR_BYTE_MAX_LIMIT || result < 0) { + // throw new SaslEncodingException("SASL EOS size limit exceeded"); + // } + // return result; + // } + /** + *

Converts two octets into the number that they represent.

+ * + * @param b the two octets. + * @return the length. + */ + public static int twoBytesToLength(byte[] b) throws SaslEncodingException + { + final int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF); + if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT) + { + throw new SaslEncodingException("SASL MPI/Text size limit exceeded"); + } + return result; + } + + // Instance methods + // ------------------------------------------------------------------------- + + public boolean hasMoreElements() + { + return (in.available() > 0); + } + + /** + *

Decodes a SASL scalar quantity, count-octet long, from the + * current buffer.

+ * + * @param count the number of octets of this scalar quantity. + * @return a native representation of a SASL scalar (unsigned integer) quantity. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public long getScalar(int count) throws IOException + { + if (count < 0 || count > 4) + { + throw new SaslEncodingException("Invalid SASL scalar octet count: " + + String.valueOf(count)); + } + if (!hasMoreElements()) + { + throw new SaslEncodingException( + "Not enough bytes for a scalar in buffer"); + } + if (in.available() < count) + { + throw new SaslEncodingException("Illegal SASL scalar encoding"); + } + byte[] element = new byte[count]; + in.read(element); + + long result = 0L; + for (int i = 0; i < count; i++) + { + result <<= 8; + result |= element[i] & 0xFFL; + } + return result; + } + + /** + *

Decodes a SASL OS from the current buffer.

+ * + * @return a native representation of a SASL OS. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public byte[] getOS() throws IOException + { + if (!hasMoreElements()) + { + throw new SaslEncodingException( + "Not enough bytes for an octet-sequence in buffer"); + } + final int elementLength = in.read(); + if (elementLength > Registry.SASL_ONE_BYTE_MAX_LIMIT) + { + throw new SaslEncodingException( + "SASL octet-sequence size limit exceeded"); + } + + if (in.available() < elementLength) + { + throw new SaslEncodingException("Illegal SASL octet-sequence encoding"); + } + + byte[] result = new byte[elementLength]; + in.read(result); + + return result; + } + + /** + *

Decodes a SASL EOS from the current buffer.

+ * + * @return a native representation of a SASL EOS. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public byte[] getEOS() throws IOException + { + if (in.available() < 2) + { + throw new SaslEncodingException( + "Not enough bytes for an extended octet-sequence in buffer"); + } + + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes); + final int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + { + throw new SaslEncodingException( + "Illegal SASL extended octet-sequence encoding"); + } + + byte[] result = new byte[elementLength]; + in.read(result); + + return result; + } + + /** + *

Decodes a SASL MPI from the current buffer.

+ * + * @return a native representation of a SASL MPI. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public BigInteger getMPI() throws IOException + { + if (in.available() < 2) + { + throw new SaslEncodingException("Not enough bytes for an MPI in buffer"); + } + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes); + final int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + { + throw new SaslEncodingException( + "Illegal SASL multi-precision integer encoding"); + } + + byte[] element = new byte[elementLength]; + in.read(element); + + return new BigInteger(1, element); + } + + /** + *

Decodes a SASL Text from the current buffer.

+ * + * @return a native representation of a SASL Text. + * @throws SaslEncodingException if an encoding exception occurs during the + * operation. + * @throws SaslEncodingException if the UTF-8 character encoding is not + * supported on this platform. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public String getText() throws IOException + { + if (in.available() < 2) + { + throw new SaslEncodingException("Not enough bytes for a text in buffer"); + } + byte[] elementLengthBytes = new byte[2]; + in.read(elementLengthBytes); + final int elementLength = twoBytesToLength(elementLengthBytes); + if (in.available() < elementLength) + { + throw new SaslEncodingException("Illegal SASL text encoding"); + } + + byte[] element = new byte[elementLength]; + in.read(element); + + return new String(element, "UTF8"); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/IntegrityException.java b/gnu/javax/crypto/sasl/IntegrityException.java new file mode 100644 index 000000000..4a56ca2d5 --- /dev/null +++ b/gnu/javax/crypto/sasl/IntegrityException.java @@ -0,0 +1,83 @@ +/* IntegrityException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * Used by mechanisms that offer a security services layer, this checked + * exception is thrown to indicate that a violation has occured during the + * processing of an integrity protection filter, including replay + * detection. + */ +public class IntegrityException extends SaslException +{ + + /** + * Constructs a new instance of IntegrityException with no + * detail message. + */ + public IntegrityException() + { + super(); + } + + /** + * Constructs a new instance of IntegrityException with the + * specified detail message. + * + * @param s the detail message. + */ + public IntegrityException(String s) + { + super(s); + } + + /** + * Constructs a new instance of IntegrityException with a + * detailed message and a root exception. + * + * @param s possibly null additional detail about the exception. + * @param x a possibly null root exception that caused this one. + */ + public IntegrityException(String s, Throwable x) + { + super(s, x); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/NoSuchMechanismException.java b/gnu/javax/crypto/sasl/NoSuchMechanismException.java new file mode 100644 index 000000000..65432082a --- /dev/null +++ b/gnu/javax/crypto/sasl/NoSuchMechanismException.java @@ -0,0 +1,62 @@ +/* NoSuchMechanismException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * A checked exception thrown to indicate that a designated SASL mechanism + * implementation was not found. + */ +public class NoSuchMechanismException extends SaslException +{ + + /** + * Constructs a NoSuchMechanismException with the specified + * detail message. In the case of this exception, the detail message + * designates the offending mechanism name. + * + * @param arg the detail message, which in this case is the offending + * mechanism name. + */ + public NoSuchMechanismException(String arg) + { + super(arg); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/NoSuchUserException.java b/gnu/javax/crypto/sasl/NoSuchUserException.java new file mode 100644 index 000000000..fe362c742 --- /dev/null +++ b/gnu/javax/crypto/sasl/NoSuchUserException.java @@ -0,0 +1,67 @@ +/* NoSuchUserException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.AuthenticationException; + +/** + * A checked exception thrown to indicate that a designated user is unknown to + * the authentication layer. + */ +public class NoSuchUserException extends AuthenticationException +{ + + /** Constructs a NoSuchUserException with no detail message. */ + public NoSuchUserException() + { + super(); + } + + /** + * Constructs a NoSuchUserException with the specified detail + * message. In the case of this exception, the detail message designates + * the offending username. + * + * @param arg the detail message, which in this case is the username. + */ + public NoSuchUserException(String arg) + { + super(arg); + } +} diff --git a/gnu/javax/crypto/sasl/OutputBuffer.java b/gnu/javax/crypto/sasl/OutputBuffer.java new file mode 100644 index 000000000..d219e7e9f --- /dev/null +++ b/gnu/javax/crypto/sasl/OutputBuffer.java @@ -0,0 +1,225 @@ +/* OutputBuffer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; + +/** + *

The implementation of an outgoing SASL buffer.

+ * + *

The data elements this class caters for are described in [1].

+ * + *

References:

+ *
    + *
  1. + * Secure Remote Password Authentication Mechanism;
    + * draft-burdis-cat-srp-sasl-09,
    + * Keith Burdis and + * Raïf S. Naffah.
  2. + *
+ */ +public class OutputBuffer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The internal output stream. */ + private ByteArrayOutputStream out; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public OutputBuffer() + { + super(); + + out = new ByteArrayOutputStream(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Encodes a SASL scalar quantity, count-octet long, to the + * current buffer.

+ * + * @param count number of octets to encode b with. + * @param b the scalar quantity. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setScalar(int count, int b) throws IOException + { + if (count < 0 || count > 4) + { + throw new SaslEncodingException("Invalid SASL scalar octet count: " + + String.valueOf(count)); + } + byte[] element = new byte[count]; + for (int i = count; --i >= 0; b >>>= 8) + { + element[i] = (byte) b; + } + out.write(element); + } + + /** + *

Encodes a SASL OS to the current buffer.

+ * + * @param b the OS element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setOS(byte[] b) throws IOException + { + final int length = b.length; + if (length > Registry.SASL_ONE_BYTE_MAX_LIMIT) + { + throw new SaslEncodingException("SASL octet-sequence too long"); + } + out.write(length & 0xFF); + out.write(b); + } + + /** + *

Encodes a SASL EOS to the current buffer.

+ * + * @param b the EOS element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setEOS(byte[] b) throws IOException + { + final int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + { + throw new SaslEncodingException("SASL extended octet-sequence too long"); + } + byte[] lengthBytes = { (byte) (length >>> 8), (byte) length }; + out.write(lengthBytes); + out.write(b); + } + + /** + *

Encodes a SASL MPI to the current buffer.

+ * + * @param val the MPI element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setMPI(BigInteger val) throws IOException + { + byte[] b = Util.trim(val); + final int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + { + throw new SaslEncodingException("SASL multi-precision integer too long"); + } + byte[] lengthBytes = { (byte) (length >>> 8), (byte) length }; + out.write(lengthBytes); + out.write(b); + } + + /** + *

Encodes a SASL Text to the current buffer.

+ * + * @param str the Text element. + * @throws SaslEncodingException if an encoding size constraint is violated. + * @throws SaslEncodingException if the UTF-8 encoding is not supported on + * this platform. + * @throws IOException if any other I/O exception occurs during the operation. + */ + public void setText(String str) throws IOException + { + byte[] b = str.getBytes("UTF8"); + final int length = b.length; + if (length > Registry.SASL_TWO_BYTE_MAX_LIMIT) + { + throw new SaslEncodingException("SASL text too long"); + } + byte[] lengthBytes = { (byte) (length >>> 8), (byte) length }; + out.write(lengthBytes); + out.write(b); + } + + /** + *

Returns the encoded form of the current buffer including the 4-byte + * length header.

+ * + * @throws SaslEncodingException if an encoding size constraint is violated. + */ + public byte[] encode() throws SaslEncodingException + { + byte[] buffer = wrap(); + final int length = buffer.length; + byte[] result = new byte[length + 4]; + result[0] = (byte) (length >>> 24); + result[1] = (byte) (length >>> 16); + result[2] = (byte) (length >>> 8); + result[3] = (byte) length; + System.arraycopy(buffer, 0, result, 4, length); + + return result; + } + + /** + *

Returns the encoded form of the current buffer excluding the 4-byte + * length header.

+ * + * @throws SaslEncodingException if an encoding size constraint is violated. + */ + public byte[] wrap() throws SaslEncodingException + { + final int length = out.size(); + if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0) + { + throw new SaslEncodingException("SASL buffer too long"); + } + return out.toByteArray(); + } +} diff --git a/gnu/javax/crypto/sasl/SaslEncodingException.java b/gnu/javax/crypto/sasl/SaslEncodingException.java new file mode 100644 index 000000000..9f4c59f1c --- /dev/null +++ b/gnu/javax/crypto/sasl/SaslEncodingException.java @@ -0,0 +1,66 @@ +/* SaslEncodingException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * A checked exception, thrown when an exception occurs while decoding a SASL + * buffer and/or a SASL data element from/to a buffer. + */ +public class SaslEncodingException extends SaslException +{ + + /** Constructs a SaslEncodingException with no detail message. */ + public SaslEncodingException() + { + super(); + } + + /** + * Constructs a SaslEncodingException with the specified detail + * message. + * + * @param s the detail message. + */ + public SaslEncodingException(String s) + { + super(s); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/SaslInputStream.java b/gnu/javax/crypto/sasl/SaslInputStream.java new file mode 100644 index 000000000..57eb2b5c5 --- /dev/null +++ b/gnu/javax/crypto/sasl/SaslInputStream.java @@ -0,0 +1,459 @@ +/* SaslInputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.util.Util; + +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.IOException; +import java.io.PrintWriter; + +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslServer; + +/** + * An input stream that uses either a {@link SaslClient} or a {@link SaslServer} + * to process the data through these entities' security layer filter(s). + */ +public class SaslInputStream extends InputStream +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "SaslOutputStream"; + + private static final String ERROR = "ERROR"; + + private static final String WARN = " WARN"; + + // private static final String INFO = " INFO"; + private static final String TRACE = "DEBUG"; + + private static final boolean DEBUG = true; + + private static final int debuglevel = 3; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String level, Object obj) + { + err.println("[" + level + "] " + NAME + ": " + String.valueOf(obj)); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + private SaslClient client; + + private SaslServer server; + + private int maxRawSendSize; + + private InputStream source; + + private byte[] internalBuf; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public SaslInputStream(SaslClient client, InputStream source) + throws IOException + { + super(); + + this.client = client; + maxRawSendSize = Integer.parseInt((String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE)); + server = null; + this.source = source; + } + + public SaslInputStream(SaslServer server, InputStream source) + throws IOException + { + super(); + + this.server = server; + maxRawSendSize = Integer.parseInt((String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE)); + client = null; + this.source = source; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // Overloaded java.io.InputStream methods ---------------------------------- + + public int available() throws IOException + { + return (internalBuf == null) ? 0 : internalBuf.length; + } + + public void close() throws IOException + { + source.close(); + } + + /** + *

Reads the next byte of data from the input stream. The value byte is + * returned as an int in the range 0 to + * 255. If no byte is available because the end of the stream + * has been reached, the value -1 is returned. This method + * blocks until input data is available, the end of the stream is detected, + * or an exception is thrown.

+ * + *

From a SASL mechanism provider's perspective, if a security layer has + * been negotiated, the underlying source is expected to contain SASL + * buffers, as defined in RFC 2222. Four octets in network byte order in the + * front of each buffer identify the length of the buffer. The provider is + * responsible for performing any integrity checking or other processing on + * the buffer before returning the data as a stream of octets. For example, + * the protocol driver's request for a single octet from the stream might; + * i.e. an invocation of this method, may result in an entire SASL buffer + * being read and processed before that single octet can be returned.

+ * + * @return the next byte of data, or -1 if the end of the stream + * is reached. + * @throws IOException if an I/O error occurs. + */ + public int read() throws IOException + { + int result = -1; + if (internalBuf != null && internalBuf.length > 0) + { + result = internalBuf[0] & 0xFF; + if (internalBuf.length == 1) + internalBuf = new byte[0]; + else + { + byte[] tmp = new byte[internalBuf.length - 1]; + // System.arraycopy(internalBuf, 0, tmp, 0, tmp.length); + System.arraycopy(internalBuf, 1, tmp, 0, tmp.length); + internalBuf = tmp; + } + } + else + { + byte[] buf = new byte[1]; + int check = read(buf); + result = (check > 0) ? (buf[0] & 0xFF) : -1; + } + + return result; + } + + /** + *

Reads up to len bytes of data from the underlying + * source input stream into an array of bytes. An attempt is made to + * read as many as len bytes, but a smaller number may be read, + * possibly zero. The number of bytes actually read is returned as an + * integer.

+ * + *

This method blocks until input data is available, end of file is + * detected, or an exception is thrown.

+ * + *

If b is null, a {@link NullPointerException} is + * thrown.

+ * + *

If off is negative, or len is negative, or + * off+len is greater than the length of the array b, + * then an {@link IndexOutOfBoundsException} is thrown.

+ * + *

If len is zero, then no bytes are read and 0 + * is returned; otherwise, there is an attempt to read at least one byte. If + * no byte is available because the stream is at end of file, the value + * -1 is returned; otherwise, at least one byte is read and + * stored into b.

+ * + *

The first byte read is stored into element b[off], the + * next one into b[off+1], and so on. The number of bytes read + * is, at most, equal to len. Let k be the number + * of bytes actually read; these bytes will be stored in elements + * b[off] through b[off+k-1], leaving elements + * b[off+k] through b[off+len-1] unaffected.

+ * + *

In every case, elements b[0] through b[off] + * and elements b[off+len] through b[b.length-1] + * are unaffected.

+ * + *

If the first byte cannot be read for any reason other than end of file, + * then an {@link IOException} is thrown. In particular, an {@link IOException} + * is thrown if the input stream has been closed.

+ * + *

From the SASL mechanism provider's perspective, if a security layer has + * been negotiated, the underlying source is expected to contain SASL + * buffers, as defined in RFC 2222. Four octets in network byte order in the + * front of each buffer identify the length of the buffer. The provider is + * responsible for performing any integrity checking or other processing on + * the buffer before returning the data as a stream of octets. The protocol + * driver's request for a single octet from the stream might result in an + * entire SASL buffer being read and processed before that single octet can + * be returned.

+ * + * @param b the buffer into which the data is read. + * @param off the start offset in array b at which the data is + * wricodeen. + * @param len the maximum number of bytes to read. + * @return the total number of bytes read into the buffer, or -1 + * if there is no more data because the end of the stream has been reached. + * @throws IOException if an I/O error occurs. + */ + public int read(byte[] b, int off, int len) throws IOException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> read(b, " + String.valueOf(off) + ", " + + String.valueOf(len) + ")"); + + if (b == null) + { + throw new NullPointerException("b"); + } + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) + || ((off + len) < 0)) + { + throw new IndexOutOfBoundsException("off=" + String.valueOf(off) + + ", len=" + String.valueOf(len) + + ", b.length=" + + String.valueOf(b.length)); + } + if (len == 0) + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== read() --> 0"); + return 0; + } + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Available: " + String.valueOf(available())); + + int result = 0; + if (internalBuf == null || internalBuf.length < 1) + try + { + internalBuf = readSaslBuffer(); + if (internalBuf == null) + { + if (DEBUG && debuglevel > 4) + debug(WARN, "Underlying stream empty. Returning -1"); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== read() --> -1"); + return -1; + } + } + catch (InterruptedIOException x) + { + if (DEBUG && debuglevel > 6) + debug(TRACE, x); + if (DEBUG && debuglevel > 4) + debug(WARN, "Reading thread was interrupted. Returning -1"); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== read() --> -1"); + return -1; + } + + if (len <= internalBuf.length) + { + result = len; + System.arraycopy(internalBuf, 0, b, off, len); + if (len == internalBuf.length) + internalBuf = null; + else + { + byte[] tmp = new byte[internalBuf.length - len]; + System.arraycopy(internalBuf, len, tmp, 0, tmp.length); + internalBuf = tmp; + } + } + else + { + // first copy the available bytes to b + result = internalBuf.length; + System.arraycopy(internalBuf, 0, b, off, result); + internalBuf = null; + + off += result; + len -= result; + + int remaining; // count of bytes remaining in buffer after an iteration + int delta; // count of bytes moved to b after an iteration + int datalen; + byte[] data; + while (len > 0) + // we need to read SASL buffers, as long as there are at least + // 4 bytes available at the source + if (source.available() > 3) + { + // process a buffer + data = readSaslBuffer(); + if (data == null) + { + if (DEBUG && debuglevel > 4) + debug(WARN, "Underlying stream exhausted. Breaking..."); + break; + } + + datalen = data.length; + + // copy [part of] the result to b + remaining = (datalen <= len) ? 0 : datalen - len; + delta = datalen - remaining; + System.arraycopy(data, 0, b, off, delta); + if (remaining > 0) + { + internalBuf = new byte[remaining]; + System.arraycopy(data, delta, internalBuf, 0, remaining); + } + + // update off, result and len + off += delta; + result += delta; + len -= delta; + } + else + { // nothing much we can do except return what we have + if (DEBUG && debuglevel > 4) + debug(WARN, + "Not enough bytes in source to read a buffer. Breaking..."); + break; + } + } + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Remaining: " + + (internalBuf == null ? 0 : internalBuf.length)); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== read() --> " + String.valueOf(result)); + return result; + } + + // other nstance methods --------------------------------------------------- + + /** + * Reads a SASL buffer from the underlying source if at least 4 bytes are + * available. + * + * @return the byte[] of decoded buffer contents, or null if the underlying + * source was exhausted. + * @throws IOException if an I/O exception occurs during the operation. + */ + private byte[] readSaslBuffer() throws IOException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> readSaslBuffer()"); + + int realLength; // check if we read as many bytes as we're supposed to + byte[] result = new byte[4]; + try + { + realLength = source.read(result); + if (realLength == -1) + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== readSaslBuffer() --> null"); + return null; + } + } + catch (IOException x) + { + if (DEBUG && debuglevel > 0) + debug(ERROR, x); + throw x; + } + + if (realLength != 4) + { + throw new IOException("Was expecting 4 but found " + + String.valueOf(realLength)); + } + int bufferLength = result[0] << 24 | (result[1] & 0xFF) << 16 + | (result[2] & 0xFF) << 8 | (result[3] & 0xFF); + + if (DEBUG && debuglevel > 6) + debug(TRACE, "SASL buffer size: " + bufferLength); + if (bufferLength > maxRawSendSize || bufferLength < 0) + { + throw new SaslEncodingException("SASL buffer (security layer) too long"); + } + + result = new byte[bufferLength]; + try + { + realLength = source.read(result); + } + catch (IOException x) + { + if (DEBUG && debuglevel > 0) + debug(ERROR, x); + throw x; + } + + if (realLength != bufferLength) + throw new IOException("Was expecting " + String.valueOf(bufferLength) + + " but found " + String.valueOf(realLength)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Incoming buffer (before security) (hex): " + + Util.dumpString(result)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Incoming buffer (before security) (str): \"" + + new String(result) + "\""); + + if (client != null) + { + result = client.unwrap(result, 0, realLength); + } + else + { + result = server.unwrap(result, 0, realLength); + } + if (DEBUG && debuglevel > 6) + debug(TRACE, "Incoming buffer (after security) (hex): " + + Util.dumpString(result)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Incoming buffer (after security) (str): \"" + + new String(result) + "\""); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== readSaslBuffer()"); + return result; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/SaslOutputStream.java b/gnu/javax/crypto/sasl/SaslOutputStream.java new file mode 100644 index 000000000..699720137 --- /dev/null +++ b/gnu/javax/crypto/sasl/SaslOutputStream.java @@ -0,0 +1,218 @@ +/* SaslOutputStream.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.util.Util; + +import java.io.OutputStream; +import java.io.IOException; +import java.io.PrintWriter; + +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslServer; + +/** + * An output stream that uses either a {@link SaslClient} or a {@link SaslServer} + * to process the data through these entities' security layer filter(s). + */ +public class SaslOutputStream extends OutputStream +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "SaslOutputStream"; + + // private static final String ERROR = "ERROR"; + // private static final String WARN = " WARN"; + // private static final String INFO = " INFO"; + private static final String TRACE = "DEBUG"; + + private static final boolean DEBUG = true; + + private static final int debuglevel = 3; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(String level, Object obj) + { + err.println("[" + level + "] " + NAME + ": " + String.valueOf(obj)); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + private SaslClient client; + + private SaslServer server; + + private int maxRawSendSize; + + private OutputStream dest; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public SaslOutputStream(SaslClient client, OutputStream dest) + throws IOException + { + super(); + + this.client = client; + maxRawSendSize = Integer.parseInt((String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE)); + server = null; + this.dest = dest; + } + + public SaslOutputStream(SaslServer server, OutputStream dest) + throws IOException + { + super(); + + this.server = server; + maxRawSendSize = Integer.parseInt((String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE)); + client = null; + this.dest = dest; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Overloaded java.io.OutputStream methods + // ------------------------------------------------------------------------- + + public void close() throws IOException + { + dest.flush(); + dest.close(); + } + + public void flush() throws IOException + { + dest.flush(); + } + + /** + * When writing octets to the resulting stream, if a security layer has been + * negotiated, each piece of data written (by a single invocation of + * write()) will be encapsulated as a SASL buffer, as defined in + * RFC 2222, and then written to the underlying dest output stream. + */ + public void write(int b) throws IOException + { + write(new byte[] { (byte) b }); + } + + /** + * When writing octets to the resulting stream, if a security layer has been + * negotiated, each piece of data written (by a single invocation of + * write()) will be encapsulated as a SASL buffer, as defined in + * RFC 2222, and then written to the underlying dest output stream. + */ + public void write(byte[] b, int off, int len) throws IOException + { + if (b == null) + { + throw new NullPointerException("b"); + } + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) + || ((off + len) < 0)) + { + throw new IndexOutOfBoundsException("off=" + String.valueOf(off) + + ", len=" + String.valueOf(len) + + ", b.length=" + + String.valueOf(b.length)); + } + if (len == 0) + { + return; + } + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> write()"); + + int chunckSize, length, chunck = 1; + byte[] output = null, result; + if (DEBUG && debuglevel > 6) + debug(TRACE, "About to wrap " + String.valueOf(len) + " byte(s)..."); + while (len > 0) + { + chunckSize = (len > maxRawSendSize ? maxRawSendSize : len); + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Outgoing buffer (before security) (hex): " + + Util.dumpString(b, off, chunckSize)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Outgoing buffer (before security) (str): \"" + + new String(b, off, chunckSize) + "\""); + + if (client != null) + output = client.wrap(b, off, chunckSize); + else + output = server.wrap(b, off, chunckSize); + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Outgoing buffer (after security) (hex): " + + Util.dumpString(output)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Outgoing buffer (after security) (str): \"" + + new String(output) + "\""); + + length = output.length; + result = new byte[length + 4]; + result[0] = (byte) (length >>> 24); + result[1] = (byte) (length >>> 16); + result[2] = (byte) (length >>> 8); + result[3] = (byte) length; + System.arraycopy(output, 0, result, 4, length); + + dest.write(result); + + off += chunckSize; + len -= chunckSize; + if (DEBUG && debuglevel > 6) + debug(TRACE, "Wrapped chunck #" + String.valueOf(chunck)); + chunck++; + } + + dest.flush(); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== write()"); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/SaslUtil.java b/gnu/javax/crypto/sasl/SaslUtil.java new file mode 100644 index 000000000..e70312c0d --- /dev/null +++ b/gnu/javax/crypto/sasl/SaslUtil.java @@ -0,0 +1,89 @@ +/* SaslUtil.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.util.Util; + +import java.math.BigInteger; +import java.security.MessageDigest; + +/** + * Utility methods for SASL-related classes. + */ +public class SaslUtil +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + private SaslUtil() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final boolean validEmailAddress(String address) + { + // need to do better than this + return (address.indexOf("@") != -1); + } + + // Visualisation methods + // ------------------------------------------------------------------------- + + /** Returns the context of the designated hash as a string. */ + public static final String dump(MessageDigest md) + { + String result; + try + { + result = Util.dumpString(((MessageDigest) md.clone()).digest()); + } + catch (Exception ignored) + { + result = "..."; + } + return result; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/ServerFactory.java b/gnu/javax/crypto/sasl/ServerFactory.java new file mode 100644 index 000000000..e9b08dbd4 --- /dev/null +++ b/gnu/javax/crypto/sasl/ServerFactory.java @@ -0,0 +1,194 @@ +/* ServerFactory.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.anonymous.AnonymousServer; +import gnu.javax.crypto.sasl.crammd5.CramMD5Server; +import gnu.javax.crypto.sasl.plain.PlainServer; +import gnu.javax.crypto.sasl.srp.SRPServer; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +/** + * The implementation of the {@link SaslServerFactory}. + */ +public class ServerFactory implements SaslServerFactory +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-arguments constructor + + // Class methods + // ------------------------------------------------------------------------- + + public static final Set getNames() + { + return Collections.unmodifiableSet(new HashSet( + Arrays.asList(getNamesInternal(null)))); + } + + private static final String[] getNamesInternal(Map props) + { + String[] all = new String[] { Registry.SASL_SRP_MECHANISM, + Registry.SASL_CRAM_MD5_MECHANISM, + Registry.SASL_PLAIN_MECHANISM, + Registry.SASL_ANONYMOUS_MECHANISM }; + + List result = new ArrayList(4); + int i; + for (i = 0; i < all.length;) + { + result.add(all[i++]); + } + + if (props == null) + { + return (String[]) result.toArray(new String[0]); // all + } + if (hasPolicy(Sasl.POLICY_PASS_CREDENTIALS, props)) + { // none + return new String[0]; + } + + if (hasPolicy(Sasl.POLICY_NOPLAINTEXT, props)) + { + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NOACTIVE, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NODICTIONARY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_NOANONYMOUS, props)) + { + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + } + if (hasPolicy(Sasl.POLICY_FORWARD_SECRECY, props)) + { + result.remove(Registry.SASL_CRAM_MD5_MECHANISM); + result.remove(Registry.SASL_ANONYMOUS_MECHANISM); + result.remove(Registry.SASL_PLAIN_MECHANISM); + } + return (String[]) result.toArray(new String[0]); + } + + public static final ServerMechanism getInstance(String mechanism) + { + if (mechanism == null) + { + return null; + } + mechanism = mechanism.trim().toUpperCase(); + if (mechanism.equals(Registry.SASL_SRP_MECHANISM)) + { + return new SRPServer(); + } + if (mechanism.equals(Registry.SASL_CRAM_MD5_MECHANISM)) + { + return new CramMD5Server(); + } + if (mechanism.equals(Registry.SASL_PLAIN_MECHANISM)) + { + return new PlainServer(); + } + if (mechanism.equals(Registry.SASL_ANONYMOUS_MECHANISM)) + { + return new AnonymousServer(); + } + return null; + } + + // Instance methods + // ------------------------------------------------------------------------- + + public SaslServer createSaslServer(String mechanism, String protocol, + String serverName, Map props, + CallbackHandler cbh) throws SaslException + { + ServerMechanism result = getInstance(mechanism); + if (result != null) + { + HashMap attributes = new HashMap(); + if (props != null) + { + attributes.putAll(props); + } + attributes.put(Registry.SASL_PROTOCOL, protocol); + attributes.put(Registry.SASL_SERVER_NAME, serverName); + attributes.put(Registry.SASL_CALLBACK_HANDLER, cbh); + + result.init(attributes); + } + return result; + } + + public String[] getMechanismNames(Map props) + { + return getNamesInternal(props); + } + + private static boolean hasPolicy(String propertyName, Map props) + { + return "true".equalsIgnoreCase(String.valueOf(props.get(propertyName))); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/ServerMechanism.java b/gnu/javax/crypto/sasl/ServerMechanism.java new file mode 100644 index 000000000..f12a075d9 --- /dev/null +++ b/gnu/javax/crypto/sasl/ServerMechanism.java @@ -0,0 +1,371 @@ +/* ServerMechanism.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import gnu.java.security.Registry; + +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; + +/** + *

A base class to facilitate implementing SASL server-side mechanisms.

+ */ +public abstract class ServerMechanism implements SaslServer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** Name of this mechanism. */ + protected String mechanism; + + /** Name of protocol using this mechanism. */ + protected String protocol; + + /** Name of server to authenticate to. */ + protected String serverName; + + /** Properties of qualities desired for this mechanism. */ + protected Map properties; + + /** Callback handler to use with this mechanism instance. */ + protected CallbackHandler handler; + + /** Whether authentication phase is completed (true) or not (false). */ + protected boolean complete = false; + + /** The authorisation identity. */ + protected String authorizationID; + + /** Channel binding data to use with this mechanism instance. */ + protected byte[] channelBinding; + + /** The state of the authentication automaton. -1 means uninitialised. */ + protected int state = -1; + + /** The provider for authentication information. */ + protected IAuthInfoProvider authenticator; + + // Constructor(s) + // ------------------------------------------------------------------------- + + protected ServerMechanism(final String mechanism) + { + super(); + + this.mechanism = mechanism; + this.authenticator = AuthInfo.getProvider(mechanism); + this.state = -1; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods to be implemented by concrete subclasses --------------- + + protected abstract void initMechanism() throws SaslException; + + protected abstract void resetMechanism() throws SaslException; + + // javax.security.sasl.SaslServer interface implementation ----------------- + + public abstract byte[] evaluateResponse(byte[] response) throws SaslException; + + public boolean isComplete() + { + return complete; + } + + public byte[] unwrap(final byte[] incoming, final int offset, final int len) + throws SaslException + { + if (!isComplete()) + { + throw new IllegalMechanismStateException(); + } + return this.engineUnwrap(incoming, offset, len); + } + + public byte[] wrap(final byte[] outgoing, final int offset, final int len) + throws SaslException + { + if (!isComplete()) + { + throw new IllegalMechanismStateException(); + } + return this.engineWrap(outgoing, offset, len); + } + + public String getMechanismName() + { + return this.mechanism; + } + + public String getAuthorizationID() + { + return this.authorizationID; + } + + public Object getNegotiatedProperty(final String propName) + { + if (!isComplete()) + { + throw new IllegalStateException(); + } + if (Sasl.QOP.equals(propName)) + { + return getNegotiatedQOP(); + } + if (Sasl.STRENGTH.equals(propName)) + { + return getNegotiatedStrength(); + } + if (Sasl.SERVER_AUTH.equals(propName)) + { + return getNegotiatedServerAuth(); + } + if (Sasl.MAX_BUFFER.equals(propName)) + { + return getNegotiatedMaxBuffer(); + } + if (Sasl.RAW_SEND_SIZE.equals(propName)) + { + return getNegotiatedRawSendSize(); + } + if (Sasl.POLICY_NOPLAINTEXT.equals(propName)) + { + return getNegotiatedPolicyNoPlainText(); + } + if (Sasl.POLICY_NOACTIVE.equals(propName)) + { + return getNegotiatedPolicyNoActive(); + } + if (Sasl.POLICY_NODICTIONARY.equals(propName)) + { + return getNegotiatedPolicyNoDictionary(); + } + if (Sasl.POLICY_NOANONYMOUS.equals(propName)) + { + return getNegotiatedPolicyNoAnonymous(); + } + if (Sasl.POLICY_FORWARD_SECRECY.equals(propName)) + { + return getNegotiatedPolicyForwardSecrecy(); + } + if (Sasl.POLICY_PASS_CREDENTIALS.equals(propName)) + { + return getNegotiatedPolicyPassCredentials(); + } + if (Sasl.REUSE.equals(propName)) + { + return getReuse(); + } + return null; + } + + public void dispose() throws SaslException + { + reset(); + } + + // other Instance methods -------------------------------------------------- + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedServerAuth() + { + return Registry.SERVER_AUTH_FALSE; + } + + protected String getNegotiatedMaxBuffer() + { + return null; + } + + protected String getNegotiatedPolicyNoPlainText() + { + return null; + } + + protected String getNegotiatedPolicyNoActive() + { + return null; + } + + protected String getNegotiatedPolicyNoDictionary() + { + return null; + } + + protected String getNegotiatedPolicyNoAnonymous() + { + return null; + } + + protected String getNegotiatedPolicyForwardSecrecy() + { + return null; + } + + protected String getNegotiatedPolicyPassCredentials() + { + return null; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(Registry.SASL_BUFFER_MAX_LIMIT); + } + + protected String getReuse() + { + return Registry.REUSE_FALSE; + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(incoming, offset, result, 0, len); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + final byte[] result = new byte[len]; + System.arraycopy(outgoing, offset, result, 0, len); + return result; + } + + /** + *

Initialises the mechanism with designated attributes. Permissible names + * and values are mechanism specific.

+ * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @throws IllegalMechanismStateException if the instance is already + * initialised. + * @throws SaslException if an exception occurs during the process. + */ + public void init(final Map attributes) throws SaslException + { + if (state != -1) + { + throw new IllegalMechanismStateException("init()"); + } + + if (properties == null) + { + properties = new HashMap(); + } + else + { + properties.clear(); + } + if (attributes != null) + { + protocol = (String) attributes.get(Registry.SASL_PROTOCOL); + serverName = (String) attributes.get(Registry.SASL_SERVER_NAME); + handler = (CallbackHandler) attributes.get(Registry.SASL_CALLBACK_HANDLER); + channelBinding = (byte[]) attributes.get(Registry.SASL_CHANNEL_BINDING); + properties.putAll(attributes); + } + else + { + handler = null; + } + + if (protocol == null) + { + protocol = ""; + } + if (serverName == null) + { + serverName = ""; + } + if (authenticator != null) + { + authenticator.activate(properties); + } + if (channelBinding == null) + { + channelBinding = new byte[0]; + } + initMechanism(); + complete = false; + state = 0; + } + + /** + *

Resets the mechanism instance for re-initialisation and use with other + * characteristics.

+ * + * @throws SaslException if an exception occurs during the process. + */ + public void reset() throws SaslException + { + resetMechanism(); + properties.clear(); + if (authenticator != null) + { + authenticator.passivate(); + } + protocol = serverName = null; + channelBinding = null; + complete = false; + state = -1; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/UserAlreadyExistsException.java b/gnu/javax/crypto/sasl/UserAlreadyExistsException.java new file mode 100644 index 000000000..764a36df3 --- /dev/null +++ b/gnu/javax/crypto/sasl/UserAlreadyExistsException.java @@ -0,0 +1,70 @@ +/* UserAlreadyExistsException.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl; + +import javax.security.sasl.SaslException; + +/** + * A checked exception thrown to indicate that a designated user is already + * known to the the authentication layer. + */ +public class UserAlreadyExistsException extends SaslException +{ + + /** + * Constructs a UserAlreadyExistsException with no detail + * message. + */ + public UserAlreadyExistsException() + { + super(); + } + + /** + * Constructs a UserAlreadyExistsException with the specified + * detail message. In the case of this exception, the detail message + * designates the offending username. + * + * @param userName the detail message, which in this case is the username. + */ + public UserAlreadyExistsException(String userName) + { + super(userName); + } +} diff --git a/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java b/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java new file mode 100644 index 000000000..f5b1faab2 --- /dev/null +++ b/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java @@ -0,0 +1,120 @@ +/* AnonymousClient.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.anonymous; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ClientMechanism; +import gnu.javax.crypto.sasl.IllegalMechanismStateException; + +import java.io.UnsupportedEncodingException; + +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; +import javax.security.sasl.AuthenticationException; + +/** + *

The ANONYMOUS client-side mechanism.

+ */ +public class AnonymousClient extends ClientMechanism implements SaslClient +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public AnonymousClient() + { + super(Registry.SASL_ANONYMOUS_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslClient interface implementation ----------------- + + public boolean hasInitialResponse() + { + return true; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + if (complete) + { + throw new IllegalMechanismStateException("evaluateChallenge()"); + } + return response(); + } + + private byte[] response() throws SaslException + { + if (!AnonymousUtil.isValidTraceInformation(authorizationID)) + { + throw new AuthenticationException( + "Authorisation ID is not a valid email address"); + } + complete = true; + // return authorizationID.getBytes(); + final byte[] result; + try + { + result = authorizationID.getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("response()", x); + } + return result; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java b/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java new file mode 100644 index 000000000..2c10f78a7 --- /dev/null +++ b/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java @@ -0,0 +1,107 @@ +/* AnonymousServer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.anonymous; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.UnsupportedEncodingException; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * The ANONYMOUS server-side mechanism. + */ +public class AnonymousServer extends ServerMechanism implements SaslServer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public AnonymousServer() + { + super(Registry.SASL_ANONYMOUS_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslServer interface implementation ----------------- + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + if (response == null) + { + return null; + } + try + { + authorizationID = new String(response, "UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + if (AnonymousUtil.isValidTraceInformation(authorizationID)) + { + this.complete = true; + return null; + } + authorizationID = null; + throw new AuthenticationException("Invalid email address"); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java b/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java new file mode 100644 index 000000000..99e95eaec --- /dev/null +++ b/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java @@ -0,0 +1,109 @@ +/* AnonymousUtil.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.anonymous; + +import gnu.javax.crypto.sasl.SaslUtil; + +/** + * An ANONYMOUS-specific utility class. + */ +public class AnonymousUtil +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial private constructor to enforce Singleton pattern. */ + private AnonymousUtil() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + static boolean isValidTraceInformation(String traceInformation) + { + if (traceInformation == null) + { + return false; + } + if (traceInformation.length() == 0) + { + return true; + } + if (SaslUtil.validEmailAddress(traceInformation)) + { + return true; + } + return isValidToken(traceInformation); + } + + static boolean isValidToken(String token) + { + if (token == null) + { + return false; + } + if (token.length() == 0) + { + return false; + } + if (token.length() > 255) + { + return false; + } + if (token.indexOf('@') != -1) + { + return false; + } + for (int i = 0; i < token.length(); i++) + { + char c = token.charAt(i); + if (c < 0x20 || c > 0x7E) + { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java b/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java new file mode 100644 index 000000000..cf73b6f98 --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java @@ -0,0 +1,200 @@ +/* CramMD5AuthInfoProvider.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.IAuthInfoProvider; +import gnu.javax.crypto.sasl.NoSuchUserException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The CRAM-MD5 mechanism authentication information provider implementation. + */ +public class CramMD5AuthInfoProvider implements IAuthInfoProvider +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private PasswordFile passwordFile = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-args constrcutor + + // Class methods + // ------------------------------------------------------------------------- + + // IAuthInfoProvider interface implementation + // ------------------------------------------------------------------------- + + public void activate(Map context) throws AuthenticationException + { + try + { + if (context == null) + { + passwordFile = new PasswordFile(); + } + else + { + String pfn = (String) context.get(CramMD5Registry.PASSWORD_FILE); + if (pfn == null) + { + passwordFile = new PasswordFile(); + } + else + { + passwordFile = new PasswordFile(pfn); + } + } + } + catch (IOException x) + { + throw new AuthenticationException("activate()", x); + } + } + + public void passivate() throws AuthenticationException + { + passwordFile = null; + } + + public boolean contains(String userName) throws AuthenticationException + { + if (passwordFile == null) + { + throw new AuthenticationException("contains()", + new IllegalStateException()); + } + boolean result = false; + try + { + result = passwordFile.contains(userName); + } + catch (IOException x) + { + throw new AuthenticationException("contains()", x); + } + return result; + } + + public Map lookup(Map userID) throws AuthenticationException + { + if (passwordFile == null) + { + throw new AuthenticationException("lookup()", + new IllegalStateException()); + } + Map result = new HashMap(); + try + { + String userName = (String) userID.get(Registry.SASL_USERNAME); + if (userName == null) + { + throw new NoSuchUserException(""); + } + String[] data = passwordFile.lookup(userName); + result.put(Registry.SASL_USERNAME, data[0]); + result.put(Registry.SASL_PASSWORD, data[1]); + result.put(CramMD5Registry.UID_FIELD, data[2]); + result.put(CramMD5Registry.GID_FIELD, data[3]); + result.put(CramMD5Registry.GECOS_FIELD, data[4]); + result.put(CramMD5Registry.DIR_FIELD, data[5]); + result.put(CramMD5Registry.SHELL_FIELD, data[6]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + { + throw (AuthenticationException) x; + } + throw new AuthenticationException("lookup()", x); + } + return result; + } + + public void update(Map userCredentials) throws AuthenticationException + { + if (passwordFile == null) + { + throw new AuthenticationException("update()", + new IllegalStateException()); + } + try + { + String userName = (String) userCredentials.get(Registry.SASL_USERNAME); + String password = (String) userCredentials.get(Registry.SASL_PASSWORD); + String uid = (String) userCredentials.get(CramMD5Registry.UID_FIELD); + String gid = (String) userCredentials.get(CramMD5Registry.GID_FIELD); + String gecos = (String) userCredentials.get(CramMD5Registry.GECOS_FIELD); + String dir = (String) userCredentials.get(CramMD5Registry.DIR_FIELD); + String shell = (String) userCredentials.get(CramMD5Registry.SHELL_FIELD); + if (uid == null || gid == null || gecos == null || dir == null + || shell == null) + { + passwordFile.changePasswd(userName, password); + } + else + { + String[] attributes = new String[] { uid, gid, gecos, dir, shell }; + passwordFile.add(userName, password, attributes); + } + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + { + throw (AuthenticationException) x; + } + throw new AuthenticationException("update()", x); + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + throw new AuthenticationException("", new UnsupportedOperationException()); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java b/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java new file mode 100644 index 000000000..094109ff9 --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java @@ -0,0 +1,201 @@ +/* CramMD5Client.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.sasl.ClientMechanism; + +import java.io.IOException; +import java.security.InvalidKeyException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * The CRAM-MD5 SASL client-side mechanism. + */ +public class CramMD5Client extends ClientMechanism implements SaslClient +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public CramMD5Client() + { + super(Registry.SASL_CRAM_MD5_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslClient interface implementation ----------------- + + public boolean hasInitialResponse() + { + return false; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + if (challenge == null) + { + throw new SaslException("null challenge"); + } + try + { + final String username; + final char[] password; + Callback[] callbacks; + + if ((!properties.containsKey(Registry.SASL_USERNAME)) + && (!properties.containsKey(Registry.SASL_PASSWORD))) + { + callbacks = new Callback[2]; + + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + { + nameCB = new NameCallback("username: "); + } + else + { + nameCB = new NameCallback("username: ", defaultName); + } + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + callbacks[0] = nameCB; + callbacks[1] = pwdCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + password = pwdCB.getPassword(); + } + else + { + if (properties.containsKey(Registry.SASL_USERNAME)) + { + username = (String) properties.get(Registry.SASL_USERNAME); + } + else + { + callbacks = new Callback[1]; + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + { + nameCB = new NameCallback("username: "); + } + else + { + nameCB = new NameCallback("username: ", defaultName); + } + callbacks[0] = nameCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + } + + if (properties.containsKey(Registry.SASL_PASSWORD)) + { + password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray(); + } + else + { + callbacks = new Callback[1]; + final PasswordCallback pwdCB = new PasswordCallback( + "password: ", + false); + callbacks[0] = pwdCB; + this.handler.handle(callbacks); + password = pwdCB.getPassword(); + } + } + + if (password == null) + { + throw new SaslException("null password supplied"); + } + final byte[] digest; + try + { + digest = CramMD5Util.createHMac(password, challenge); + } + catch (InvalidKeyException x) + { + throw new AuthenticationException("evaluateChallenge()", x); + } + final String response = username + " " + + Util.toString(digest).toLowerCase(); + this.complete = true; + + return response.getBytes("UTF-8"); + } + catch (UnsupportedCallbackException x) + { + throw new AuthenticationException("evaluateChallenge()", x); + } + catch (IOException x) + { + throw new AuthenticationException("evaluateChallenge()", x); + } + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java b/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java new file mode 100644 index 000000000..1c61cace4 --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java @@ -0,0 +1,66 @@ +/* CramMD5Registry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +/** + * A list of properties common to CRAM-MD5 classes. + */ +public interface CramMD5Registry +{ + /** Name of the password file (used by the server) property. */ + String PASSWORD_FILE = "gnu.crypto.sasl.crammd5.password.file"; + + /** Default password file (used by the server) pathname. */ + String DEFAULT_PASSWORD_FILE = "/etc/passwd"; + + /** Name of the UID field in the plain password file. */ + String UID_FIELD = "crammd5.uid"; + + /** Name of the GID field in the plain password file. */ + String GID_FIELD = "crammd5.gid"; + + /** Name of the GECOS field in the plain password file. */ + String GECOS_FIELD = "crammd5.gecos"; + + /** Name of the DIR field in the plain password file. */ + String DIR_FIELD = "crammd5.dir"; + + /** Name of the SHELL field in the plain password file. */ + String SHELL_FIELD = "crammd5.shell"; +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java b/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java new file mode 100644 index 000000000..d6622b6db --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java @@ -0,0 +1,185 @@ +/* CramMD5Server.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + *

The CRAM-MD5 SASL server-side mechanism.

+ */ +public class CramMD5Server extends ServerMechanism implements SaslServer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private byte[] msgID; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public CramMD5Server() + { + super(Registry.SASL_CRAM_MD5_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslServer interface implementation ----------------- + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + if (state == 0) + { + msgID = CramMD5Util.createMsgID(); + state++; + return msgID; + } + + final String responseStr = new String(response); + final int index = responseStr.lastIndexOf(" "); + final String username = responseStr.substring(0, index); + final byte[] responseDigest; + try + { + responseDigest = responseStr.substring(index + 1).getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + + // Look up the password + final char[] password = lookupPassword(username); + + // Compute the digest + byte[] digest; + try + { + digest = CramMD5Util.createHMac(password, msgID); + } + catch (InvalidKeyException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + try + { + // digest = (new String(Util.toString(digest).toLowerCase())).getBytes("UTF-8"); + digest = Util.toString(digest).toLowerCase().getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("evaluateResponse()", x); + } + + // Compare the received and computed digests + if (!Arrays.equals(digest, responseDigest)) + { + throw new AuthenticationException("Digest mismatch"); + } + state++; + return null; + } + + public boolean isComplete() + { + return (state == 2); + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + // Other instance methods -------------------------------------------------- + + private char[] lookupPassword(final String userName) throws SaslException + { + try + { + if (!authenticator.contains(userName)) + { + throw new NoSuchUserException(userName); + } + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, userName); + final Map credentials = authenticator.lookup(userID); + final String password = (String) credentials.get(Registry.SASL_PASSWORD); + if (password == null) + { + throw new AuthenticationException("lookupPassword()", + new InternalError()); + } + return password.toCharArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new AuthenticationException("lookupPassword()", x); + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java b/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java new file mode 100644 index 000000000..6e7539349 --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java @@ -0,0 +1,137 @@ +/* CramMD5Util.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.mac.HMacFactory; +import gnu.javax.crypto.mac.IMac; + +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.InvalidKeyException; +import java.util.HashMap; + +import javax.security.sasl.SaslException; + +/** + * A package-private CRAM-MD5-specific utility class. + */ +class CramMD5Util +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + private CramMD5Util() + { + super(); + } + + // Class methods + // ------------------------------------------------------------------------- + + static byte[] createMsgID() throws SaslException + { + // + final String encoded; + try + { + encoded = Util.toBase64(Thread.currentThread().getName().getBytes( + "UTF-8")); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("createMsgID()", x); + } + String hostname = "localhost"; + try + { + hostname = InetAddress.getLocalHost().getHostAddress(); + } + catch (UnknownHostException ignored) + { + } + + final byte[] result; + try + { + result = new StringBuffer().append("<").append( + encoded.substring( + 0, + encoded.length())).append( + ".").append( + String.valueOf(System.currentTimeMillis())).append( + "@").append( + hostname).append( + ">").toString().getBytes( + "UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("createMsgID()", x); + } + return result; + } + + static byte[] createHMac(final char[] passwd, final byte[] data) + throws InvalidKeyException, SaslException + { + final IMac mac = HMacFactory.getInstance(Registry.HMAC_NAME_PREFIX + + Registry.MD5_HASH); + final HashMap map = new HashMap(); + final byte[] km; + try + { + km = new String(passwd).getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("createHMac()", x); + } + map.put(IMac.MAC_KEY_MATERIAL, km); + mac.init(map); + mac.update(data, 0, data.length); + return mac.digest(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/crammd5/PasswordFile.java b/gnu/javax/crypto/sasl/crammd5/PasswordFile.java new file mode 100644 index 000000000..081af4615 --- /dev/null +++ b/gnu/javax/crypto/sasl/crammd5/PasswordFile.java @@ -0,0 +1,301 @@ +/* PasswordFile.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.crammd5; + +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.UserAlreadyExistsException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + * The CRAM-MD5 password file representation. + */ +public class PasswordFile +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = System.getProperty(CramMD5Registry.PASSWORD_FILE, + CramMD5Registry.DEFAULT_PASSWORD_FILE); + } + + private HashMap entries; + + private File passwdFile; + + private long lastmod; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public PasswordFile() throws IOException + { + this(DEFAULT_FILE); + } + + public PasswordFile(final File pwFile) throws IOException + { + this(pwFile.getAbsolutePath()); + } + + public PasswordFile(final String fileName) throws IOException + { + passwdFile = new File(fileName); + update(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public synchronized void add(final String user, final String passwd, + final String[] attributes) throws IOException + { + checkCurrent(); // check if the entry exists + if (entries.containsKey(user)) + { + throw new UserAlreadyExistsException(user); + } + if (attributes.length != 5) + { + throw new IllegalArgumentException("Wrong number of attributes"); + } + + final String[] fields = new String[7]; // create the new entry + fields[0] = user; + fields[1] = passwd; + System.arraycopy(attributes, 0, fields, 2, 5); + entries.put(user, fields); + savePasswd(); + } + + public synchronized void changePasswd(final String user, final String passwd) + throws IOException + { + checkCurrent(); + if (!entries.containsKey(user)) + { // check if the entry exists + throw new NoSuchUserException(user); + } + + final String[] fields = (String[]) entries.get(user); // get the existing entry + fields[1] = passwd; // modify the password field + entries.remove(user); // delete the existing entry + entries.put(user, fields); // add the new entry + + savePasswd(); + } + + public synchronized String[] lookup(final String user) throws IOException + { + checkCurrent(); + if (!entries.containsKey(user)) + { + throw new NoSuchUserException(user); + } + return (String[]) entries.get(user); + } + + public synchronized boolean contains(final String s) throws IOException + { + checkCurrent(); + + return entries.containsKey(s); + } + + private synchronized void update() throws IOException + { + lastmod = passwdFile.lastModified(); + readPasswd(new FileInputStream(passwdFile)); + } + + private void checkCurrent() throws IOException + { + if (passwdFile.lastModified() > lastmod) + { + update(); + } + } + + private synchronized void readPasswd(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line; + entries = new HashMap(); + while ((line = din.readLine()) != null) + { + final String[] fields = new String[7]; + final StringTokenizer st = new StringTokenizer(line, ":", true); + try + { + fields[0] = st.nextToken(); // username + st.nextToken(); + + fields[1] = st.nextToken(); // passwd + if (fields[1].equals(":")) + { + fields[1] = ""; + } + else + { + st.nextToken(); + } + + fields[2] = st.nextToken(); // uid + if (fields[2].equals(":")) + { + fields[2] = ""; + } + else + { + st.nextToken(); + } + + fields[3] = st.nextToken(); // gid + if (fields[3].equals(":")) + { + fields[3] = ""; + } + else + { + st.nextToken(); + } + + fields[4] = st.nextToken(); // gecos + if (fields[4].equals(":")) + { + fields[4] = ""; + } + else + { + st.nextToken(); + } + + fields[5] = st.nextToken(); // dir + if (fields[5].equals(":")) + { + fields[5] = ""; + } + else + { + st.nextToken(); + } + + fields[6] = st.nextToken(); // shell + if (fields[6].equals(":")) + { + fields[6] = ""; + } + } + catch (NoSuchElementException x) + { + continue; + } + + entries.put(fields[0], fields); + } + } + + private synchronized void savePasswd() throws IOException + { + if (passwdFile != null) + { + final FileOutputStream fos = new FileOutputStream(passwdFile); + PrintWriter pw = null; + try + { + pw = new PrintWriter(fos); + String key; + String[] fields; + StringBuffer sb; + int i; + for (Iterator it = entries.keySet().iterator(); it.hasNext();) + { + key = (String) it.next(); + fields = (String[]) entries.get(key); + sb = new StringBuffer(fields[0]); + for (i = 1; i < fields.length; i++) + { + sb.append(":").append(fields[i]); + } + pw.println(sb.toString()); + } + } + finally + { + if (pw != null) + { + try + { + pw.flush(); + } + finally + { + pw.close(); + } + } + try + { + fos.close(); + } + catch (IOException ignored) + { + } + lastmod = passwdFile.lastModified(); + } + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/plain/PasswordFile.java b/gnu/javax/crypto/sasl/plain/PasswordFile.java new file mode 100644 index 000000000..4ef6b8541 --- /dev/null +++ b/gnu/javax/crypto/sasl/plain/PasswordFile.java @@ -0,0 +1,309 @@ +/* PasswordFile.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.plain; + +import gnu.classpath.SystemProperties; + +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.UserAlreadyExistsException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.StringTokenizer; +import java.util.NoSuchElementException; + +/** + * A representation of a Plain password file. + */ +public class PasswordFile +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = SystemProperties.getProperty(PlainRegistry.PASSWORD_FILE, + PlainRegistry.DEFAULT_PASSWORD_FILE); + } + + private Hashtable entries; + + private File passwdFile; + + // private String[] last_params; + private long lastmod; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public PasswordFile() throws IOException + { + this(DEFAULT_FILE); + } + + public PasswordFile(File pwFile) throws IOException + { + this(pwFile.getAbsolutePath()); + } + + public PasswordFile(String fileName) throws IOException + { + passwdFile = new File(fileName); + update(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + public synchronized void add(String user, String passwd, String[] attributes) + throws IOException + { + checkCurrent(); + if (entries.containsKey(user)) + { + throw new UserAlreadyExistsException(user); + } + if (attributes.length != 5) + { + throw new IllegalArgumentException("Wrong number of attributes"); + } + // create the new entry + String[] fields = new String[7]; + fields[0] = user; + fields[1] = passwd; + System.arraycopy(attributes, 0, fields, 2, 5); + entries.put(user, fields); + + savePasswd(); + } + + public synchronized void changePasswd(String user, String passwd) + throws IOException + { + checkCurrent(); + if (!entries.containsKey(user)) + { + throw new NoSuchUserException(user); + } + + String[] fields = (String[]) entries.get(user); // get the existing entry + fields[1] = passwd; // modify the password field + entries.remove(user); // delete the existing entry + entries.put(user, fields); // add the new entry + + savePasswd(); + } + + public synchronized String[] lookup(String user) throws IOException + { + checkCurrent(); + if (!entries.containsKey(user)) + { + throw new NoSuchUserException(user); + } + return (String[]) entries.get(user); + } + + public synchronized boolean contains(String s) throws IOException + { + checkCurrent(); + return entries.containsKey(s); + } + + //----------------------------------------------------------------// + + private synchronized void update() throws IOException + { + lastmod = passwdFile.lastModified(); + readPasswd(new FileInputStream(passwdFile)); + } + + private void checkCurrent() throws IOException + { + if (passwdFile.lastModified() > lastmod) + { + update(); + } + } + + private synchronized void readPasswd(InputStream in) throws IOException + { + BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line; + entries = new Hashtable(); + String[] fields = new String[7]; + while ((line = din.readLine()) != null) + { + StringTokenizer st = new StringTokenizer(line, ":", true); + try + { + fields[0] = st.nextToken(); // username + st.nextToken(); + + fields[1] = st.nextToken(); // passwd + if (fields[1].equals(":")) + { + fields[1] = ""; + } + else + { + st.nextToken(); + } + + fields[2] = st.nextToken(); // uid + if (fields[2].equals(":")) + { + fields[2] = ""; + } + else + { + st.nextToken(); + } + + fields[3] = st.nextToken(); // gid + if (fields[3].equals(":")) + { + fields[3] = ""; + } + else + { + st.nextToken(); + } + + fields[4] = st.nextToken(); // gecos + if (fields[4].equals(":")) + { + fields[4] = ""; + } + else + { + st.nextToken(); + } + + fields[5] = st.nextToken(); // dir + if (fields[5].equals(":")) + { + fields[5] = ""; + } + else + { + st.nextToken(); + } + + fields[6] = st.nextToken(); // shell + if (fields[6].equals(":")) + { + fields[6] = ""; + } + } + catch (NoSuchElementException ignored) + { + continue; + } + + entries.put(fields[0], fields); + } + } + + private synchronized void savePasswd() throws IOException + { + if (passwdFile != null) + { + FileOutputStream fos = new FileOutputStream(passwdFile); + PrintWriter pw = null; + try + { + pw = new PrintWriter(fos); + String key; + String[] fields; + StringBuffer sb; + Enumeration keys = entries.keys(); + while (keys.hasMoreElements()) + { + key = (String) keys.nextElement(); + fields = (String[]) entries.get(key); + sb = new StringBuffer(fields[0]); + for (int i = 1; i < fields.length; i++) + { + sb.append(":" + fields[i]); + } + pw.println(sb.toString()); + } + } + finally + { + if (pw != null) + { + try + { + pw.flush(); + } + finally + { + pw.close(); + } + } + if (fos != null) + { + try + { + fos.close(); + } + catch (IOException ignored) + { + } + } + lastmod = passwdFile.lastModified(); + } + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java b/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java new file mode 100644 index 000000000..9882ce9bb --- /dev/null +++ b/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java @@ -0,0 +1,206 @@ +/* PlainAuthInfoProvider.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.plain; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.IAuthInfoProvider; +import gnu.javax.crypto.sasl.NoSuchUserException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + * The PLAIN mechanism authentication information provider implementation. + */ +public class PlainAuthInfoProvider implements IAuthInfoProvider, PlainRegistry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private PasswordFile passwordFile = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-args constrcutor + + // Class methods + // ------------------------------------------------------------------------- + + // IAuthInfoProvider interface implementation + // ------------------------------------------------------------------------- + + public void activate(Map context) throws AuthenticationException + { + try + { + if (context == null) + { + passwordFile = new PasswordFile(); + } + else + { + String pfn = (String) context.get(PASSWORD_FILE); + if (pfn == null) + { + passwordFile = new PasswordFile(); + } + else + { + passwordFile = new PasswordFile(pfn); + } + } + } + catch (IOException x) + { + throw new AuthenticationException("activate()", x); + } + } + + public void passivate() throws AuthenticationException + { + passwordFile = null; + } + + public boolean contains(String userName) throws AuthenticationException + { + if (passwordFile == null) + { + throw new AuthenticationException("contains()", + new IllegalStateException()); + } + boolean result = false; + try + { + result = passwordFile.contains(userName); + } + catch (IOException x) + { + throw new AuthenticationException("contains()", x); + } + return result; + } + + public Map lookup(Map userID) throws AuthenticationException + { + if (passwordFile == null) + { + throw new AuthenticationException("lookup()", + new IllegalStateException()); + } + Map result = new HashMap(); + try + { + String userName = (String) userID.get(Registry.SASL_USERNAME); + if (userName == null) + { + throw new NoSuchUserException(""); + } + String[] data = passwordFile.lookup(userName); + result.put(Registry.SASL_USERNAME, data[0]); + result.put(Registry.SASL_PASSWORD, data[1]); + result.put(UID_FIELD, data[2]); + result.put(GID_FIELD, data[3]); + result.put(GECOS_FIELD, data[4]); + result.put(DIR_FIELD, data[5]); + result.put(SHELL_FIELD, data[6]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + { + throw (AuthenticationException) x; + } + else + { + throw new AuthenticationException("lookup()", x); + } + } + return result; + } + + public void update(Map userCredentials) throws AuthenticationException + { + if (passwordFile == null) + { + throw new AuthenticationException("update()", + new IllegalStateException()); + } + try + { + String userName = (String) userCredentials.get(Registry.SASL_USERNAME); + String password = (String) userCredentials.get(Registry.SASL_PASSWORD); + String uid = (String) userCredentials.get(UID_FIELD); + String gid = (String) userCredentials.get(GID_FIELD); + String gecos = (String) userCredentials.get(GECOS_FIELD); + String dir = (String) userCredentials.get(DIR_FIELD); + String shell = (String) userCredentials.get(SHELL_FIELD); + if (uid == null || gid == null || gecos == null || dir == null + || shell == null) + { + passwordFile.changePasswd(userName, password); + } + else + { + String[] attributes = new String[] { uid, gid, gecos, dir, shell }; + passwordFile.add(userName, password, attributes); + } + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + { + throw (AuthenticationException) x; + } + else + { + throw new AuthenticationException("update()", x); + } + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + throw new AuthenticationException("", new UnsupportedOperationException()); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/plain/PlainClient.java b/gnu/javax/crypto/sasl/plain/PlainClient.java new file mode 100644 index 000000000..066db3770 --- /dev/null +++ b/gnu/javax/crypto/sasl/plain/PlainClient.java @@ -0,0 +1,193 @@ +/* PlainClient.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.plain; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.ClientMechanism; + +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; + +/** + *

The PLAIN SASL client-side mechanism.

+ */ +public class PlainClient extends ClientMechanism implements SaslClient +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public PlainClient() + { + super(Registry.SASL_PLAIN_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslClient interface implementation ----------------- + + public boolean hasInitialResponse() + { + return true; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + try + { + final String username; + final char[] password; + Callback[] callbacks; + + if ((!properties.containsKey(Registry.SASL_USERNAME)) + && (!properties.containsKey(Registry.SASL_PASSWORD))) + { + callbacks = new Callback[2]; + + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + { + nameCB = new NameCallback("username: "); + } + else + { + nameCB = new NameCallback("username: ", defaultName); + } + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + callbacks[0] = nameCB; + callbacks[1] = pwdCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + password = pwdCB.getPassword(); + } + else + { + if (properties.containsKey(Registry.SASL_USERNAME)) + { + username = (String) properties.get(Registry.SASL_USERNAME); + } + else + { + callbacks = new Callback[1]; + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + { + nameCB = new NameCallback("username: "); + } + else + { + nameCB = new NameCallback("username: ", defaultName); + } + callbacks[0] = nameCB; + this.handler.handle(callbacks); + username = nameCB.getName(); + } + + if (properties.containsKey(Registry.SASL_PASSWORD)) + { + password = ((String) properties.get(Registry.SASL_PASSWORD)).toCharArray(); + } + else + { + callbacks = new Callback[1]; + final PasswordCallback pwdCB = new PasswordCallback( + "password: ", + false); + callbacks[0] = pwdCB; + this.handler.handle(callbacks); + password = pwdCB.getPassword(); + } + } + + if (password == null) + { + throw new SaslException("null password supplied"); + } + final StringBuffer sb = new StringBuffer(); + if (authorizationID != null) + { + sb.append(authorizationID); + } + sb.append('\0'); + sb.append(username); + sb.append('\0'); + sb.append(password); + this.complete = true; + + final byte[] response = sb.toString().getBytes("UTF-8"); + return response; + } + catch (Exception x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("evaluateChallenge()", x); + } + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/plain/PlainRegistry.java b/gnu/javax/crypto/sasl/plain/PlainRegistry.java new file mode 100644 index 000000000..0b48c0ad3 --- /dev/null +++ b/gnu/javax/crypto/sasl/plain/PlainRegistry.java @@ -0,0 +1,67 @@ +/* PlainRegistry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.plain; + +public interface PlainRegistry +{ + + // Constants + // ------------------------------------------------------------------------- + + /** Name of PLAIN password file property. */ + String PASSWORD_FILE = "gnu.crypto.sasl.plain.password.file"; + + /** Default fully qualified pathname of the PLAIN password file. */ + String DEFAULT_PASSWORD_FILE = "/etc/tpasswd"; + + /** Name of the UID field in the plain password file. */ + String UID_FIELD = "plain.uid"; + + /** Name of the GID field in the plain password file. */ + String GID_FIELD = "plain.gid"; + + /** Name of the GECOS field in the plain password file. */ + String GECOS_FIELD = "plain.gecos"; + + /** Name of the DIR field in the plain password file. */ + String DIR_FIELD = "plain.dir"; + + /** Name of the SHELL field in the plain password file. */ + String SHELL_FIELD = "plain.shell"; +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/plain/PlainServer.java b/gnu/javax/crypto/sasl/plain/PlainServer.java new file mode 100644 index 000000000..205688473 --- /dev/null +++ b/gnu/javax/crypto/sasl/plain/PlainServer.java @@ -0,0 +1,196 @@ +/* PlainServer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.plain; + +import gnu.java.security.Registry; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + *

The PLAIN SASL server-side mechanism.

+ */ +public class PlainServer extends ServerMechanism implements SaslServer +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // Constructor(s) + // ------------------------------------------------------------------------- + + public PlainServer() + { + super(Registry.SASL_PLAIN_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + // javax.security.sasl.SaslServer interface implementation ----------------- + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + if (response == null) + { + return null; + } + try + { + final String nullStr = new String("\0"); + final StringTokenizer strtok = new StringTokenizer( + new String(response), + nullStr, true); + + authorizationID = strtok.nextToken(); + if (!authorizationID.equals(nullStr)) + { + strtok.nextToken(); + } + else + { + authorizationID = null; + } + final String id = strtok.nextToken(); + if (id.equals(nullStr)) + { + throw new SaslException("No identity given"); + } + if (authorizationID == null) + { + authorizationID = id; + } + if ((!authorizationID.equals(nullStr)) && (!authorizationID.equals(id))) + { + throw new SaslException("Delegation not supported"); + } + strtok.nextToken(); + final byte[] pwd; + try + { + pwd = strtok.nextToken().getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("evaluateResponse()", x); + } + if (pwd == null) + { + throw new SaslException("No password given"); + } + final byte[] password; + try + { + password = new String(lookupPassword(id)).getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new SaslException("evaluateResponse()", x); + } + if (!Arrays.equals(pwd, password)) + { + throw new SaslException("Password incorrect"); + } + this.complete = true; + return null; + } + catch (NoSuchElementException x) + { + throw new SaslException("evaluateResponse()", x); + } + } + + protected String getNegotiatedQOP() + { + return Registry.QOP_AUTH; + } + + // other methods ----------------------------------------------------------- + + private char[] lookupPassword(final String userName) throws SaslException + { + try + { + if (!authenticator.contains(userName)) + { + throw new NoSuchUserException(userName); + } + final Map userID = new HashMap(); + userID.put(Registry.SASL_USERNAME, userName); + final Map credentials = authenticator.lookup(userID); + final String password = (String) credentials.get(Registry.SASL_PASSWORD); + if (password == null) + { + throw new SaslException("lookupPassword()", new InternalError()); + } + return password.toCharArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("lookupPassword()", x); + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/CALG.java b/gnu/javax/crypto/sasl/srp/CALG.java new file mode 100644 index 000000000..6215783d6 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/CALG.java @@ -0,0 +1,292 @@ +/* CALG.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.javax.crypto.assembly.Assembly; +import gnu.javax.crypto.assembly.Cascade; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.assembly.Stage; +import gnu.javax.crypto.assembly.Transformer; +import gnu.javax.crypto.assembly.TransformerException; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.IPad; +import gnu.javax.crypto.pad.PadFactory; +import gnu.javax.crypto.sasl.ConfidentialityException; + +import java.util.HashMap; + +import javax.security.sasl.SaslException; + +/** + *

A Factory class that returns CALG (Confidentiality Algorithm) instances + * that operate as described in the draft-burdis-cat-sasl-srp-08.

+ * + *

The designated CALG block cipher should be used in OFB (Output Feedback + * Block) mode in the ISO variant, as described in The Handbook of Applied + * Cryptography, algorithm 7.20.

+ * + *

Let k be the block size of the chosen symmetric key block + * cipher algorithm; e.g. for AES this is 128 bits or 16 + * octets. The OFB mode used shall be of length/size k.

+ * + *

It is recommended that block ciphers operating in OFB mode be used with an + * Initial Vector (the mode's IV). In such a mode of operation - OFB with key + * re-use - the IV need not be secret. For the mechanism in question the IVs + * shall be a random octet sequence of k bytes.

+ * + * The input data to the confidentiality protection algorithm shall be + * a multiple of the symmetric cipher block size k. When the input + * length is not a multiple of k octets, the data shall be padded + * according to the following scheme:

+ * + *

Assuming the length of the input is l octets, + * (k - (l mod k)) octets, all having the value + * (k - (l mod k)), shall be appended to the original data. In + * other words, the input is padded at the trailing end with one of the + * following sequences:

+ * + *
+ *
+ *                    01 -- if l mod k = k-1
+ *                   02 02 -- if l mod k = k-2
+ *                             ...
+ *                             ...
+ *                             ...
+ *                 k k ... k k -- if l mod k = 0
+ *
+ * + *

The padding can be removed unambiguously since all input is padded and no + * padding sequence is a suffix of another. This padding method is well-defined + * if and only if k < 256 octets, which is the case with + * symmetric key block ciphers today, and in the forseeable future.

+ */ +public final class CALG +{ + + // Constants and variables + // -------------------------------------------------------------------------- + + private Assembly assembly; + + private Object modeNdx; // initialisation key of the cascade's attributes + + private int blockSize; // the underlying cipher's blocksize == IV length + + private int keySize; // the underlying cipher's key size (in bytes). + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** Private constructor to enforce instantiation through Factory method. */ + private CALG(final int blockSize, final int keySize, final Object modeNdx, + final Assembly assembly) + { + super(); + + this.blockSize = blockSize; + this.keySize = keySize; + this.modeNdx = modeNdx; + this.assembly = assembly; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a SASL-SRP CALG implementation.

+ * + * @param algorithm the name of the symmetric cipher algorithm. + * @return an instance of this object. + */ + static synchronized CALG getInstance(final String algorithm) + { + final IBlockCipher cipher = CipherFactory.getInstance(algorithm); + final int blockSize = cipher.defaultBlockSize(); + final int keySize = cipher.defaultKeySize(); + final Cascade ofbCipher = new Cascade(); + final Object modeNdx = ofbCipher.append(Stage.getInstance( + ModeFactory.getInstance( + Registry.OFB_MODE, + cipher, + blockSize), + Direction.FORWARD)); + final IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD); + // the passed IV may be longer that what we need. ensure correct length + // byte[] realIV = null; + // if (iv.length == blockSize) { + // realIV = iv; + // } else { + // realIV = new byte[blockSize]; + // if (iv.length > blockSize) { + // System.arraycopy(iv, 0, realIV, 0, blockSize); + // } else { // shouldnt happen + // System.arraycopy(iv, 0, realIV, 0, iv.length); + // } + // } + + // HashMap modeAttributes = new HashMap(); + // modeAttributes.put(IBlockCipher.KEY_MATERIAL, K.clone()); + // modeAttributes.put(IMode.IV, realIV); + + final Assembly asm = new Assembly(); + asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher)); + asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7)); + + // HashMap attributes = new HashMap(); + // attributes.put(Assembly.DIRECTION, dir); + // attributes.put(modeNdx, modeAttributes); + // try { + // asm.init(attributes); + // } catch (TransformerException x) { + // throw new SaslException("getInstance()", x); + // } + + return new CALG(blockSize, keySize, modeNdx, asm); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Initialises a SASL-SRP CALG implementation.

+ * + * @param kdf the key derivation function. + * @param iv the initial vector value to use. + * @param dir whether this CALG is used for encryption or decryption. + */ + // public void init(byte[] K, byte[] iv, Direction dir) throws SaslException { + public void init(final KDF kdf, final byte[] iv, final Direction dir) + throws SaslException + { + // IBlockCipher cipher = CipherFactory.getInstance(algorithm); + // int blockSize = cipher.defaultBlockSize(); + // Cascade ofbCipher = new Cascade(); + // Object modeNdx = ofbCipher.append( + // Stage.getInstace( + // ModeFactory.getInstance(Registry.OFB_MODE, cipher, blockSize), + // Direction.FORWARD)); + // IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD); + // the passed IV may be longer that what we need. ensure correct length + final byte[] realIV; + if (iv.length == blockSize) + { + realIV = iv; + } + else + { + realIV = new byte[blockSize]; + if (iv.length > blockSize) + { + System.arraycopy(iv, 0, realIV, 0, blockSize); + } + else + { // shouldnt happen + System.arraycopy(iv, 0, realIV, 0, iv.length); + } + } + + final HashMap modeAttributes = new HashMap(); + // modeAttributes.put(IBlockCipher.KEY_MATERIAL, K.clone()); + final byte[] sk = kdf.derive(keySize); + modeAttributes.put(IBlockCipher.KEY_MATERIAL, sk); + //System.out.println("**** Initialised CALG with: "+gnu.crypto.util.Util.dumpString(sk)); + modeAttributes.put(IMode.IV, realIV); + + // Assembly asm = new Assembly(); + // asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher)); + // asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7)); + + final HashMap attributes = new HashMap(); + attributes.put(Assembly.DIRECTION, dir); + attributes.put(modeNdx, modeAttributes); + try + { + // asm.init(attributes); + assembly.init(attributes); + } + catch (TransformerException x) + { + throw new SaslException("getInstance()", x); + } + + // return new CALG(asm); + } + + /** + *

Encrypts or decrypts, depending on the mode already set, a designated + * array of bytes and returns the result.

+ * + * @param data the data to encrypt/decrypt. + * @return the decrypted/encrypted result. + * @throws ConfidentialityException if an exception occurs duirng the process. + */ + public byte[] doFinal(final byte[] data) throws ConfidentialityException + { + return doFinal(data, 0, data.length); + } + + /** + *

Encrypts or decrypts, depending on the mode already set, a designated + * array of bytes and returns the result.

+ * + * @param data the data to encrypt/decrypt. + * @param offset where to start in data. + * @param length how many bytes to consider in data. + * @return the decrypted/encrypted result. + * @throws ConfidentialityException if an exception occurs duirng the process. + */ + public byte[] doFinal(final byte[] data, final int offset, final int length) + throws ConfidentialityException + { + final byte[] result; + try + { + result = assembly.lastUpdate(data, offset, length); + } + catch (TransformerException x) + { + throw new ConfidentialityException("doFinal()", x); + } + return result; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/ClientStore.java b/gnu/javax/crypto/sasl/srp/ClientStore.java new file mode 100644 index 000000000..ce16f4aa7 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/ClientStore.java @@ -0,0 +1,173 @@ +/* ClientStore.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import java.util.HashMap; + +/** + *

The client-side implementation of the SRP security context store.

+ */ +public class ClientStore +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The underlying singleton. */ + private static ClientStore singleton = null; + + /** The map of uid --> SASL Security Context record. */ + private static final HashMap uid2ssc = new HashMap(); + + /** The map of sid --> Session timing record. */ + private static final HashMap uid2ttl = new HashMap(); + + /** A synchronisation lock. */ + private static final Object lock = new Object(); + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Private constructor to enforce Singleton pattern. */ + private ClientStore() + { + super(); + + // TODO: add a cleaning timer thread + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns the classloader Singleton.

+ * + * @return the classloader Singleton instance. + */ + static synchronized final ClientStore instance() + { + if (singleton == null) + { + singleton = new ClientStore(); + } + return singleton; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns a boolean flag indicating if the designated client's session is + * still alive or not.

+ * + * @param uid the identifier of the client whose session to check. + * @return true if the designated client's session is still + * alive. false otherwise. + */ + boolean isAlive(final String uid) + { + final boolean result; + synchronized (lock) + { + final Object obj = uid2ssc.get(uid); + result = (obj != null); + if (result) + { // is it still alive? + final StoreEntry sto = (StoreEntry) uid2ttl.get(uid); + if (!sto.isAlive()) + { // invalidate it + uid2ssc.remove(uid); + uid2ttl.remove(uid); + } + } + } + return result; + } + + /** + *

Records a mapping between a client's unique identifier and its security + * context.

+ * + * @param uid the unique identifier of the SRP client for which the session + * is to be cached. + * @param ttl the session's Time-To-Live indicator (in seconds). + * @param ctx the client's security context. + */ + void cacheSession(final String uid, final int ttl, final SecurityContext ctx) + { + synchronized (lock) + { + uid2ssc.put(uid, ctx); + uid2ttl.put(uid, new StoreEntry(ttl)); + } + } + + /** + *

Removes the mapping between the designated SRP client unique identifier + * and the its session security context (and other timing information).

+ * + * @param uid the identifier of the client whose session is to invalidate. + */ + void invalidateSession(final String uid) + { + synchronized (lock) + { + uid2ssc.remove(uid); + uid2ttl.remove(uid); + } + } + + /** + *

Returns an SRP client's security context record mapped by that client's + * unique identifier.

+ * + * @param uid the identifier of the client whose session is to restore. + * @return the SRP client's security context. + */ + SecurityContext restoreSession(final String uid) + { + final SecurityContext result; + synchronized (lock) + { + result = (SecurityContext) uid2ssc.remove(uid); + uid2ttl.remove(uid); + } + return result; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/IALG.java b/gnu/javax/crypto/sasl/srp/IALG.java new file mode 100644 index 000000000..2c65dfda1 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/IALG.java @@ -0,0 +1,159 @@ +/* IALG.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; + +import javax.security.sasl.SaslException; + +/** + *

A Factory class that returns IALG (Integrity Algorithm) instances that + * operate as described in the draft-burdis-cat-sasl-srp-04 and later.

+ * + * @version $Revision: 1.1.4.1 $ + */ +public final class IALG implements Cloneable +{ + + // Constants and variables + // -------------------------------------------------------------------------- + + private IMac hmac; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** Private constructor to enforce instantiation through Factory method. */ + private IALG(final IMac hmac) + { + super(); + + this.hmac = hmac; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of a SASL-SRP IALG implementation.

+ * + * @param algorithm the name of the HMAC algorithm. + * @return an instance of this object. + */ + static synchronized IALG getInstance(final String algorithm) + throws SaslException + { + final IMac hmac; + hmac = MacFactory.getInstance(algorithm); + if (hmac == null) + { + throw new SaslException("getInstance()", + new NoSuchAlgorithmException(algorithm)); + } + // try { + // byte[] sk = (byte[]) K.clone(); + // HashMap map = new HashMap(); + // map.put(IMac.MAC_KEY_MATERIAL, sk); + // hmac.init(map); + // } catch (InvalidKeyException x) { + // throw new SaslException("getInstance()", x); + // } + return new IALG(hmac); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // Cloneable interface implementation -------------------------------------- + + public Object clone() throws CloneNotSupportedException + { + return new IALG((IMac) hmac.clone()); + } + + // other methdds ----------------------------------------------------------- + + // public void init(final byte[] K) throws SaslException { + public void init(final KDF kdf) throws SaslException + { + try + { + // final byte[] sk = (byte[]) K.clone(); + final byte[] sk = kdf.derive(hmac.macSize()); + final HashMap map = new HashMap(); + map.put(IMac.MAC_KEY_MATERIAL, sk); + hmac.init(map); + //System.out.println("**** Initialised IALG with: "+gnu.crypto.util.Util.dumpString(sk)); + } + catch (InvalidKeyException x) + { + throw new SaslException("getInstance()", x); + } + } + + public void update(final byte[] data) + { + hmac.update(data, 0, data.length); + } + + public void update(final byte[] data, final int offset, final int length) + { + hmac.update(data, offset, length); + } + + public byte[] doFinal() + { + return hmac.digest(); + } + + /** + *

Returns the length (in bytes) of this SASL SRP Integrity Algorithm.

+ * + * @return the length, in bytes, of this integrity protection algorithm. + */ + public int length() + { + return hmac.macSize(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/KDF.java b/gnu/javax/crypto/sasl/srp/KDF.java new file mode 100644 index 000000000..0d5eeacd1 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/KDF.java @@ -0,0 +1,169 @@ +/* KDF.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.util.HashMap; + +/** + *

The SASL-SRP KDF implementation, which is also used, depending on how it + * was instantiated, as a secure Pseudo Random Number Generator.

+ */ +public class KDF +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private static final int AES_BLOCK_SIZE = 16; // default block size for the AES + + private static final int AES_KEY_SIZE = 16; // default key size for the AES + + private static final byte[] buffer = new byte[1]; + + /** Our default source of randomness. */ + private static final PRNG prng = PRNG.getInstance(); + + /** The shared secret K to use. */ + // private byte[] keyMaterial; + /** The underlying UMAC Generator instance. */ + private UMacGenerator umac = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Constructs an instance of the KDF initialised with the + * designated shared secret bytes.

+ * + * @param keyMaterial the SASL SRP shared secret (K) bytes. + */ + private KDF(final byte[] keyMaterial, final int ndx) + { + super(); + + // if (ndx != 0) { + // this.keyMaterial = (byte[]) keyMaterial.clone(); + // } + final HashMap map = new HashMap(); + map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + map.put(UMacGenerator.INDEX, new Integer(ndx)); + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, new Integer(AES_BLOCK_SIZE)); + final byte[] key = new byte[AES_KEY_SIZE]; + System.arraycopy(keyMaterial, 0, key, 0, AES_KEY_SIZE); + map.put(IBlockCipher.KEY_MATERIAL, key); + + umac = new UMacGenerator(); + umac.init(map); + //System.out.println("**** Initialised KDF with: "+gnu.crypto.util.Util.dumpString(key)); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

A Factory mehod that returns an instance of a KDF based on + * supplied seed data.

+ * + * @param K the SASL SRP shared secret for a KDF to be used for + * CALG and IALG setup. null otherwise. + * @return an instance of a KDF. + */ + static final KDF getInstance(final byte[] K) + { + int ndx = -1; + final byte[] keyMaterial; + if (K != null) + { + keyMaterial = K; + ndx = 0; + } + else + { + keyMaterial = new byte[AES_BLOCK_SIZE]; + while (ndx < 1 || ndx > 255) + ndx = (byte) nextByte(); + } + return new KDF(keyMaterial, ndx); + } + + private static synchronized final int nextByte() + { + prng.nextBytes(buffer); + return (buffer[0] & 0xFF); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns a designated number of bytes suitable for use in the SASL SRP + * mechanism.

+ * + * @param length the number of bytes needed. + * @return a byte array containing the generated/selected bytes. + */ + public synchronized byte[] derive(final int length) + { + final byte[] result = new byte[length]; + // if (keyMaterial == null || length > keyMaterial.length) { + try + { + umac.nextBytes(result, 0, length); + } + catch (IllegalStateException x) + { // should not happen + x.printStackTrace(System.err); + } + catch (LimitReachedException x) + { // idem + x.printStackTrace(System.err); + } + // } else { + // System.arraycopy(keyMaterial, 0, result, 0, length); + // } + + return result; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/PasswordFile.java b/gnu/javax/crypto/sasl/srp/PasswordFile.java new file mode 100644 index 000000000..1628a4167 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/PasswordFile.java @@ -0,0 +1,699 @@ +/* PasswordFile.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; +import gnu.javax.crypto.key.srp6.SRPAlgorithm; +import gnu.javax.crypto.sasl.NoSuchUserException; +import gnu.javax.crypto.sasl.UserAlreadyExistsException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + *

The implementation of SRP password files.

+ * + *

For SRP, there are three (3) files: + *

    + *
  1. The password configuration file: tpasswd.conf. It contains the pairs + * <N,g> indexed by a number for each pair used for a user. By default, + * this file's pathname is constructed from the base password file pathname + * by prepending it with the ".conf" suffix.
  2. + * + *
  3. The base password file: tpasswd. It contains the related password + * entries for all the users with values computed using SRP's default + * message digest algorithm: SHA-1 (with 160-bit output block size).
  4. + * + *
  5. The extended password file: tpasswd2. Its name, by default, is + * constructed by adding the suffix "2" to the fully qualified pathname of + * the base password file. It contains, in addition to the same fields as + * the base password file, albeit with a different verifier value, an extra + * field identifying the message digest algorithm used to compute this + * (verifier) value.
  6. + *

+ * + *

This implementation assumes the following message digest algorithm codes: + *

    + *
  • 0: the default hash algorithm, which is SHA-1 (or its alias SHA-160).
  • + *
  • 1: MD5.
  • + *
  • 2: RIPEMD-128.
  • + *
  • 3: RIPEMD-160.
  • + *
  • 4: SHA-256.
  • + *
  • 5: SHA-384.
  • + *
  • 6: SHA-512.
  • + *

+ * + *

IMPORTANT: This method computes the verifiers as described in + * RFC-2945, which differs from the description given on the web page for + * SRP-6.

+ * + *

Reference:

+ *
    + *
  1. SRP Protocol Design
    + * Thomas J. Wu.
  2. + *
+ */ +public class PasswordFile +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + // names of property keys used in this class + private static final String USER_FIELD = "user"; + + private static final String VERIFIERS_FIELD = "verifier"; + + private static final String SALT_FIELD = "salt"; + + private static final String CONFIG_FIELD = "config"; + + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = System.getProperty(SRPRegistry.PASSWORD_FILE, + SRPRegistry.DEFAULT_PASSWORD_FILE); + } + + /** The SRP algorithm instances used by this object. */ + private static final HashMap srps; + static + { + final HashMap map = new HashMap(SRPRegistry.SRP_ALGORITHMS.length); + // The first entry MUST exist. The others are optional. + map.put("0", SRP.instance(SRPRegistry.SRP_ALGORITHMS[0])); + for (int i = 1; i < SRPRegistry.SRP_ALGORITHMS.length; i++) + { + try + { + map.put(String.valueOf(i), + SRP.instance(SRPRegistry.SRP_ALGORITHMS[i])); + } + catch (Exception x) + { + System.err.println("Ignored: " + x); + x.printStackTrace(System.err); + } + } + srps = map; + } + + private String confName, pwName, pw2Name; + + private File configFile, passwdFile, passwd2File; + + private long lastmodPasswdFile, lastmodPasswd2File; + + private HashMap entries = new HashMap(); + + private HashMap configurations = new HashMap(); + + // default N values to use when creating a new password.conf file + private static final BigInteger[] Nsrp = new BigInteger[] { + SRPAlgorithm.N_2048, + SRPAlgorithm.N_1536, + SRPAlgorithm.N_1280, + SRPAlgorithm.N_1024, + SRPAlgorithm.N_768, + SRPAlgorithm.N_640, + SRPAlgorithm.N_512 }; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public PasswordFile() throws IOException + { + this(DEFAULT_FILE); + } + + public PasswordFile(final File pwFile) throws IOException + { + this(pwFile.getAbsolutePath()); + } + + public PasswordFile(final String pwName) throws IOException + { + this(pwName, pwName + "2", pwName + ".conf"); + } + + public PasswordFile(final String pwName, final String confName) + throws IOException + { + this(pwName, pwName + "2", confName); + } + + public PasswordFile(final String pwName, final String pw2Name, + final String confName) throws IOException + { + super(); + + this.pwName = pwName; + this.pw2Name = pw2Name; + this.confName = confName; + + readOrCreateConf(); + update(); + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns a string representing the decimal value of an integer + * identifying the message digest algorithm to use for the SRP computations. + *

+ * + * @param mdName the canonical name of a message digest algorithm. + * @return a string representing the decimal value of an ID for that + * algorithm. + */ + private static final String nameToID(final String mdName) + { + if (Registry.SHA_HASH.equalsIgnoreCase(mdName) + || Registry.SHA1_HASH.equalsIgnoreCase(mdName) + || Registry.SHA160_HASH.equalsIgnoreCase(mdName)) + { + return "0"; + } + else if (Registry.MD5_HASH.equalsIgnoreCase(mdName)) + { + return "1"; + } + else if (Registry.RIPEMD128_HASH.equalsIgnoreCase(mdName)) + { + return "2"; + } + else if (Registry.RIPEMD160_HASH.equalsIgnoreCase(mdName)) + { + return "3"; + } + else if (Registry.SHA256_HASH.equalsIgnoreCase(mdName)) + { + return "4"; + } + else if (Registry.SHA384_HASH.equalsIgnoreCase(mdName)) + { + return "5"; + } + else if (Registry.SHA512_HASH.equalsIgnoreCase(mdName)) + { + return "6"; + } + return "0"; + } + + // SRP password configuration file methods --------------------------------- + + /** + *

Checks if the current configuration file contains the <N, g> pair + * for the designated index.

+ * + * @param index a string representing 1-digit identification of an <N, g> + * pair used. + * @return true if the designated index is that of + * a known <N, g> pair, and false otherwise. + * @throws IOException if an exception occurs during the process. + * @see SRPRegistry#N_2048_BITS + * @see SRPRegistry#N_1536_BITS + * @see SRPRegistry#N_1280_BITS + * @see SRPRegistry#N_1024_BITS + * @see SRPRegistry#N_768_BITS + * @see SRPRegistry#N_640_BITS + * @see SRPRegistry#N_512_BITS + */ + public synchronized boolean containsConfig(final String index) + throws IOException + { + checkCurrent(); + return configurations.containsKey(index); + } + + /** + *

Returns a pair of strings representing the pair of N and + * g MPIs for the designated index.

+ * + * @param index a string representing 1-digit identification of an <N, g> + * pair to look up. + * @return a pair of strings, arranged in an array, where the first (at index + * position #0) is the repesentation of the MPI N, and the + * second (at index position #1) is the representation of the MPI + * g. If the index refers to an unknown pair, then + * an empty string array is returned. + * @throws IOException if an exception occurs during the process. + */ + public synchronized String[] lookupConfig(final String index) + throws IOException + { + checkCurrent(); + String[] result = null; + if (configurations.containsKey(index)) + { + result = (String[]) configurations.get(index); + } + return result; + } + + // SRP base and extended password configuration files methods -------------- + + public synchronized boolean contains(final String user) throws IOException + { + checkCurrent(); + return entries.containsKey(user); + } + + public synchronized void add(final String user, final String passwd, + final byte[] salt, final String index) + throws IOException + { + checkCurrent(); + if (entries.containsKey(user)) + { + throw new UserAlreadyExistsException(user); + } + final HashMap fields = new HashMap(4); + fields.put(USER_FIELD, user); // 0 + fields.put(VERIFIERS_FIELD, newVerifiers(user, salt, passwd, index)); // 1 + fields.put(SALT_FIELD, Util.toBase64(salt)); // 2 + fields.put(CONFIG_FIELD, index); // 3 + entries.put(user, fields); + savePasswd(); + } + + public synchronized void changePasswd(final String user, final String passwd) + throws IOException + { + checkCurrent(); + if (!entries.containsKey(user)) + { + throw new NoSuchUserException(user); + } + final HashMap fields = (HashMap) entries.get(user); + final byte[] salt; + try + { + salt = Util.fromBase64((String) fields.get(SALT_FIELD)); + } + catch (NumberFormatException x) + { + throw new IOException("Password file corrupt"); + } + final String index = (String) fields.get(CONFIG_FIELD); + fields.put(VERIFIERS_FIELD, newVerifiers(user, salt, passwd, index)); + entries.put(user, fields); + savePasswd(); + } + + public synchronized void savePasswd() throws IOException + { + final FileOutputStream f1 = new FileOutputStream(passwdFile); + final FileOutputStream f2 = new FileOutputStream(passwd2File); + PrintWriter pw1 = null; + PrintWriter pw2 = null; + try + { + pw1 = new PrintWriter(f1, true); + pw2 = new PrintWriter(f2, true); + this.writePasswd(pw1, pw2); + } + finally + { + if (pw1 != null) + { + try + { + pw1.flush(); + } + finally + { + pw1.close(); + } + } + if (pw2 != null) + { + try + { + pw2.flush(); + } + finally + { + pw2.close(); + } + } + try + { + f1.close(); + } + catch (IOException ignored) + { + } + try + { + f2.close(); + } + catch (IOException ignored) + { + } + } + lastmodPasswdFile = passwdFile.lastModified(); + lastmodPasswd2File = passwd2File.lastModified(); + } + + /** + *

Returns the triplet: verifier, salt and configuration file index, of a + * designated user, and a designated message digest algorithm name, as an + * array of strings.

+ * + * @param user the username. + * @param mdName the canonical name of the SRP's message digest algorithm. + * @return a string array containing, in this order, the BASE-64 encodings of + * the verifier, the salt and the index in the password configuration file of + * the MPIs N and g of the designated user. + */ + public synchronized String[] lookup(final String user, final String mdName) + throws IOException + { + checkCurrent(); + if (!entries.containsKey(user)) + { + throw new NoSuchUserException(user); + } + final HashMap fields = (HashMap) entries.get(user); + final HashMap verifiers = (HashMap) fields.get(VERIFIERS_FIELD); + final String salt = (String) fields.get(SALT_FIELD); + final String index = (String) fields.get(CONFIG_FIELD); + final String verifier = (String) verifiers.get(nameToID(mdName)); + return new String[] { verifier, salt, index }; + } + + // Other instance methods -------------------------------------------------- + + private synchronized void readOrCreateConf() throws IOException + { + configurations.clear(); + final FileInputStream fis; + configFile = new File(confName); + try + { + fis = new FileInputStream(configFile); + readConf(fis); + } + catch (FileNotFoundException x) + { // create a default one + final String g = Util.toBase64(Util.trim(new BigInteger("2"))); + String index, N; + for (int i = 0; i < Nsrp.length; i++) + { + index = String.valueOf(i + 1); + N = Util.toBase64(Util.trim(Nsrp[i])); + configurations.put(index, new String[] { N, g }); + } + FileOutputStream f0 = null; + PrintWriter pw0 = null; + try + { + f0 = new FileOutputStream(configFile); + pw0 = new PrintWriter(f0, true); + this.writeConf(pw0); + } + finally + { + if (pw0 != null) + { + pw0.close(); + } + else if (f0 != null) + { + f0.close(); + } + } + } + } + + private void readConf(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line, index, N, g; + StringTokenizer st; + while ((line = din.readLine()) != null) + { + st = new StringTokenizer(line, ":"); + try + { + index = st.nextToken(); + N = st.nextToken(); + g = st.nextToken(); + } + catch (NoSuchElementException x) + { + throw new IOException("SRP password configuration file corrupt"); + } + configurations.put(index, new String[] { N, g }); + } + } + + private void writeConf(final PrintWriter pw) + { + String ndx; + String[] mpi; + StringBuffer sb; + for (Iterator it = configurations.keySet().iterator(); it.hasNext();) + { + ndx = (String) it.next(); + mpi = (String[]) configurations.get(ndx); + sb = new StringBuffer(ndx).append(":").append(mpi[0]).append(":").append( + mpi[1]); + pw.println(sb.toString()); + } + } + + /** + *

Compute the new verifiers for the designated username and password.

+ * + *

IMPORTANT: This method computes the verifiers as described in + * RFC-2945, which differs from the description given on the web page for + * SRP-6.

+ * + * @param user the user's name. + * @param s the user's salt. + * @param password the user's password + * @param index the index of the <N, g> pair to use for this user. + * @return a {@link java.util.Map} of user verifiers. + * @throws UnsupportedEncodingException if the US-ASCII decoder is not + * available on this platform. + */ + private HashMap newVerifiers(final String user, final byte[] s, + final String password, final String index) + throws UnsupportedEncodingException + { + // to ensure inter-operability with non-java tools + final String[] mpi = (String[]) configurations.get(index); + final BigInteger N = new BigInteger(1, Util.fromBase64(mpi[0])); + final BigInteger g = new BigInteger(1, Util.fromBase64(mpi[1])); + + final HashMap result = new HashMap(srps.size()); + BigInteger x, v; + SRP srp; + for (int i = 0; i < srps.size(); i++) + { + final String digestID = String.valueOf(i); + srp = (SRP) srps.get(digestID); + x = new BigInteger(1, srp.computeX(s, user, password)); + v = g.modPow(x, N); + final String verifier = Util.toBase64(v.toByteArray()); + + result.put(digestID, verifier); + } + return result; + } + + private synchronized void update() throws IOException + { + entries.clear(); + + FileInputStream fis; + passwdFile = new File(pwName); + lastmodPasswdFile = passwdFile.lastModified(); + try + { + fis = new FileInputStream(passwdFile); + readPasswd(fis); + } + catch (FileNotFoundException ignored) + { + } + passwd2File = new File(pw2Name); + lastmodPasswd2File = passwd2File.lastModified(); + try + { + fis = new FileInputStream(passwd2File); + readPasswd2(fis); + } + catch (FileNotFoundException ignored) + { + } + } + + private void checkCurrent() throws IOException + { + if (passwdFile.lastModified() > lastmodPasswdFile + || passwd2File.lastModified() > lastmodPasswd2File) + { + update(); + } + } + + private void readPasswd(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line, user, verifier, salt, index; + StringTokenizer st; + while ((line = din.readLine()) != null) + { + st = new StringTokenizer(line, ":"); + try + { + user = st.nextToken(); + verifier = st.nextToken(); + salt = st.nextToken(); + index = st.nextToken(); + } + catch (NoSuchElementException x) + { + throw new IOException("SRP base password file corrupt"); + } + + final HashMap verifiers = new HashMap(6); + verifiers.put("0", verifier); + + final HashMap fields = new HashMap(4); + fields.put(USER_FIELD, user); + fields.put(VERIFIERS_FIELD, verifiers); + fields.put(SALT_FIELD, salt); + fields.put(CONFIG_FIELD, index); + + entries.put(user, fields); + } + } + + private void readPasswd2(final InputStream in) throws IOException + { + final BufferedReader din = new BufferedReader(new InputStreamReader(in)); + String line, digestID, user, verifier; + StringTokenizer st; + HashMap fields, verifiers; + while ((line = din.readLine()) != null) + { + st = new StringTokenizer(line, ":"); + try + { + digestID = st.nextToken(); + user = st.nextToken(); + verifier = st.nextToken(); + } + catch (NoSuchElementException x) + { + throw new IOException("SRP extended password file corrupt"); + } + + fields = (HashMap) entries.get(user); + if (fields != null) + { + verifiers = (HashMap) fields.get(VERIFIERS_FIELD); + verifiers.put(digestID, verifier); + } + } + } + + private void writePasswd(final PrintWriter pw1, final PrintWriter pw2) + throws IOException + { + String user, digestID; + HashMap fields, verifiers; + StringBuffer sb1, sb2; + Iterator j; + final Iterator i = entries.keySet().iterator(); + while (i.hasNext()) + { + user = (String) i.next(); + fields = (HashMap) entries.get(user); + if (!user.equals(fields.get(USER_FIELD))) + { + throw new IOException("Inconsistent SRP password data"); + } + verifiers = (HashMap) fields.get(VERIFIERS_FIELD); + sb1 = new StringBuffer().append(user).append(":").append( + (String) verifiers.get("0")).append( + ":").append( + (String) fields.get(SALT_FIELD)).append( + ":").append( + (String) fields.get(CONFIG_FIELD)); + pw1.println(sb1.toString()); + // write extended information + j = verifiers.keySet().iterator(); + while (j.hasNext()) + { + digestID = (String) j.next(); + if (!"0".equals(digestID)) + { + // #0 is the default digest, already present in tpasswd! + sb2 = new StringBuffer().append(digestID).append(":").append( + user).append( + ":").append( + (String) verifiers.get(digestID)); + pw2.println(sb2.toString()); + } + } + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SRP.java b/gnu/javax/crypto/sasl/srp/SRP.java new file mode 100644 index 000000000..d3eb596d4 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SRP.java @@ -0,0 +1,285 @@ +/* SRP.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.HashMap; + +/** + *

A Factory class that returns SRP Singletons that know all SRP-related + * mathematical computations and protocol-related operations for both the + * client- and server-sides.

+ */ +public final class SRP +{ + + // Constants and variables + // -------------------------------------------------------------------------- + + /** The map of already instantiated SRP algorithm instances. */ + private static final HashMap algorithms = new HashMap(); + + private static final byte COLON = (byte) 0x3A; + + /** The underlying message digest algorithm used for all SRP calculations. */ + private IMessageDigest mda; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** Trivial private constructor to enforce Singleton pattern. */ + private SRP(final IMessageDigest mda) + { + super(); + + this.mda = mda; + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns an instance of this object that uses the designated message + * digest algorithm as its digest function.

+ * + * @return an instance of this object for the designated digest name. + */ + public static synchronized SRP instance(String mdName) + { + if (mdName != null) + { + mdName = mdName.trim().toLowerCase(); + } + if (mdName == null || mdName.equals("")) + { + mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME; + } + SRP result = (SRP) algorithms.get(mdName); + if (result == null) + { + final IMessageDigest mda = HashFactory.getInstance(mdName); + result = new SRP(mda); + algorithms.put(mdName, result); + } + return result; + } + + private static final byte[] xor(final byte[] b1, final byte[] b2, + final int length) + { + final byte[] result = new byte[length]; + for (int i = 0; i < length; ++i) + { + result[i] = (byte) (b1[i] ^ b2[i]); + } + return result; + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** @return the message digest algorithm name used by this instance. */ + public String getAlgorithm() + { + return mda.name(); + } + + // Message Digest algorithm related methods -------------------------------- + + /** + *

Returns a new instance of the SRP message digest algorithm --which is + * SHA-160 by default, but could be anything else provided the proper + * conditions as specified in the SRP specifications.

+ * + * @return a new instance of the underlying SRP message digest algorithm. + * @throws RuntimeException if the implementation of the message digest + * algorithm does not support cloning. + */ + public IMessageDigest newDigest() + { + return (IMessageDigest) mda.clone(); + } + + /** + *

Convenience method to return the result of digesting the designated + * input with a new instance of the SRP message digest algorithm.

+ * + * @param src some bytes to digest. + * @return the bytes constituting the result of digesting the designated + * input with a new instance of the SRP message digest algorithm. + */ + public byte[] digest(final byte[] src) + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + hash.update(src, 0, src.length); + return hash.digest(); + } + + /** + *

Convenience method to return the result of digesting the designated + * input with a new instance of the SRP message digest algorithm.

+ * + * @param src a String whose bytes (using US-ASCII encoding) are to be + * digested. + * @return the bytes constituting the result of digesting the designated + * input with a new instance of the SRP message digest algorithm. + * @throws UnsupportedEncodingException if US-ASCII charset is not found. + */ + public byte[] digest(final String src) throws UnsupportedEncodingException + { + return digest(src.getBytes("US-ASCII")); + } + + // Other methods ----------------------------------------------------------- + + /** + *

Convenience method to XOR N bytes from two arrays; N being the output + * size of the SRP message digest algorithm.

+ * + * @param a the first byte array. + * @param b the second one. + * @return N bytes which are the result of the XOR operations on the first N + * bytes from the designated arrays. N is the size of the SRP message digest + * algorithm; eg. 20 for SHA-160. + */ + public byte[] xor(final byte[] a, final byte[] b) + { + return xor(a, b, mda.hashSize()); + } + + public byte[] generateM1(final BigInteger N, final BigInteger g, + final String U, final byte[] s, final BigInteger A, + final BigInteger B, final byte[] K, final String I, + final String L, final byte[] cn, final byte[] cCB) + throws UnsupportedEncodingException + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + byte[] b; + b = xor(digest(Util.trim(N)), digest(Util.trim(g))); + hash.update(b, 0, b.length); + b = digest(U); + hash.update(b, 0, b.length); + hash.update(s, 0, s.length); + b = Util.trim(A); + hash.update(b, 0, b.length); + b = Util.trim(B); + hash.update(b, 0, b.length); + hash.update(K, 0, K.length); + b = digest(I); + hash.update(b, 0, b.length); + b = digest(L); + hash.update(b, 0, b.length); + hash.update(cn, 0, cn.length); + hash.update(cCB, 0, cCB.length); + + return hash.digest(); + } + + public byte[] generateM2(final BigInteger A, final byte[] M1, final byte[] K, + final String U, final String I, final String o, + final byte[] sid, final int ttl, final byte[] cIV, + final byte[] sIV, final byte[] sCB) + throws UnsupportedEncodingException + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + byte[] b; + b = Util.trim(A); + hash.update(b, 0, b.length); + hash.update(M1, 0, M1.length); + hash.update(K, 0, K.length); + b = digest(U); + hash.update(b, 0, b.length); + b = digest(I); + hash.update(b, 0, b.length); + b = digest(o); + hash.update(b, 0, b.length); + hash.update(sid, 0, sid.length); + hash.update((byte) (ttl >>> 24)); + hash.update((byte) (ttl >>> 16)); + hash.update((byte) (ttl >>> 8)); + hash.update((byte) ttl); + hash.update(cIV, 0, cIV.length); + hash.update(sIV, 0, sIV.length); + hash.update(sCB, 0, sCB.length); + + return hash.digest(); + } + + public byte[] generateKn(final byte[] K, final byte[] cn, final byte[] sn) + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + hash.update(K, 0, K.length); + hash.update(cn, 0, cn.length); + hash.update(sn, 0, sn.length); + + return hash.digest(); + } + + public byte[] computeX(final byte[] s, final String user, + final String password) + throws UnsupportedEncodingException + { + return computeX(s, user.getBytes("US-ASCII"), password.getBytes("US-ASCII")); + } + + public byte[] computeX(final byte[] s, final String user, final byte[] p) + throws UnsupportedEncodingException + { + return computeX(s, user.getBytes("US-ASCII"), p); + } + + private byte[] computeX(final byte[] s, final byte[] user, final byte[] p) + { + final IMessageDigest hash = (IMessageDigest) mda.clone(); + hash.update(user, 0, user.length); + hash.update(COLON); + hash.update(p, 0, p.length); + final byte[] up = hash.digest(); + + hash.update(s, 0, s.length); + hash.update(up, 0, up.length); + + return hash.digest(); + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java b/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java new file mode 100644 index 000000000..9ea21efb6 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java @@ -0,0 +1,218 @@ +/* SRPAuthInfoProvider.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; +import gnu.javax.crypto.sasl.IAuthInfoProvider; +import gnu.javax.crypto.sasl.NoSuchUserException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.security.sasl.AuthenticationException; + +/** + *

The SRP mechanism authentication information provider implementation.

+ */ +public class SRPAuthInfoProvider implements IAuthInfoProvider +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private PasswordFile passwordFile = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + // implicit 0-args constrcutor + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IAuthInfoProvider interface implementation ------------------------------ + + public void activate(Map context) throws AuthenticationException + { + try + { + if (context == null) + { + passwordFile = new PasswordFile(); + } + else + { + passwordFile = (PasswordFile) context.get(SRPRegistry.PASSWORD_DB); + if (passwordFile == null) + { + String pfn = (String) context.get(SRPRegistry.PASSWORD_FILE); + if (pfn == null) + { + passwordFile = new PasswordFile(); + } + else + { + passwordFile = new PasswordFile(pfn); + } + } + } + } + catch (IOException x) + { + throw new AuthenticationException("activate()", x); + } + } + + public void passivate() throws AuthenticationException + { + passwordFile = null; + } + + public boolean contains(String userName) throws AuthenticationException + { + if (passwordFile == null) + { + throw new AuthenticationException("contains()", + new IllegalStateException()); + } + boolean result = false; + try + { + result = passwordFile.contains(userName); + } + catch (IOException x) + { + throw new AuthenticationException("contains()", x); + } + return result; + } + + public Map lookup(Map userID) throws AuthenticationException + { + if (passwordFile == null) + { + throw new AuthenticationException("lookup()", + new IllegalStateException()); + } + Map result = new HashMap(); + try + { + String userName = (String) userID.get(Registry.SASL_USERNAME); + if (userName == null) + { + throw new NoSuchUserException(""); + } + String mdName = (String) userID.get(SRPRegistry.MD_NAME_FIELD); + + String[] data = passwordFile.lookup(userName, mdName); + result.put(SRPRegistry.USER_VERIFIER_FIELD, data[0]); + result.put(SRPRegistry.SALT_FIELD, data[1]); + result.put(SRPRegistry.CONFIG_NDX_FIELD, data[2]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + { + throw (AuthenticationException) x; + } + throw new AuthenticationException("lookup()", x); + } + return result; + } + + public void update(Map userCredentials) throws AuthenticationException + { + if (passwordFile == null) + throw new AuthenticationException("update()", new IllegalStateException()); + + try + { + String userName = (String) userCredentials.get(Registry.SASL_USERNAME); + String password = (String) userCredentials.get(Registry.SASL_PASSWORD); + String salt = (String) userCredentials.get(SRPRegistry.SALT_FIELD); + String config = (String) userCredentials.get(SRPRegistry.CONFIG_NDX_FIELD); + if (salt == null || config == null) + { + passwordFile.changePasswd(userName, password); + } + else + { + passwordFile.add(userName, password, Util.fromBase64(salt), config); + } + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + { + throw (AuthenticationException) x; + } + throw new AuthenticationException("update()", x); + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + if (passwordFile == null) + { + throw new AuthenticationException("getConfiguration()", + new IllegalStateException()); + } + Map result = new HashMap(); + try + { + String[] data = passwordFile.lookupConfig(mode); + result.put(SRPRegistry.SHARED_MODULUS, data[0]); + result.put(SRPRegistry.FIELD_GENERATOR, data[1]); + } + catch (Exception x) + { + if (x instanceof AuthenticationException) + { + throw (AuthenticationException) x; + } + throw new AuthenticationException("getConfiguration()", x); + } + return result; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SRPClient.java b/gnu/javax/crypto/sasl/srp/SRPClient.java new file mode 100644 index 000000000..1a1664ff7 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SRPClient.java @@ -0,0 +1,1211 @@ +/* SRPClient.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.java.security.hash.MD5; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.key.IKeyAgreementParty; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.sasl.ClientMechanism; +import gnu.javax.crypto.sasl.IllegalMechanismStateException; +import gnu.javax.crypto.sasl.InputBuffer; +import gnu.javax.crypto.sasl.IntegrityException; +import gnu.javax.crypto.sasl.OutputBuffer; + +import gnu.javax.security.auth.Password; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.StringTokenizer; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.DestroyFailedException; +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + *

The SASL-SRP client-side mechanism.

+ */ +public class SRPClient extends ClientMechanism implements SaslClient +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "SRPClient"; + + // private static final String ERROR = "ERROR"; + // private static final String WARN = " WARN"; + private static final String INFO = " INFO"; + + private static final String TRACE = "DEBUG"; + + private static final boolean DEBUG = true; + + private static final int debuglevel = 3; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(final String level, final Object obj) + { + err.println("[" + level + "] " + NAME + ": " + String.valueOf(obj)); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + // private static final HashMap uid2ctx = new HashMap(); + + private String uid; // the unique key for this type of client + + private String U; // the authentication identity + + BigInteger N, g, A, B; + + private Password password; // the authentication credentials + + private byte[] s; // the user's salt + + private byte[] cIV, sIV; // client+server IVs, when confidentiality is on + + private byte[] M1, M2; // client+server evidences + + private byte[] cn, sn; // client's and server's nonce + + private SRP srp; // SRP algorithm instance used by this client + + private byte[] sid; // session ID when re-used + + private int ttl; // session time-to-live in seconds + + private byte[] sCB; // the peer's channel binding data + + private String L; // available options + + private String o; + + private String chosenIntegrityAlgorithm; + + private String chosenConfidentialityAlgorithm; + + private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT; + + private byte[] K; // shared session key + + private boolean replayDetection = true; // whether Replay Detection is on + + private int inCounter = 0; // messages sequence numbers + + private int outCounter = 0; + + private IALG inMac, outMac; // if !null, use for integrity + + private CALG inCipher, outCipher; // if !null, use for confidentiality + + private IKeyAgreementParty clientHandler = KeyAgreementFactory.getPartyAInstance(Registry.SRP_SASL_KA); + + /** Our default source of randomness. */ + private PRNG prng = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public SRPClient() + { + super(Registry.SASL_SRP_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + // we shall keep track of the sid (and the security context of this + // SRP client) based on the initialisation parameters of an SRP session. + // we shall compute a unique key for those parameters and key the sid + // (and the security context) accordingly. + // 1. compute the mapping key. use MD5 (the fastest) for this purpose + final MD5 md = new MD5(); + byte[] b; + b = authorizationID.getBytes(); + md.update(b, 0, b.length); + b = serverName.getBytes(); + md.update(b, 0, b.length); + b = protocol.getBytes(); + md.update(b, 0, b.length); + if (channelBinding.length > 0) + { + md.update(channelBinding, 0, channelBinding.length); + } + uid = Util.toBase64(md.digest()); + if (ClientStore.instance().isAlive(uid)) + { + final SecurityContext ctx = ClientStore.instance().restoreSession(uid); + srp = SRP.instance(ctx.getMdName()); + sid = ctx.getSID(); + K = ctx.getK(); + cIV = ctx.getClientIV(); + sIV = ctx.getServerIV(); + replayDetection = ctx.hasReplayDetection(); + inCounter = ctx.getInCounter(); + outCounter = ctx.getOutCounter(); + inMac = ctx.getInMac(); + outMac = ctx.getOutMac(); + inCipher = ctx.getInCipher(); + outCipher = ctx.getOutCipher(); + } + else + { + sid = new byte[0]; + ttl = 0; + K = null; + cIV = null; + sIV = null; + cn = null; + sn = null; + } + } + + protected void resetMechanism() throws SaslException + { + try + { + password.destroy(); + } + catch (DestroyFailedException dfe) + { + SaslException se = new SaslException("resetMechanism()"); + se.initCause(dfe); + throw se; + } + password = null; + M1 = null; + K = null; + cIV = null; + sIV = null; + inMac = outMac = null; + inCipher = outCipher = null; + + sid = null; + ttl = 0; + cn = null; + sn = null; + } + + // javax.security.sasl.SaslClient interface implementation ----------------- + + public boolean hasInitialResponse() + { + return true; + } + + public byte[] evaluateChallenge(final byte[] challenge) throws SaslException + { + switch (state) + { + case 0: + state++; + return sendIdentities(); + case 1: + state++; + final byte[] result = sendPublicKey(challenge); + try + { + password.destroy(); //don't need further this session + } + catch (DestroyFailedException x) + { + SaslException se = new SaslException("sendPublicKey()"); + se.initCause(se); + throw se; + } + return result; + case 2: // should only occur if session re-use was rejected + if (!complete) + { + state++; + return receiveEvidence(challenge); + } + // else fall through + default: + throw new IllegalMechanismStateException("evaluateChallenge()"); + } + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> engineUnwrap()"); + + if (inMac == null && inCipher == null) + { + throw new IllegalStateException("connection is not protected"); + } + + // at this point one, or both, of confidentiality and integrity protection + // services are active. + + final byte[] result; + try + { + // final InputBuffer frameIn = InputBuffer.getInstance(incoming, offset, len); + // result = frameIn.getEOS(); + if (inMac != null) + { // integrity bytes are at the end of the stream + final int macBytesCount = inMac.length(); + final int payloadLength = len - macBytesCount; + // final byte[] received_mac = frameIn.getOS(); + final byte[] received_mac = new byte[macBytesCount]; + System.arraycopy(incoming, offset + payloadLength, received_mac, 0, + macBytesCount); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got C (received MAC): " + + Util.dumpString(received_mac)); + // inMac.update(result); + inMac.update(incoming, offset, payloadLength); + if (replayDetection) + { + inCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "inCounter=" + String.valueOf(inCounter)); + inMac.update(new byte[] { (byte) (inCounter >>> 24), + (byte) (inCounter >>> 16), + (byte) (inCounter >>> 8), + (byte) inCounter }); + } + + final byte[] computed_mac = inMac.doFinal(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Computed MAC: " + Util.dumpString(computed_mac)); + if (!Arrays.equals(received_mac, computed_mac)) + { + throw new IntegrityException("engineUnwrap()"); + } + + // deal with the payload, which can be either plain or encrypted + if (inCipher != null) + { + result = inCipher.doFinal(incoming, offset, payloadLength); + } + else + { + result = new byte[len - macBytesCount]; + System.arraycopy(incoming, offset, result, 0, result.length); + } + } + else + { // no integrity protection; just confidentiality + // if (inCipher != null) { + result = inCipher.doFinal(incoming, offset, len); + // } else { + // result = new byte[len]; + // System.arraycopy(incoming, offset, result, 0, len); + // } + } + // if (inCipher != null) { + // result = inCipher.doFinal(result); + // } + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("engineUnwrap()", x); + } + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== engineUnwrap()"); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> engineWrap()"); + + if (outMac == null && outCipher == null) + { + throw new IllegalStateException("connection is not protected"); + } + + // at this point one, or both, of confidentiality and integrity protection + // services are active. + + // byte[] data = new byte[len]; + // System.arraycopy(outgoing, offset, data, 0, len); + byte[] result; + try + { + // OutputBuffer frameOut = new OutputBuffer(); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + // Process the data + if (outCipher != null) + { + // data = outCipher.doFinal(data); + result = outCipher.doFinal(outgoing, offset, len); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding c (encrypted plaintext): " + + Util.dumpString(result)); + + // frameOut.setEOS(data); + out.write(result); + + if (outMac != null) + { + outMac.update(result); + if (replayDetection) + { + outCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "outCounter=" + String.valueOf(outCounter)); + outMac.update(new byte[] { (byte) (outCounter >>> 24), + (byte) (outCounter >>> 16), + (byte) (outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + // frameOut.setOS(C); + out.write(C); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding C (integrity checksum): " + + Util.dumpString(C)); + } // else confidentiality only; do nothing + } + else + { // no confidentiality; just integrity [+ replay detection] + // if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding p (plaintext): "+Util.dumpString(data)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding p (plaintext): " + + Util.dumpString(outgoing, offset, len)); + + // frameOut.setEOS(data); + out.write(outgoing, offset, len); + + // if (outMac != null) { + // outMac.update(data); + outMac.update(outgoing, offset, len); + if (replayDetection) + { + outCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "outCounter=" + String.valueOf(outCounter)); + outMac.update(new byte[] { (byte) (outCounter >>> 24), + (byte) (outCounter >>> 16), + (byte) (outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + // frameOut.setOS(C); + out.write(C); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding C (integrity checksum): " + + Util.dumpString(C)); + // } + } + + // frameOut.setEOS(data); + // + // if (outMac != null) { + // outMac.update(data); + // if (replayDetection) { + // outCounter++; + // if (DEBUG && debuglevel > 6) debug(TRACE, "outCounter="+String.valueOf(outCounter)); + // outMac.update(new byte[] { + // (byte)(outCounter >>> 24), + // (byte)(outCounter >>> 16), + // (byte)(outCounter >>> 8), + // (byte) outCounter }); + // } + // byte[] C = outMac.doFinal(); + // frameOut.setOS(C); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding C (integrity checksum): "+Util.dumpString(C)); + // } + + // result = frameOut.wrap(); + result = out.toByteArray(); + + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("engineWrap()", x); + } + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== engineWrap()"); + return result; + } + + protected String getNegotiatedQOP() + { + if (inMac != null) + { + if (inCipher != null) + { + return Registry.QOP_AUTH_CONF; + } + else + { + return Registry.QOP_AUTH_INT; + } + } + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + if (inMac != null) + { + if (inCipher != null) + { + return Registry.STRENGTH_HIGH; + } + else + { + return Registry.STRENGTH_MEDIUM; + } + } + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(rawSendSize); + } + + protected String getReuse() + { + return Registry.REUSE_TRUE; + } + + // other methods ----------------------------------------------------------- + + private byte[] sendIdentities() throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> sendIdentities()"); + + // If necessary, prompt the client for the username and password + getUsernameAndPassword(); + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Password: \"" + new String(password.getPassword()) + "\""); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding U (username): \"" + U + "\""); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding I (userid): \"" + authorizationID + "\""); + + // if session re-use generate new 16-byte nonce + if (sid.length != 0) + { + cn = new byte[16]; + getDefaultPRNG().nextBytes(cn); + } + else + { + cn = new byte[0]; + } + + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setText(U); + frameOut.setText(authorizationID); + frameOut.setEOS(sid); // session ID to re-use + frameOut.setOS(cn); // client nonce + frameOut.setEOS(channelBinding); + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new AuthenticationException("sendIdentities()", x); + } + final byte[] result = frameOut.encode(); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendIdentities()"); + if (DEBUG && debuglevel > 2) + debug(INFO, "C: " + Util.dumpString(result)); + if (DEBUG && debuglevel > 2) + debug(INFO, " U = " + U); + if (DEBUG && debuglevel > 2) + debug(INFO, " I = " + authorizationID); + if (DEBUG && debuglevel > 2) + debug(INFO, "sid = " + new String(sid)); + if (DEBUG && debuglevel > 2) + debug(INFO, " cn = " + Util.dumpString(cn)); + if (DEBUG && debuglevel > 2) + debug(INFO, "cCB = " + Util.dumpString(channelBinding)); + return result; + } + + private byte[] sendPublicKey(final byte[] input) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> sendPublicKey()"); + if (DEBUG && debuglevel > 6) + debug(TRACE, "S: " + Util.dumpString(input)); + + // Server sends [00], N, g, s, B, L + // or [FF], sn, sCB + final InputBuffer frameIn = new InputBuffer(input); + final int ack; + try + { + ack = (int) frameIn.getScalar(1); + if (ack == 0x00) + { // new session + N = frameIn.getMPI(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got N (modulus): " + Util.dump(N)); + g = frameIn.getMPI(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got g (generator): " + Util.dump(g)); + s = frameIn.getOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got s (salt): " + Util.dumpString(s)); + B = frameIn.getMPI(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got B (server ephermeral public key): " + + Util.dump(B)); + L = frameIn.getText(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got L (available options): \"" + L + "\""); + } + else if (ack == 0xFF) + { // session re-use + sn = frameIn.getOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got sn (server nonce): " + Util.dumpString(sn)); + sCB = frameIn.getEOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got sCB (server channel binding): " + + Util.dumpString(sCB)); + } + else + { // unexpected scalar + throw new SaslException("sendPublicKey(): Invalid scalar (" + ack + + ") in server's request"); + } + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("sendPublicKey()", x); + } + + if (ack == 0x00) + { // new session --------------------------------------- + o = createO(L.toLowerCase()); // do this first to initialise the SRP hash + + final byte[] pBytes; // use ASCII encoding to inter-operate w/ non-java + pBytes = password.getBytes(); + + // ---------------------------------------------------------------------- + final HashMap mapA = new HashMap(); + // mapA.put(SRP6KeyAgreement.HASH_FUNCTION, srp.newDigest()); + mapA.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm()); + mapA.put(SRP6KeyAgreement.USER_IDENTITY, U); + mapA.put(SRP6KeyAgreement.USER_PASSWORD, pBytes); + try + { + clientHandler.init(mapA); + clientHandler.processMessage(null); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendPublicKey()", x); + } + + // ---------------------------------------------------------------------- + + // ------------------------------------------------------------------- + try + { + OutgoingMessage out = new OutgoingMessage(); + out.writeMPI(N); + out.writeMPI(g); + out.writeMPI(new BigInteger(1, s)); + out.writeMPI(B); + IncomingMessage in = new IncomingMessage(out.toByteArray()); + out = clientHandler.processMessage(in); + + in = new IncomingMessage(out.toByteArray()); + A = in.readMPI(); + K = clientHandler.getSharedSecret(); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendPublicKey()", x); + } + // ------------------------------------------------------------------- + + if (DEBUG && debuglevel > 6) + debug(TRACE, "K: " + Util.dumpString(K)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding A (client ephemeral public key): " + + Util.dump(A)); + + try + { + M1 = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn, + channelBinding); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("sendPublicKey()", x); + } + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding o (client chosen options): \"" + o + "\""); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding cIV (client IV): \"" + Util.dumpString(cIV) + + "\""); + + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setMPI(A); + frameOut.setOS(M1); + frameOut.setText(o); + frameOut.setOS(cIV); + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new AuthenticationException("sendPublicKey()", x); + } + final byte[] result = frameOut.encode(); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendPublicKey()"); + if (DEBUG && debuglevel > 2) + debug(INFO, "New session, or session re-use rejected..."); + if (DEBUG && debuglevel > 2) + debug(INFO, "C: " + Util.dumpString(result)); + if (DEBUG && debuglevel > 2) + debug(INFO, " A = 0x" + A.toString(16)); + if (DEBUG && debuglevel > 2) + debug(INFO, " M1 = " + Util.dumpString(M1)); + if (DEBUG && debuglevel > 2) + debug(INFO, " o = " + o); + if (DEBUG && debuglevel > 2) + debug(INFO, "cIV = " + Util.dumpString(cIV)); + + return result; + } + else + { // session re-use accepted ------------------------------------- + setupSecurityServices(true); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendPublicKey()"); + if (DEBUG && debuglevel > 2) + debug(INFO, "Session re-use accepted..."); + return null; + } + } + + private byte[] receiveEvidence(byte[] input) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> receiveEvidence()"); + if (DEBUG && debuglevel > 6) + debug(TRACE, "S: " + Util.dumpString(input)); + + // Server send M2, sIV, sCB, sid, ttl + final InputBuffer frameIn = new InputBuffer(input); + try + { + M2 = frameIn.getOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got M2 (server evidence): " + Util.dumpString(M2)); + sIV = frameIn.getOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got sIV (server IV): " + Util.dumpString(sIV)); + sid = frameIn.getEOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got sid (session ID): " + new String(sid)); + ttl = (int) frameIn.getScalar(4); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got ttl (session time-to-live): " + ttl + "sec."); + sCB = frameIn.getEOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got sCB (server channel binding): " + + Util.dumpString(sCB)); + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new AuthenticationException("receiveEvidence()", x); + } + + final byte[] expected; + try + { + expected = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl, + cIV, sIV, sCB); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("receiveEvidence()", x); + } + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Expected: " + Util.dumpString(expected)); + if (!Arrays.equals(M2, expected)) + { + throw new AuthenticationException("M2 mismatch"); + } + + setupSecurityServices(false); + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== receiveEvidence()"); + return null; + } + + private void getUsernameAndPassword() throws AuthenticationException + { + try + { + if ((!properties.containsKey(Registry.SASL_USERNAME)) + && (!properties.containsKey(Registry.SASL_PASSWORD))) + { + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + { + nameCB = new NameCallback("username: "); + } + else + { + nameCB = new NameCallback("username: ", defaultName); + } + final PasswordCallback pwdCB = new PasswordCallback("password: ", + false); + handler.handle(new Callback[] { nameCB, pwdCB }); + U = nameCB.getName(); + password = new Password(pwdCB.getPassword()); + } + else + { + if (properties.containsKey(Registry.SASL_USERNAME)) + { + this.U = (String) properties.get(Registry.SASL_USERNAME); + } + else + { + final NameCallback nameCB; + final String defaultName = System.getProperty("user.name"); + if (defaultName == null) + { + nameCB = new NameCallback("username: "); + } + else + { + nameCB = new NameCallback("username: ", defaultName); + } + this.handler.handle(new Callback[] { nameCB }); + this.U = nameCB.getName(); + } + + if (properties.containsKey(Registry.SASL_PASSWORD)) + { + Object pw = properties.get(Registry.SASL_PASSWORD); + if (pw instanceof char[]) + password = new Password((char[]) pw); + else if (pw instanceof Password) + password = (Password) pw; + else if (pw instanceof String) + password = new Password(((String) pw).toCharArray()); + else + throw new IllegalArgumentException( + pw.getClass().getName() + + "is not a valid password class"); + } + else + { + final PasswordCallback pwdCB = new PasswordCallback( + "password: ", + false); + this.handler.handle(new Callback[] { pwdCB }); + password = new Password(pwdCB.getPassword()); + } + } + + if (U == null) + { + throw new AuthenticationException("null username supplied"); + } + if (password == null) + { + throw new AuthenticationException("null password supplied"); + } + } + catch (UnsupportedCallbackException x) + { + throw new AuthenticationException("getUsernameAndPassword()", x); + } + catch (IOException x) + { + throw new AuthenticationException("getUsernameAndPassword()", x); + } + } + + // We go through the list of available services and for each available one + // we decide whether or not we want it enabled, based on properties passed + // to us by the client. + private String createO(final String aol) throws AuthenticationException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> createO(\"" + aol + "\")"); + + boolean replaydetectionAvailable = false; + boolean integrityAvailable = false; + boolean confidentialityAvailable = false; + String option, mandatory = SRPRegistry.DEFAULT_MANDATORY; + int i; + + String mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME; + + final StringTokenizer st = new StringTokenizer(aol, ","); + while (st.hasMoreTokens()) + { + option = st.nextToken(); + if (option.startsWith(SRPRegistry.OPTION_SRP_DIGEST + "=")) + { + option = option.substring(option.indexOf('=') + 1); + if (DEBUG && debuglevel > 6) + debug(TRACE, "mda: <" + option + ">"); + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + { + if (SRPRegistry.SRP_ALGORITHMS[i].equals(option)) + { + mdName = option; + break; + } + } + } + else if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION)) + { + replaydetectionAvailable = true; + } + else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "=")) + { + option = option.substring(option.indexOf('=') + 1); + if (DEBUG && debuglevel > 6) + debug(TRACE, "ialg: <" + option + ">"); + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + { + if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option)) + { + chosenIntegrityAlgorithm = option; + integrityAvailable = true; + break; + } + } + } + else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "=")) + { + option = option.substring(option.indexOf('=') + 1); + if (DEBUG && debuglevel > 6) + debug(TRACE, "calg: <" + option + ">"); + for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++) + { + if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option)) + { + chosenConfidentialityAlgorithm = option; + confidentialityAvailable = true; + break; + } + } + } + else if (option.startsWith(SRPRegistry.OPTION_MANDATORY + "=")) + { + mandatory = option.substring(option.indexOf('=') + 1); + } + else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=")) + { + final String maxBufferSize = option.substring(option.indexOf('=') + 1); + try + { + rawSendSize = Integer.parseInt(maxBufferSize); + if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT + || rawSendSize < 1) + { + throw new AuthenticationException( + "Illegal value for 'maxbuffersize' option"); + } + } + catch (NumberFormatException x) + { + throw new AuthenticationException( + SRPRegistry.OPTION_MAX_BUFFER_SIZE + + "=" + + String.valueOf(maxBufferSize), + x); + } + } + } + + replayDetection = replaydetectionAvailable + && Boolean.valueOf( + (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION)).booleanValue(); + boolean integrity = integrityAvailable + && Boolean.valueOf( + (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION)).booleanValue(); + boolean confidentiality = confidentialityAvailable + && Boolean.valueOf( + (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY)).booleanValue(); + + // make sure we do the right thing + if (SRPRegistry.OPTION_REPLAY_DETECTION.equals(mandatory)) + { + replayDetection = true; + integrity = true; + } + else if (SRPRegistry.OPTION_INTEGRITY.equals(mandatory)) + { + integrity = true; + } + else if (SRPRegistry.OPTION_CONFIDENTIALITY.equals(mandatory)) + { + confidentiality = true; + } + if (replayDetection) + { + if (chosenIntegrityAlgorithm == null) + { + throw new AuthenticationException( + "Replay detection is required but no " + + "integrity protection algorithm was chosen"); + } + } + if (integrity) + { + if (chosenIntegrityAlgorithm == null) + { + throw new AuthenticationException( + "Integrity protection is required but no " + + "algorithm was chosen"); + } + } + if (confidentiality) + { + if (chosenConfidentialityAlgorithm == null) + { + throw new AuthenticationException( + "Confidentiality protection is required " + + "but no algorithm was chosen"); + } + } + + // 1. check if we'll be using confidentiality; if not set IV to 0-byte + if (chosenConfidentialityAlgorithm == null) + { + cIV = new byte[0]; + } + else + { + // 2. get the block size of the cipher + final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm); + if (cipher == null) + { + throw new AuthenticationException("createO()", + new NoSuchAlgorithmException()); + } + final int blockSize = cipher.defaultBlockSize(); + // 3. generate random iv + cIV = new byte[blockSize]; + getDefaultPRNG().nextBytes(cIV); + } + + srp = SRP.instance(mdName); + + // Now create the options list specifying which of the available options + // we have chosen. + + // For now we just select the defaults. Later we need to add support for + // properties (perhaps in a file) where a user can specify the list of + // algorithms they would prefer to use. + + final StringBuffer sb = new StringBuffer(); + sb.append(SRPRegistry.OPTION_SRP_DIGEST).append("=").append(mdName).append( + ","); + if (replayDetection) + { + sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(","); + } + if (integrity) + { + sb.append(SRPRegistry.OPTION_INTEGRITY).append("=").append( + chosenIntegrityAlgorithm).append( + ","); + } + if (confidentiality) + { + sb.append(SRPRegistry.OPTION_CONFIDENTIALITY).append("=").append( + chosenConfidentialityAlgorithm).append( + ","); + } + final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE).append( + "=").append( + Registry.SASL_BUFFER_MAX_LIMIT).toString(); + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== createO() --> " + result); + return result; + } + + private void setupSecurityServices(final boolean sessionReUse) + throws SaslException + { + complete = true; // signal end of authentication phase + if (!sessionReUse) + { + outCounter = inCounter = 0; + // instantiate cipher if confidentiality protection filter is active + if (chosenConfidentialityAlgorithm != null) + { + if (DEBUG && debuglevel > 2) + debug(INFO, "Activating confidentiality protection filter"); + inCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + outCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + } + // instantiate hmacs if integrity protection filter is active + if (chosenIntegrityAlgorithm != null) + { + if (DEBUG && debuglevel > 2) + debug(INFO, "Activating integrity protection filter"); + inMac = IALG.getInstance(chosenIntegrityAlgorithm); + outMac = IALG.getInstance(chosenIntegrityAlgorithm); + } + } + else + { // same session new Keys + K = srp.generateKn(K, cn, sn); + } + + final KDF kdf = KDF.getInstance(K); + + // initialise in/out ciphers if confidentiality protection is used + if (inCipher != null) + { + inCipher.init(kdf, sIV, Direction.REVERSED); + outCipher.init(kdf, cIV, Direction.FORWARD); + } + // initialise in/out macs if integrity protection is used + if (inMac != null) + { + inMac.init(kdf); + outMac.init(kdf); + } + + if (sid != null && sid.length != 0) + { // update the security context and save in map + if (DEBUG && debuglevel > 2) + debug(INFO, "Updating security context for UID = " + uid); + ClientStore.instance().cacheSession( + uid, + ttl, + new SecurityContext( + srp.getAlgorithm(), + sid, + K, + cIV, + sIV, + replayDetection, + inCounter, + outCounter, + inMac, outMac, + inCipher, + outCipher)); + } + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SRPRegistry.java b/gnu/javax/crypto/sasl/srp/SRPRegistry.java new file mode 100644 index 000000000..262cbcba3 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SRPRegistry.java @@ -0,0 +1,219 @@ +/* SRPRegistry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; + +/** + *

A list of key names designating the values exchanged between the server + * and client in an SRP communication authentication phase.

+ */ +public interface SRPRegistry +{ + + /** Indices of (N, g) parameter values for SRP (.conf) password database. */ + String N_2048_BITS = "1"; + + String N_1536_BITS = "2"; + + String N_1280_BITS = "3"; + + String N_1024_BITS = "4"; + + String N_768_BITS = "5"; + + String N_640_BITS = "6"; + + String N_512_BITS = "7"; + + /** Available hash algorithms for all SRP calculations. */ + String[] SRP_ALGORITHMS = { Registry.SHA160_HASH, // the default one + Registry.MD5_HASH, Registry.RIPEMD128_HASH, + Registry.RIPEMD160_HASH, + + Registry.SHA256_HASH, Registry.SHA384_HASH, + Registry.SHA512_HASH }; + + /** + * The name of the default message digest algorithm to use when no name is + * explicitely given. In this implementation it is the first among + * those supported; i.e. the algorithm at index position #0: SHA with + * 160-bit output. + */ + String SRP_DEFAULT_DIGEST_NAME = SRP_ALGORITHMS[0]; + + /** + * The property name of the message digest algorithm name to use in a given + * SRP incarnation. + */ + String SRP_DIGEST_NAME = "srp.digest.name"; + + /** The public shared modulus: n. */ + String SHARED_MODULUS = "srp.N"; + + /** The GF generator used: g. */ + String FIELD_GENERATOR = "srp.g"; + + /** The list of server's available security options. */ + String AVAILABLE_OPTIONS = "srp.L"; + + /** The client's chosen security options. */ + String CHOSEN_OPTIONS = "srp.o"; + + /** The client's username. */ + String USER_NAME = "srp.U"; + + /** The client's authorization ID. */ + String USER_ROLE = "srp.I"; + + /** The user's salt. */ + String USER_SALT = "srp.s"; + + /** The user's password verifier. */ + String PASSWORD_VERIFIER = "srp.v"; + + /** The client's public ephemeral exponent: A. */ + String CLIENT_PUBLIC_KEY = "srp.A"; + + /** The server's public ephemeral exponent: B. */ + String SERVER_PUBLIC_KEY = "srp.B"; + + /** The client's evidence: M1. */ + String CLIENT_EVIDENCE = "srp.M1"; + + /** The server's evidence: M2. */ + String SERVER_EVIDENCE = "srp.M2"; + + /** Name of underlying hash algorithm for use with all SRP calculations. */ + String SRP_HASH = "gnu.crypto.sasl.srp.hash"; + + /** Name of SRP mandatory service property. */ + String SRP_MANDATORY = "gnu.crypto.sasl.srp.mandatory"; + + /** Name of SRP replay detection property. */ + String SRP_REPLAY_DETECTION = "gnu.crypto.sasl.srp.replay.detection"; + + /** Name of SRP integrity protection property. */ + String SRP_INTEGRITY_PROTECTION = "gnu.crypto.sasl.srp.integrity"; + + /** Name of SRP confidentiality protection property. */ + String SRP_CONFIDENTIALITY = "gnu.crypto.sasl.srp.confidentiality"; + + /** Name of the main SRP password file pathname property. */ + String PASSWORD_FILE = "gnu.crypto.sasl.srp.password.file"; + + /** + * Name of the SRP password database property --a reference to + * {@link gnu.crypto.sasl.srp.PasswordFile} object. + */ + String PASSWORD_DB = "gnu.crypto.sasl.srp.password.db"; + + /** Default fully qualified pathname of the SRP password file. */ + String DEFAULT_PASSWORD_FILE = "/etc/tpasswd"; + + /** Default value for replay detection security service. */ + boolean DEFAULT_REPLAY_DETECTION = true; + + /** Default value for integrity protection security service. */ + boolean DEFAULT_INTEGRITY = true; // implied by the previous option + + /** Default value for confidentiality protection security service. */ + boolean DEFAULT_CONFIDENTIALITY = false; + + // constants defining HMAC names + String HMAC_SHA1 = "hmac-sha1"; + + String HMAC_MD5 = "hmac-md5"; + + String HMAC_RIPEMD_160 = "hmac-ripemd-160"; + + /** Available HMAC algorithms for integrity protection. */ + String[] INTEGRITY_ALGORITHMS = { HMAC_SHA1, HMAC_MD5, HMAC_RIPEMD_160 }; + + // constants defining Cipher names + String AES = "aes"; + + String BLOWFISH = "blowfish"; + + /** Available Cipher algorithms for confidentiality protection. */ + String[] CONFIDENTIALITY_ALGORITHMS = { AES, BLOWFISH }; + + /** String for mandatory replay detection. */ + String OPTION_MANDATORY = "mandatory"; + + /** String for mda: the SRP digest algorithm name. */ + String OPTION_SRP_DIGEST = "mda"; + + /** String for mandatory replay detection. */ + String OPTION_REPLAY_DETECTION = "replay_detection"; + + /** String for mandatory integrity protection. */ + String OPTION_INTEGRITY = "integrity"; + + /** String for mandatory confidentiality protection. */ + String OPTION_CONFIDENTIALITY = "confidentiality"; + + /** String for mandatory replay detection. */ + String OPTION_MAX_BUFFER_SIZE = "maxbuffersize"; + + /** String for no mandatory security service. */ + String MANDATORY_NONE = "none"; + + /** Default mandatory security service required. */ + // String DEFAULT_MANDATORY = MANDATORY_NONE; + String DEFAULT_MANDATORY = OPTION_REPLAY_DETECTION; + + // String DEFAULT_MANDATORY = OPTION_INTEGRITY; + // String DEFAULT_MANDATORY = OPTION_CONFIDENTIALITY; + + /** Name of the UID field in the plain password file. */ + String MD_NAME_FIELD = "srp.md.name"; + + /** Name of the GID field in the plain password file. */ + String USER_VERIFIER_FIELD = "srp.user.verifier"; + + /** Name of the GECOS field in the plain password file. */ + String SALT_FIELD = "srp.salt"; + + /** Name of the SHELL field in the plain password file. */ + String CONFIG_NDX_FIELD = "srp.config.ndx"; + + /** Minimum bitlength of the SRP public modulus. */ + int MINIMUM_MODULUS_BITLENGTH = 512; +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SRPServer.java b/gnu/javax/crypto/sasl/srp/SRPServer.java new file mode 100644 index 000000000..f4421c1e8 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SRPServer.java @@ -0,0 +1,1156 @@ +/* SRPServer.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import gnu.java.security.Registry; +import gnu.java.security.util.PRNG; +import gnu.java.security.util.Util; + +import gnu.javax.crypto.assembly.Direction; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.key.IKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +import gnu.javax.crypto.sasl.IllegalMechanismStateException; +import gnu.javax.crypto.sasl.InputBuffer; +import gnu.javax.crypto.sasl.IntegrityException; +import gnu.javax.crypto.sasl.OutputBuffer; +import gnu.javax.crypto.sasl.ServerMechanism; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.HashMap; +import java.util.StringTokenizer; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + *

The SASL-SRP server-side mechanism.

+ * + * @version $Revision: 1.2.2.1 $ + */ +public class SRPServer extends ServerMechanism implements SaslServer +{ + + // Debugging methods and variables + // ------------------------------------------------------------------------- + + private static final String NAME = "SRPServer"; + + // private static final String ERROR = "ERROR"; + private static final String WARN = " WARN"; + + private static final String INFO = " INFO"; + + private static final String TRACE = "DEBUG"; + + private static final boolean DEBUG = true; + + private static final int debuglevel = 3; + + private static final PrintWriter err = new PrintWriter(System.out, true); + + private static void debug(final String level, final Object obj) + { + err.println("[" + level + "] " + NAME + ": " + String.valueOf(obj)); + } + + // Constants and variables + // ------------------------------------------------------------------------- + + private String U = null; // client's username + + private BigInteger N, g, A, B; + + private byte[] s; // salt + + private byte[] cIV, sIV; // client+server IVs, when confidentiality is on + + private byte[] cn, sn; // client's and server's nonce + + private SRP srp; // SRP algorithm instance used by this server + + private byte[] sid; // session ID when re-used + + private int ttl = 360; // session time-to-live in seconds + + private byte[] cCB; // peer's channel binding' + + private String mandatory; // List of available options + + private String L = null; + + private String o; + + private String chosenIntegrityAlgorithm; + + private String chosenConfidentialityAlgorithm; + + private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT; + + private byte[] K; // shared session key + + private boolean replayDetection = true; // whether Replay Detection is on + + private int inCounter = 0; // messages sequence numbers + + private int outCounter = 0; + + private IALG inMac, outMac; // if !null, use for integrity + + private CALG inCipher, outCipher; // if !null, use for confidentiality + + private IKeyAgreementParty serverHandler = KeyAgreementFactory.getPartyBInstance(Registry.SRP_SASL_KA); + + /** Our default source of randomness. */ + private PRNG prng = null; + + // Constructor(s) + // ------------------------------------------------------------------------- + + public SRPServer() + { + super(Registry.SASL_SRP_MECHANISM); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // abstract methods implementation ----------------------------------------- + + protected void initMechanism() throws SaslException + { + // TODO: + // we must have a means to map a given username to a preferred + // SRP hash algorithm; otherwise we end up using _always_ SHA. + // for the time being get it from the mechanism properties map + // and apply it for all users. + final String mda = (String) properties.get(SRPRegistry.SRP_HASH); + srp = SRP.instance(mda == null ? SRPRegistry.SRP_DEFAULT_DIGEST_NAME : mda); + } + + protected void resetMechanism() throws SaslException + { + s = null; + A = B = null; + K = null; + inMac = outMac = null; + inCipher = outCipher = null; + + sid = null; + } + + // javax.security.sasl.SaslServer interface implementation ----------------- + + public byte[] evaluateResponse(final byte[] response) throws SaslException + { + switch (state) + { + case 0: + if (response == null) + { + return null; + } + state++; + return sendProtocolElements(response); + case 1: + if (!complete) + { + state++; + return sendEvidence(response); + } + // else fall through + default: + throw new IllegalMechanismStateException("evaluateResponse()"); + } + } + + protected byte[] engineUnwrap(final byte[] incoming, final int offset, + final int len) throws SaslException + { + // if (DEBUG && debuglevel > 8) debug(TRACE, "==> engineUnwrap()"); + // + // if (inMac == null && inCipher == null) { + // throw new IllegalStateException("connection is not protected"); + // } + // + // if (DEBUG && debuglevel > 6) debug(TRACE, "Incoming buffer (before security): "+Util.dumpString(incoming, offset, len)); + // + // byte[] data = null; + // try { + // InputBuffer frameIn = InputBuffer.getInstance(incoming, offset, len); + // data = frameIn.getEOS(); + // if (inMac != null) { + // byte[] received_mac = frameIn.getOS(); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Got C (received MAC): "+Util.dumpString(received_mac)); + // inMac.update(data); + // if (replayDetection) { + // inCounter++; + // if (DEBUG && debuglevel > 6) debug(TRACE, "inCounter="+String.valueOf(inCounter)); + // inMac.update(new byte[] { + // (byte)(inCounter >>> 24), + // (byte)(inCounter >>> 16), + // (byte)(inCounter >>> 8), + // (byte) inCounter }); + // } + // final byte[] computed_mac = inMac.doFinal(); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Computed MAC: "+Util.dumpString(computed_mac)); + // if (!Arrays.equals(received_mac, computed_mac)) + // throw new IntegrityException("engineUnwrap()"); + // } + // if (inCipher != null) { + // data = inCipher.doFinal(data); + // } + // } catch (IOException x) { + // if (x instanceof SaslException) { + // throw (SaslException) x; + // } + // throw new SaslException("engineUnwrap()", x); + // } + // + // if (DEBUG && debuglevel > 6) debug(TRACE, "Incoming buffer (after security): "+Util.dumpString(data)); + // if (DEBUG && debuglevel > 8) debug(TRACE, "<== engineUnwrap()"); + // return data; + + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> engineUnwrap()"); + + if (inMac == null && inCipher == null) + { + throw new IllegalStateException("connection is not protected"); + } + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Incoming buffer (before security): " + + Util.dumpString(incoming, offset, len)); + + // at this point one, or both, of confidentiality and integrity protection + // services are active. + + final byte[] result; + try + { + if (inMac != null) + { // integrity bytes are at the end of the stream + final int macBytesCount = inMac.length(); + final int payloadLength = len - macBytesCount; + final byte[] received_mac = new byte[macBytesCount]; + System.arraycopy(incoming, offset + payloadLength, received_mac, 0, + macBytesCount); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got C (received MAC): " + + Util.dumpString(received_mac)); + inMac.update(incoming, offset, payloadLength); + if (replayDetection) + { + inCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "inCounter=" + String.valueOf(inCounter)); + inMac.update(new byte[] { (byte) (inCounter >>> 24), + (byte) (inCounter >>> 16), + (byte) (inCounter >>> 8), + (byte) inCounter }); + } + + final byte[] computed_mac = inMac.doFinal(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Computed MAC: " + Util.dumpString(computed_mac)); + if (!Arrays.equals(received_mac, computed_mac)) + { + throw new IntegrityException("engineUnwrap()"); + } + + // deal with the payload, which can be either plain or encrypted + if (inCipher != null) + { + result = inCipher.doFinal(incoming, offset, payloadLength); + } + else + { + result = new byte[payloadLength]; + System.arraycopy(incoming, offset, result, 0, result.length); + } + } + else + { // no integrity protection; just confidentiality + // if (inCipher != null) { + result = inCipher.doFinal(incoming, offset, len); + // } else { + // result = new byte[len]; + // System.arraycopy(incoming, offset, result, 0, len); + // } + } + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("engineUnwrap()", x); + } + if (DEBUG && debuglevel > 6) + debug(TRACE, "Incoming buffer (after security): " + + Util.dumpString(result)); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== engineUnwrap()"); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + // if (DEBUG && debuglevel > 8) debug(TRACE, "==> engineWrap()"); + // + // if (outMac == null && outCipher == null) { + // throw new IllegalStateException("connection is not protected"); + // } + // + // byte[] data = new byte[len]; + // System.arraycopy(outgoing, offset, data, 0, len); + // + // if (DEBUG && debuglevel > 6) debug(TRACE, "Outgoing buffer (before security) (hex): "+Util.dumpString(data)); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Outgoing buffer (before security) (str): \""+new String(data)+"\""); + // + // final byte[] result; + // try { + // OutputBuffer frameOut = new OutputBuffer(); + // // Process the data + // if (outCipher != null) { + // data = outCipher.doFinal(data); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding c (encrypted plaintext): "+Util.dumpString(data)); + // } else { + // if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding p (plaintext): "+Util.dumpString(data)); + // } + // frameOut.setEOS(data); + // if (outMac != null) { + // outMac.update(data); + // if (replayDetection) { + // outCounter++; + // if (DEBUG && debuglevel > 6) debug(TRACE, "outCounter="+String.valueOf(outCounter)); + // outMac.update(new byte[] { + // (byte)(outCounter >>> 24), + // (byte)(outCounter >>> 16), + // (byte)(outCounter >>> 8), + // (byte) outCounter}); + // } + // byte[] C = outMac.doFinal(); + // frameOut.setOS(C); + // if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding C (integrity checksum): "+Util.dumpString(C)); + // } + // result = frameOut.wrap(); + // + // } catch (IOException x) { + // if (x instanceof SaslException) { + // throw (SaslException) x; + // } + // throw new SaslException("engineWrap()", x); + // } + // + // if (DEBUG && debuglevel > 8) debug(TRACE, "<== engineWrap()"); + // return result; + + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> engineWrap()"); + + if (outMac == null && outCipher == null) + { + throw new IllegalStateException("connection is not protected"); + } + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Outgoing buffer (before security) (hex): " + + Util.dumpString(outgoing, offset, len)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Outgoing buffer (before security) (str): \"" + + new String(outgoing, offset, len) + "\""); + + // at this point one, or both, of confidentiality and integrity protection + // services are active. + + byte[] result; + try + { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + if (outCipher != null) + { + result = outCipher.doFinal(outgoing, offset, len); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding c (encrypted plaintext): " + + Util.dumpString(result)); + + out.write(result); + + if (outMac != null) + { + outMac.update(result); + if (replayDetection) + { + outCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "outCounter=" + String.valueOf(outCounter)); + outMac.update(new byte[] { (byte) (outCounter >>> 24), + (byte) (outCounter >>> 16), + (byte) (outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + out.write(C); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding C (integrity checksum): " + + Util.dumpString(C)); + } // else ciphertext only; do nothing + } + else + { // no confidentiality; just integrity [+ replay detection] + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding p (plaintext): " + + Util.dumpString(outgoing, offset, len)); + + out.write(outgoing, offset, len); + + // if (outMac != null) { + outMac.update(outgoing, offset, len); + if (replayDetection) + { + outCounter++; + if (DEBUG && debuglevel > 6) + debug(TRACE, "outCounter=" + String.valueOf(outCounter)); + outMac.update(new byte[] { (byte) (outCounter >>> 24), + (byte) (outCounter >>> 16), + (byte) (outCounter >>> 8), + (byte) outCounter }); + } + final byte[] C = outMac.doFinal(); + out.write(C); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding C (integrity checksum): " + + Util.dumpString(C)); + // } // else plaintext only; do nothing + } + + result = out.toByteArray(); + + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new SaslException("engineWrap()", x); + } + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== engineWrap()"); + return result; + } + + protected String getNegotiatedQOP() + { + if (inMac != null) + { + if (inCipher != null) + { + return Registry.QOP_AUTH_CONF; + } + else + { + return Registry.QOP_AUTH_INT; + } + } + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + if (inMac != null) + { + if (inCipher != null) + { + return Registry.STRENGTH_HIGH; + } + else + { + return Registry.STRENGTH_MEDIUM; + } + } + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(rawSendSize); + } + + protected String getReuse() + { + return Registry.REUSE_TRUE; + } + + // other methods ----------------------------------------------------------- + + private byte[] sendProtocolElements(final byte[] input) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> sendProtocolElements()"); + if (DEBUG && debuglevel > 6) + debug(TRACE, "C: " + Util.dumpString(input)); + + // Client send U, I, sid, cn + final InputBuffer frameIn = new InputBuffer(input); + try + { + U = frameIn.getText(); // Extract username + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got U (username): \"" + U + "\""); + authorizationID = frameIn.getText(); // Extract authorisation ID + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got I (userid): \"" + authorizationID + "\""); + sid = frameIn.getEOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got sid (session ID): " + new String(sid)); + cn = frameIn.getOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got cn (client nonce): " + Util.dumpString(cn)); + cCB = frameIn.getEOS(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got cCB (client channel binding): " + + Util.dumpString(cCB)); + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new AuthenticationException("sendProtocolElements()", x); + } + + // do/can we re-use? + if (ServerStore.instance().isAlive(sid)) + { + final SecurityContext ctx = ServerStore.instance().restoreSession(sid); + srp = SRP.instance(ctx.getMdName()); + K = ctx.getK(); + cIV = ctx.getClientIV(); + sIV = ctx.getServerIV(); + replayDetection = ctx.hasReplayDetection(); + inCounter = ctx.getInCounter(); + outCounter = ctx.getOutCounter(); + inMac = ctx.getInMac(); + outMac = ctx.getOutMac(); + inCipher = ctx.getInCipher(); + outCipher = ctx.getOutCipher(); + + if (sn == null || sn.length != 16) + { + sn = new byte[16]; + } + getDefaultPRNG().nextBytes(sn); + + setupSecurityServices(false); + + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setScalar(1, 0xFF); + frameOut.setOS(sn); + frameOut.setEOS(channelBinding); + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new AuthenticationException("sendProtocolElements()", x); + } + final byte[] result = frameOut.encode(); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendProtocolElements()"); + if (DEBUG && debuglevel > 2) + debug(INFO, "Old session..."); + if (DEBUG && debuglevel > 2) + debug(INFO, "S: " + Util.dumpString(result)); + if (DEBUG && debuglevel > 2) + debug(INFO, " sn = " + Util.dumpString(sn)); + if (DEBUG && debuglevel > 2) + debug(INFO, " sCB = " + Util.dumpString(channelBinding)); + return result; + } + else + { // new session + authenticator.activate(properties); + + // ------------------------------------------------------------------- + final HashMap mapB = new HashMap(); + // mapB.put(SRP6KeyAgreement.HASH_FUNCTION, srp.newDigest()); + mapB.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm()); + mapB.put(SRP6KeyAgreement.HOST_PASSWORD_DB, authenticator); + + try + { + serverHandler.init(mapB); + OutgoingMessage out = new OutgoingMessage(); + out.writeString(U); + IncomingMessage in = new IncomingMessage(out.toByteArray()); + out = serverHandler.processMessage(in); + + in = new IncomingMessage(out.toByteArray()); + N = in.readMPI(); + g = in.readMPI(); + s = in.readMPI().toByteArray(); + B = in.readMPI(); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendProtocolElements()", x); + } + // ------------------------------------------------------------------- + + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding N (modulus): " + Util.dump(N)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding g (generator): " + Util.dump(g)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding s (client's salt): " + Util.dumpString(s)); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding B (server ephemeral public key): " + + Util.dump(B)); + + // The server creates an options list (L), which consists of a + // comma-separated list of option strings that specify the security + // service options the server supports. + L = createL(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding L (available options): \"" + L + "\""); + if (DEBUG && debuglevel > 6) + debug(TRACE, "Encoding sIV (server IV): " + Util.dumpString(sIV)); + + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setScalar(1, 0x00); + frameOut.setMPI(N); + frameOut.setMPI(g); + frameOut.setOS(s); + frameOut.setMPI(B); + frameOut.setText(L); + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new AuthenticationException("sendProtocolElements()", x); + } + final byte[] result = frameOut.encode(); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendProtocolElements()"); + if (DEBUG && debuglevel > 2) + debug(INFO, "New session..."); + if (DEBUG && debuglevel > 2) + debug(INFO, "S: " + Util.dumpString(result)); + if (DEBUG && debuglevel > 2) + debug(INFO, " N = 0x" + N.toString(16)); + if (DEBUG && debuglevel > 2) + debug(INFO, " g = 0x" + g.toString(16)); + if (DEBUG && debuglevel > 2) + debug(INFO, " s = " + Util.dumpString(s)); + if (DEBUG && debuglevel > 2) + debug(INFO, " B = 0x" + B.toString(16)); + if (DEBUG && debuglevel > 2) + debug(INFO, " L = " + L); + return result; + } + } + + private byte[] sendEvidence(final byte[] input) throws SaslException + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> sendEvidence()"); + if (DEBUG && debuglevel > 6) + debug(TRACE, "C: " + Util.dumpString(input)); + + // Client send A, M1, o, cIV + final InputBuffer frameIn = new InputBuffer(input); + final byte[] M1; + try + { + A = frameIn.getMPI(); // Extract client's ephemeral public key + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got A (client ephemeral public key): " + Util.dump(A)); + M1 = frameIn.getOS(); // Extract evidence + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got M1 (client evidence): " + Util.dumpString(M1)); + o = frameIn.getText(); // Extract client's options list + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got o (client chosen options): \"" + o + "\""); + cIV = frameIn.getOS(); // Extract client's IV + if (DEBUG && debuglevel > 6) + debug(TRACE, "Got cIV (client IV): " + Util.dumpString(cIV)); + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new AuthenticationException("sendEvidence()", x); + } + + // Parse client's options and set security layer variables + parseO(o); + + // ---------------------------------------------------------------------- + try + { + final OutgoingMessage out = new OutgoingMessage(); + out.writeMPI(A); + final IncomingMessage in = new IncomingMessage(out.toByteArray()); + serverHandler.processMessage(in); + K = serverHandler.getSharedSecret(); + } + catch (KeyAgreementException x) + { + throw new SaslException("sendEvidence()", x); + } + // ---------------------------------------------------------------------- + + if (DEBUG && debuglevel > 6) + debug(TRACE, "K: " + Util.dumpString(K)); + + final byte[] expected; + try + { + expected = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn, + cCB); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("sendEvidence()", x); + } + + // Verify client evidence + if (!Arrays.equals(M1, expected)) + { + throw new AuthenticationException("M1 mismatch"); + } + + setupSecurityServices(true); + + final byte[] M2; + try + { + M2 = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl, cIV, + sIV, channelBinding); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("sendEvidence()", x); + } + + final OutputBuffer frameOut = new OutputBuffer(); + try + { + frameOut.setOS(M2); + frameOut.setOS(sIV); + frameOut.setEOS(sid); + frameOut.setScalar(4, ttl); + frameOut.setEOS(channelBinding); + } + catch (IOException x) + { + if (x instanceof SaslException) + { + throw (SaslException) x; + } + throw new AuthenticationException("sendEvidence()", x); + } + final byte[] result = frameOut.encode(); + if (DEBUG && debuglevel > 2) + debug(INFO, "S: " + Util.dumpString(result)); + if (DEBUG && debuglevel > 2) + debug(INFO, " M2 = " + Util.dumpString(M2)); + if (DEBUG && debuglevel > 2) + debug(INFO, " sIV = " + Util.dumpString(sIV)); + if (DEBUG && debuglevel > 2) + debug(INFO, " sid = " + new String(sid)); + if (DEBUG && debuglevel > 2) + debug(INFO, " ttl = " + ttl); + if (DEBUG && debuglevel > 2) + debug(INFO, " sCB = " + Util.dumpString(channelBinding)); + + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== sendEvidence()"); + return result; + } + + private String createL() + { + if (DEBUG && debuglevel > 8) + debug(TRACE, "==> createL()"); + + String s = (String) properties.get(SRPRegistry.SRP_MANDATORY); + if (s == null) + { + s = SRPRegistry.DEFAULT_MANDATORY; + } + if (!SRPRegistry.MANDATORY_NONE.equals(s) + && !SRPRegistry.OPTION_REPLAY_DETECTION.equals(s) + && !SRPRegistry.OPTION_INTEGRITY.equals(s) + && !SRPRegistry.OPTION_CONFIDENTIALITY.equals(s)) + { + if (DEBUG && debuglevel > 4) + debug(WARN, "Unrecognised mandatory option (" + s + + "). Using default..."); + s = SRPRegistry.DEFAULT_MANDATORY; + } + + mandatory = s; + + s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY); + final boolean confidentiality = (s == null ? SRPRegistry.DEFAULT_CONFIDENTIALITY + : Boolean.valueOf(s).booleanValue()); + + s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION); + boolean integrity = (s == null ? SRPRegistry.DEFAULT_INTEGRITY + : Boolean.valueOf(s).booleanValue()); + + s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION); + final boolean replayDetection = (s == null ? SRPRegistry.DEFAULT_REPLAY_DETECTION + : Boolean.valueOf(s).booleanValue()); + + final StringBuffer sb = new StringBuffer(); + sb.append(SRPRegistry.OPTION_SRP_DIGEST).append("=").append( + srp.getAlgorithm()).append( + ","); + + if (!SRPRegistry.MANDATORY_NONE.equals(mandatory)) + { + sb.append(SRPRegistry.OPTION_MANDATORY).append("=").append(mandatory).append( + ","); + } + if (replayDetection) + { + sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(","); + // if replay detection is on then force integrity protection + integrity = true; + } + + int i; + if (integrity) + { + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + { + sb.append(SRPRegistry.OPTION_INTEGRITY).append("=").append( + SRPRegistry.INTEGRITY_ALGORITHMS[i]).append( + ","); + } + } + + if (confidentiality) + { + IBlockCipher cipher; + for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++) + { + cipher = CipherFactory.getInstance(SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]); + if (cipher != null) + { + sb.append(SRPRegistry.OPTION_CONFIDENTIALITY).append("=").append( + SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]).append( + ","); + } + } + } + + final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE).append( + "=").append( + Registry.SASL_BUFFER_MAX_LIMIT).toString(); + if (DEBUG && debuglevel > 8) + debug(TRACE, "<== createL()"); + return result; + } + + // Parse client's options and set security layer variables + private void parseO(final String o) throws AuthenticationException + { + this.replayDetection = false; + boolean integrity = false; + boolean confidentiality = false; + String option; + int i; + + final StringTokenizer st = new StringTokenizer(o.toLowerCase(), ","); + while (st.hasMoreTokens()) + { + option = st.nextToken(); + if (DEBUG && debuglevel > 6) + debug(TRACE, "option: <" + option + ">"); + if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION)) + { + replayDetection = true; + } + else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "=")) + { + if (integrity) + { + throw new AuthenticationException( + "Only one integrity algorithm may be chosen"); + } + else + { + option = option.substring(option.indexOf('=') + 1); + if (DEBUG && debuglevel > 6) + debug(TRACE, "algorithm: <" + option + ">"); + for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++) + { + if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option)) + { + chosenIntegrityAlgorithm = option; + integrity = true; + break; + } + } + if (!integrity) + { + throw new AuthenticationException( + "Unknown integrity algorithm: " + + option); + } + } + } + else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "=")) + { + if (confidentiality) + { + throw new AuthenticationException( + "Only one confidentiality algorithm may be chosen"); + } + else + { + option = option.substring(option.indexOf('=') + 1); + if (DEBUG && debuglevel > 6) + debug(TRACE, "algorithm: <" + option + ">"); + for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++) + { + if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option)) + { + chosenConfidentialityAlgorithm = option; + confidentiality = true; + break; + } + } + if (!confidentiality) + { + throw new AuthenticationException( + "Unknown confidentiality algorithm: " + + option); + } + } + } + else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=")) + { + final String maxBufferSize = option.substring(option.indexOf('=') + 1); + try + { + rawSendSize = Integer.parseInt(maxBufferSize); + if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT + || rawSendSize < 1) + throw new AuthenticationException( + "Illegal value for 'maxbuffersize' option"); + } + catch (NumberFormatException x) + { + throw new AuthenticationException( + SRPRegistry.OPTION_MAX_BUFFER_SIZE + + "=" + + String.valueOf(maxBufferSize), + x); + } + } + } + + // check if client did the right thing + if (replayDetection) + { + if (!integrity) + { + throw new AuthenticationException( + "Missing integrity protection algorithm " + + "but replay detection is chosen"); + } + } + if (mandatory.equals(SRPRegistry.OPTION_REPLAY_DETECTION)) + { + if (!replayDetection) + { + throw new AuthenticationException( + "Replay detection is mandatory but was not chosen"); + } + } + if (mandatory.equals(SRPRegistry.OPTION_INTEGRITY)) + { + if (!integrity) + { + throw new AuthenticationException( + "Integrity protection is mandatory but was not chosen"); + } + } + if (mandatory.equals(SRPRegistry.OPTION_CONFIDENTIALITY)) + { + if (!confidentiality) + { + throw new AuthenticationException( + "Confidentiality is mandatory but was not chosen"); + } + } + + int blockSize = 0; + if (chosenConfidentialityAlgorithm != null) + { + final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm); + if (cipher != null) + { + blockSize = cipher.defaultBlockSize(); + } + else + { // should not happen + throw new AuthenticationException("Confidentiality algorithm (" + + chosenConfidentialityAlgorithm + + ") not available"); + } + } + + sIV = new byte[blockSize]; + if (blockSize > 0) + getDefaultPRNG().nextBytes(sIV); + } + + private void setupSecurityServices(final boolean newSession) + throws SaslException + { + complete = true; // signal end of authentication phase + if (newSession) + { + outCounter = inCounter = 0; + // instantiate cipher if confidentiality protection filter is active + if (chosenConfidentialityAlgorithm != null) + { + if (DEBUG && debuglevel > 2) + debug(INFO, "Activating confidentiality protection filter"); + inCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + outCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + } + // instantiate hmacs if integrity protection filter is active + if (chosenIntegrityAlgorithm != null) + { + if (DEBUG && debuglevel > 2) + debug(INFO, "Activating integrity protection filter"); + inMac = IALG.getInstance(chosenIntegrityAlgorithm); + outMac = IALG.getInstance(chosenIntegrityAlgorithm); + } + + // generate a new sid if at least integrity is used + sid = (inMac != null ? ServerStore.getNewSessionID() : new byte[0]); + } + else + { // same session new keys + K = srp.generateKn(K, cn, sn); + } + + final KDF kdf = KDF.getInstance(K); + + // initialise in/out ciphers if confidentaility protection is used + if (inCipher != null) + { + outCipher.init(kdf, sIV, Direction.FORWARD); + inCipher.init(kdf, cIV, Direction.REVERSED); + } + // initialise in/out macs if integrity protection is used + if (inMac != null) + { + outMac.init(kdf); + inMac.init(kdf); + } + + if (sid != null && sid.length != 0) + { // update the security context and save in map + if (DEBUG && debuglevel > 2) + debug(INFO, "Updating security context for sid = " + new String(sid)); + ServerStore.instance().cacheSession( + ttl, + new SecurityContext( + srp.getAlgorithm(), + sid, + K, + cIV, + sIV, + replayDetection, + inCounter, + outCounter, + inMac, outMac, + inCipher, + outCipher)); + } + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/SecurityContext.java b/gnu/javax/crypto/sasl/srp/SecurityContext.java new file mode 100644 index 000000000..feca25cad --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/SecurityContext.java @@ -0,0 +1,164 @@ +/* SecurityContext.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +/** + *

A package-private placeholder for an SRP security context.

+ */ +class SecurityContext +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private String mdName; + + private byte[] sid; + + private byte[] K; + + private byte[] cIV; + + private byte[] sIV; + + private boolean replayDetection; + + private int inCounter; + + private int outCounter; + + private IALG inMac; + + private IALG outMac; + + private CALG inCipher; + + private CALG outCipher; + + // Constructor(s) + // ------------------------------------------------------------------------- + + SecurityContext(final String mdName, final byte[] sid, final byte[] K, + final byte[] cIV, final byte[] sIV, + final boolean replayDetection, final int inCounter, + final int outCounter, final IALG inMac, final IALG outMac, + final CALG inCipher, final CALG outCipher) + { + super(); + + this.mdName = mdName; + this.sid = sid; + this.K = K; + this.cIV = cIV; + this.sIV = sIV; + this.replayDetection = replayDetection; + this.inCounter = inCounter; + this.outCounter = outCounter; + this.inMac = inMac; + this.outMac = outMac; + this.inCipher = inCipher; + this.outCipher = outCipher; + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + String getMdName() + { + return mdName; + } + + byte[] getSID() + { + return sid; + } + + byte[] getK() + { + return K; + } + + byte[] getClientIV() + { + return cIV; + } + + byte[] getServerIV() + { + return sIV; + } + + boolean hasReplayDetection() + { + return replayDetection; + } + + int getInCounter() + { + return inCounter; + } + + int getOutCounter() + { + return outCounter; + } + + IALG getInMac() + { + return inMac; + } + + IALG getOutMac() + { + return outMac; + } + + CALG getInCipher() + { + return inCipher; + } + + CALG getOutCipher() + { + return outCipher; + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/ServerStore.java b/gnu/javax/crypto/sasl/srp/ServerStore.java new file mode 100644 index 000000000..99bf96a94 --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/ServerStore.java @@ -0,0 +1,196 @@ +/* ServerStore.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +import java.util.HashMap; + +/** + *

The server-side implementation of the SRP security context store.

+ */ +public class ServerStore +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The underlying singleton. */ + private static ServerStore singleton = null; + + /** The map of sid --> Security Context record. */ + private static final HashMap sid2ssc = new HashMap(); + + /** The map of sid --> Session timing record. */ + private static final HashMap sid2ttl = new HashMap(); + + /** A synchronisation lock. */ + private static final Object lock = new Object(); + + /** A counter to generate legible SIDs. */ + private static int counter = 0; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Private constructor to enforce Singleton pattern. */ + private ServerStore() + { + super(); + + // TODO: add a cleaning timer thread + } + + // Class methods + // ------------------------------------------------------------------------- + + /** + *

Returns the classloader Singleton.

+ * + * @return the classloader Singleton instance. + */ + static synchronized final ServerStore instance() + { + if (singleton == null) + { + singleton = new ServerStore(); + } + return singleton; + } + + /** + *

Returns a legible new session identifier.

+ * + * @return a new session identifier. + */ + static synchronized final byte[] getNewSessionID() + { + final String sid = String.valueOf(++counter); + return new StringBuffer("SID-").append( + "0000000000".substring( + 0, + 10 - sid.length())).append( + sid).toString().getBytes(); + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns a boolean flag indicating if the designated session is still + * alive or not.

+ * + * @param sid the identifier of the session to check. + * @return true if the designated session is still alive. + * false otherwise. + */ + boolean isAlive(final byte[] sid) + { + boolean result = false; + if (sid != null && sid.length != 0) + { + synchronized (lock) + { + final String key = new String(sid); + final StoreEntry ctx = (StoreEntry) sid2ttl.get(key); + if (ctx != null) + { + result = ctx.isAlive(); + if (!result) + { // invalidate it en-passant + sid2ssc.remove(key); + sid2ttl.remove(key); + } + } + } + } + return result; + } + + /** + *

Records a mapping between a session identifier and the Security Context + * of the designated SRP server mechanism instance.

+ * + * @param ttl the session's Time-To-Live indicator (in seconds). + * @param ctx the server's security context. + */ + void cacheSession(final int ttl, final SecurityContext ctx) + { + synchronized (lock) + { + final String key = new String(ctx.getSID()); + sid2ssc.put(key, ctx); + sid2ttl.put(key, new StoreEntry(ttl)); + } + } + + /** + *

Updates the mapping between the designated session identifier and the + * designated server's SASL Security Context. In the process, computes + * and return the underlying mechanism server's evidence that shall be + * returned to the client in a session re-use exchange.

+ * + * @param sid the identifier of the session to restore. + * @return an SRP server's security context. + */ + SecurityContext restoreSession(final byte[] sid) + { + final String key = new String(sid); + final SecurityContext result; + synchronized (lock) + { + result = (SecurityContext) sid2ssc.remove(key); + sid2ttl.remove(key); + } + return result; + } + + /** + *

Removes all information related to the designated session ID.

+ * + * @param sid the identifier of the seesion to invalidate. + */ + void invalidateSession(final byte[] sid) + { + final String key = new String(sid); + synchronized (lock) + { + sid2ssc.remove(key); + sid2ttl.remove(key); + } + } +} \ No newline at end of file diff --git a/gnu/javax/crypto/sasl/srp/StoreEntry.java b/gnu/javax/crypto/sasl/srp/StoreEntry.java new file mode 100644 index 000000000..c5041fa4b --- /dev/null +++ b/gnu/javax/crypto/sasl/srp/StoreEntry.java @@ -0,0 +1,89 @@ +/* StoreEntry.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.crypto.sasl.srp; + +/** + *

A simple timing-related object for use by SRP re-use code.

+ */ +class StoreEntry +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + private boolean perenial; + + private long timeToDie; + + // Constructor(s) + // ------------------------------------------------------------------------- + + StoreEntry(int ttl) + { + super(); + + if (ttl == 0) + { + perenial = true; + timeToDie = 0L; + } + else + { + perenial = false; + timeToDie = System.currentTimeMillis() + (ttl & 0xFFFFFFFFL) * 1000L; + } + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + /** + *

Returns true if the Time-To_live period has not elapsed.

+ * + * @return true if the Time-To-Live period (in seconds) has not + * elapsed yet; false otherwise. + */ + boolean isAlive() + { + return (perenial ? true : (System.currentTimeMillis() < timeToDie)); + } +} \ No newline at end of file diff --git a/gnu/javax/net/ssl/Base64.java b/gnu/javax/net/ssl/Base64.java new file mode 100644 index 000000000..52989da69 --- /dev/null +++ b/gnu/javax/net/ssl/Base64.java @@ -0,0 +1,311 @@ +/* Base64.java -- Base64 encoding and decoding. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + +-- +Base64 encoding derived from ISC's DHCP. Copyright notices from DHCP +follow. See http://www.isc.org/products/DHCP/. + +Copyright (c) 1996 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-- +Portions Copyright (c) 1995 by International Business Machines, Inc. + +International Business Machines, Inc. (hereinafter called IBM) grants +permission under its copyrights to use, copy, modify, and distribute +this Software with or without fee, provided that the above copyright +notice and all paragraphs of this notice appear in all copies, and +that the name of IBM not be used in connection with the marketing of +any product incorporating the Software or modifications thereof, +without specific, written prior permission. + +To the extent it has a right to do so, IBM grants an immunity from +suit under its patents, if any, for the use, sale or manufacture of +products to the extent that such products are used for performing +Domain Name System dynamic updates in TCP/IP networks by means of the +Software. No immunity is granted for any product per se or for any +other function of any product. + +THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, +DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE, EVEN IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH +DAMAGES. */ + + +package gnu.javax.net.ssl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public final class Base64 +{ + + // No constructor. + private Base64() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** Base-64 characters. */ + private static final String BASE_64 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** Base-64 padding character. */ + private static final char BASE_64_PAD = '='; + + /** + * Base64 encode a byte array, returning the returning string. + * + * @param buf The byte array to encode. + * @param tw The total length of any line, 0 for unlimited. + * @return buf encoded in Base64. + */ + public static String encode(byte[] buf, int tw) + { + int srcLength = buf.length; + byte[] input = new byte[3]; + int[] output = new int[4]; + StringBuffer out = new StringBuffer(); + int i = 0; + int chars = 0; + + while (srcLength > 2) + { + input[0] = buf[i++]; + input[1] = buf[i++]; + input[2] = buf[i++]; + srcLength -= 3; + + output[0] = (input[0] & 0xff) >>> 2; + output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); + output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); + output[3] = input[2] & 0x3f; + + out.append(BASE_64.charAt(output[0])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[1])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[2])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[3])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + } + + if (srcLength != 0) + { + input[0] = input[1] = input[2] = 0; + for (int j = 0; j < srcLength; j++) + { + input[j] = buf[i+j]; + } + output[0] = (input[0] & 0xff) >>> 2; + output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); + output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); + + out.append(BASE_64.charAt(output[0])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[1])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + if (srcLength == 1) + { + out.append(BASE_64_PAD); + } + else + { + out.append(BASE_64.charAt(output[2])); + } + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64_PAD); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + } + if (tw > 0) + { + out.append("\n"); + } + + return out.toString(); + } + + /** + * Decode a Base-64 string into a byte array. + * + * @param b64 The Base-64 encoded string. + * @return The decoded bytes. + * @throws java.io.IOException If the argument is not a valid Base-64 + * encoding. + */ + public static byte[] decode(String b64) throws IOException + { + ByteArrayOutputStream result = new ByteArrayOutputStream(b64.length() / 3); + int state = 0, i; + byte temp = 0; + + for (i = 0; i < b64.length(); i++) + { + if (Character.isWhitespace(b64.charAt(i))) + { + continue; + } + if (b64.charAt(i) == BASE_64_PAD) + { + break; + } + + int pos = BASE_64.indexOf(b64.charAt(i)); + if (pos < 0) + { + throw new IOException("non-Base64 character " + b64.charAt(i)); + } + switch (state) + { + case 0: + temp = (byte) (pos - BASE_64.indexOf('A') << 2); + state = 1; + break; + + case 1: + temp |= (byte) (pos - BASE_64.indexOf('A') >>> 4); + result.write(temp); + temp = (byte) ((pos - BASE_64.indexOf('A') & 0x0f) << 4); + state = 2; + break; + + case 2: + temp |= (byte) ((pos - BASE_64.indexOf('A') & 0x7f) >>> 2); + result.write(temp); + temp = (byte) ((pos - BASE_64.indexOf('A') & 0x03) << 6); + state = 3; + break; + + case 3: + temp |= (byte) (pos - BASE_64.indexOf('A') & 0xff); + result.write(temp); + state = 0; + break; + + default: + throw new Error("this statement should be unreachable"); + } + } + + if (i < b64.length() && b64.charAt(i) == BASE_64_PAD) + { + switch (state) + { + case 0: + case 1: + throw new IOException("malformed Base64 sequence"); + + case 2: + for ( ; i < b64.length(); i++) + { + if (!Character.isWhitespace(b64.charAt(i))) + { + break; + } + } + // We must see a second pad character here. + if (b64.charAt(i) != BASE_64_PAD) + { + throw new IOException("malformed Base64 sequence"); + } + i++; + // Fall-through. + + case 3: + i++; + for ( ; i < b64.length(); i++) + { + // We should only see whitespace after this. + if (!Character.isWhitespace(b64.charAt(i))) + { + System.err.println(b64.charAt(i)); + throw new IOException("malformed Base64 sequence"); + } + } + } + } + else + { + if (state != 0) + { + throw new IOException("malformed Base64 sequence"); + } + } + + return result.toByteArray(); + } +} diff --git a/gnu/javax/net/ssl/EntropySource.java b/gnu/javax/net/ssl/EntropySource.java new file mode 100644 index 000000000..be840e5d6 --- /dev/null +++ b/gnu/javax/net/ssl/EntropySource.java @@ -0,0 +1,62 @@ +/* EntropySource.java -- a source of random bits. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +/** + * A generic interface for adding random bytes to an entropy pool. + */ +public interface EntropySource +{ + + /** + * Returns the estimated quality of this source. This value should be + * between 0 and 100 (the running quality is computed as a percentage, + * 100 percent being perfect-quality). + * + * @return The quality. + */ + double quality(); + + /** + * Returns a new buffer with the next random bytes to add. + * + * @return The next random bytes. + */ + byte[] nextBytes(); +} diff --git a/gnu/javax/net/ssl/NullManagerParameters.java b/gnu/javax/net/ssl/NullManagerParameters.java new file mode 100644 index 000000000..0e9337932 --- /dev/null +++ b/gnu/javax/net/ssl/NullManagerParameters.java @@ -0,0 +1,56 @@ +/* NullManagerParameters.java -- parameters for empty managers. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +import javax.net.ssl.ManagerFactoryParameters; + +/** + * This empty class can be used to initialize {@link + * javax.net.ssl.KeyManagerFactory} and {@link + * javax.net.ssl.TrustManagerFactory} instances for the ``JessieX509'' + * algorithm, for cases when no keys or trusted certificates are + * desired or needed. + * + *

This is the default manager parameters object used in {@link + * javax.net.ssl.KeyManagerFactory} instances if no key stores are + * specified through security properties. + */ +public final class NullManagerParameters implements ManagerFactoryParameters +{ +} diff --git a/gnu/javax/net/ssl/PrivateCredentials.java b/gnu/javax/net/ssl/PrivateCredentials.java new file mode 100644 index 000000000..f602f98ae --- /dev/null +++ b/gnu/javax/net/ssl/PrivateCredentials.java @@ -0,0 +1,360 @@ +/* PrivateCredentials.java -- private key/certificate pairs. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +import java.math.BigInteger; + +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; + +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +import gnu.javax.security.auth.callback.ConsoleCallbackHandler; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.pad.WrongPaddingException; + +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; + +/** + * An instance of a manager factory parameters for holding a single + * certificate/private key pair, encoded in PEM format. + */ +public class PrivateCredentials implements ManagerFactoryParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + public static final String BEGIN_DSA = "-----BEGIN DSA PRIVATE KEY"; + public static final String END_DSA = "-----END DSA PRIVATE KEY"; + public static final String BEGIN_RSA = "-----BEGIN RSA PRIVATE KEY"; + public static final String END_RSA = "-----END RSA PRIVATE KEY"; + + private List privateKeys; + private List certChains; + + // Constructor. + // ------------------------------------------------------------------------- + + public PrivateCredentials() + { + privateKeys = new LinkedList(); + certChains = new LinkedList(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void add(InputStream certChain, InputStream privateKey) + throws CertificateException, InvalidKeyException, InvalidKeySpecException, + IOException, NoSuchAlgorithmException, WrongPaddingException + { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Collection certs = cf.generateCertificates(certChain); + X509Certificate[] chain = (X509Certificate[]) certs.toArray(new X509Certificate[0]); + + String alg = null; + String line = readLine(privateKey); + String finalLine = null; + if (line.startsWith(BEGIN_DSA)) + { + alg = "DSA"; + finalLine = END_DSA; + } + else if (line.startsWith(BEGIN_RSA)) + { + alg = "RSA"; + finalLine = END_RSA; + } + else + throw new IOException("Unknown private key type."); + + boolean encrypted = false; + String cipher = null; + String salt = null; + StringBuffer base64 = new StringBuffer(); + while (true) + { + line = readLine(privateKey); + if (line == null) + throw new EOFException("premature end-of-file"); + else if (line.startsWith("Proc-Type: 4,ENCRYPTED")) + encrypted = true; + else if (line.startsWith("DEK-Info: ")) + { + int i = line.indexOf(','); + if (i < 0) + cipher = line.substring(10).trim(); + else + { + cipher = line.substring(10, i).trim(); + salt = line.substring(i + 1).trim(); + } + } + else if (line.startsWith(finalLine)) + break; + else if (line.length() > 0) + { + base64.append(line); + base64.append(System.getProperty("line.separator")); + } + } + + byte[] enckey = Base64.decode(base64.toString()); + if (encrypted) + { + enckey = decryptKey(enckey, cipher, toByteArray(salt)); + } + + DERReader der = new DERReader(enckey); + if (der.read().getTag() != DER.SEQUENCE) + throw new IOException("malformed DER sequence"); + der.read(); // version + + KeyFactory kf = KeyFactory.getInstance(alg); + KeySpec spec = null; + if (alg.equals("DSA")) + { + BigInteger p = (BigInteger) der.read().getValue(); + BigInteger q = (BigInteger) der.read().getValue(); + BigInteger g = (BigInteger) der.read().getValue(); + der.read(); // y + BigInteger x = (BigInteger) der.read().getValue(); + spec = new DSAPrivateKeySpec(x, p, q, g); + } + else + { + spec = new RSAPrivateCrtKeySpec( + (BigInteger) der.read().getValue(), // modulus + (BigInteger) der.read().getValue(), // pub exponent + (BigInteger) der.read().getValue(), // priv expenent + (BigInteger) der.read().getValue(), // prime p + (BigInteger) der.read().getValue(), // prime q + (BigInteger) der.read().getValue(), // d mod (p-1) + (BigInteger) der.read().getValue(), // d mod (q-1) + (BigInteger) der.read().getValue()); // coefficient + } + privateKeys.add(kf.generatePrivate(spec)); + certChains.add(chain); + } + + public List getPrivateKeys() + { + if (isDestroyed()) + { + throw new IllegalStateException("this object is destroyed"); + } + return privateKeys; + } + + public List getCertChains() + { + return certChains; + } + + public void destroy() + { + privateKeys.clear(); + privateKeys = null; + } + + public boolean isDestroyed() + { + return (privateKeys == null); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private String readLine(InputStream in) throws IOException + { + boolean eol_is_cr = System.getProperty("line.separator").equals("\r"); + StringBuffer str = new StringBuffer(); + while (true) + { + int i = in.read(); + if (i == -1) + { + if (str.length() > 0) + break; + else + return null; + } + else if (i == '\r') + { + if (eol_is_cr) + break; + } + else if (i == '\n') + break; + else + str.append((char) i); + } + return str.toString(); + } + + private byte[] decryptKey(byte[] ct, String cipher, byte[] salt) + throws IOException, InvalidKeyException, WrongPaddingException + { + byte[] pt = new byte[ct.length]; + IMode mode = null; + if (cipher.equals("DES-EDE3-CBC")) + { + mode = ModeFactory.getInstance("CBC", "TripleDES", 8); + HashMap attr = new HashMap(); + attr.put(IMode.KEY_MATERIAL, deriveKey(salt, 24)); + attr.put(IMode.IV, salt); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + mode.init(attr); + } + else if (cipher.equals("DES-CBC")) + { + mode = ModeFactory.getInstance("CBC", "DES", 8); + HashMap attr = new HashMap(); + attr.put(IMode.KEY_MATERIAL, deriveKey(salt, 8)); + attr.put(IMode.IV, salt); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + mode.init(attr); + } + else + throw new IllegalArgumentException("unknown cipher: " + cipher); + + for (int i = 0; i < ct.length; i += 8) + mode.update(ct, i, pt, i); + + int pad = pt[pt.length-1]; + if (pad < 1 || pad > 8) + throw new WrongPaddingException(); + for (int i = pt.length - pad; i < pt.length; i++) + { + if (pt[i] != pad) + throw new WrongPaddingException(); + } + + byte[] result = new byte[pt.length - pad]; + System.arraycopy(pt, 0, result, 0, result.length); + return result; + } + + private byte[] deriveKey(byte[] salt, int keylen) + throws IOException + { + CallbackHandler passwordHandler = new ConsoleCallbackHandler(); + try + { + Class c = Class.forName(Security.getProperty("jessie.password.handler")); + passwordHandler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) { } + + PasswordCallback passwdCallback = + new PasswordCallback("Enter PEM passphrase: ", false); + try + { + passwordHandler.handle(new Callback[] { passwdCallback }); + } + catch (UnsupportedCallbackException uce) + { + throw new IOException("specified handler cannot handle passwords"); + } + char[] passwd = passwdCallback.getPassword(); + + IMessageDigest md5 = HashFactory.getInstance("MD5"); + byte[] key = new byte[keylen]; + int count = 0; + while (count < keylen) + { + for (int i = 0; i < passwd.length; i++) + md5.update((byte) passwd[i]); + md5.update(salt, 0, salt.length); + byte[] digest = md5.digest(); + int len = Math.min(digest.length, keylen - count); + System.arraycopy(digest, 0, key, count, len); + count += len; + if (count >= keylen) + break; + md5.reset(); + md5.update(digest, 0, digest.length); + } + passwdCallback.clearPassword(); + return key; + } + + private byte[] toByteArray(String hex) + { + hex = hex.toLowerCase(); + byte[] buf = new byte[hex.length() / 2]; + int j = 0; + for (int i = 0; i < buf.length; i++) + { + buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) | + Character.digit(hex.charAt(j++), 16)); + } + return buf; + } +} diff --git a/gnu/javax/net/ssl/SRPManagerParameters.java b/gnu/javax/net/ssl/SRPManagerParameters.java new file mode 100644 index 000000000..a2a745e1b --- /dev/null +++ b/gnu/javax/net/ssl/SRPManagerParameters.java @@ -0,0 +1,81 @@ +/* SRPManagerParameters.java -- Wrapper for SRP PasswordFile. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +import javax.net.ssl.ManagerFactoryParameters; +import gnu.javax.crypto.sasl.srp.PasswordFile; + +/** + * Instances of this class are used to initialize {@link + * javax.net.ssl.TrustManagerFactory} instances for the ``SRP'' algorithm. + */ +public class SRPManagerParameters implements ManagerFactoryParameters +{ + + // Field. + // ------------------------------------------------------------------------- + + private final PasswordFile file; + + // Constructor. + // ------------------------------------------------------------------------- + + /** + * Initializes these parameters with the specified SRP password file. + * + * @param file The SRP password file object. + * @throws NullPointerException if file is null. + */ + public SRPManagerParameters(PasswordFile file) + { + if (file == null) + { + throw new NullPointerException(); + } + this.file = file; + } + + // Instance method. + // ------------------------------------------------------------------------- + + public PasswordFile getPasswordFile() + { + return file; + } +} diff --git a/gnu/javax/net/ssl/SRPTrustManager.java b/gnu/javax/net/ssl/SRPTrustManager.java new file mode 100644 index 000000000..664fa4cab --- /dev/null +++ b/gnu/javax/net/ssl/SRPTrustManager.java @@ -0,0 +1,99 @@ +/* SRPTrustManager.java -- interface to SRP trust managers. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +import gnu.javax.crypto.sasl.srp.PasswordFile; + +import java.math.BigInteger; +import java.security.KeyPair; +import javax.net.ssl.TrustManager; + +/** + * A trust manager for secure remote password (SRP) key exchange cipher + * suites. This is a read-only interface to the {@link + * gnu.crypto.sasl.srp.PasswordFile} class, with convenience methods to + * generate session key pairs. + */ +public interface SRPTrustManager extends TrustManager +{ + + // Methods. + // ------------------------------------------------------------------------- + + /** + * Tests if the configured password file contains the specified user name. + * + * @param user The user name. + * @return True if the password file has an entry for user + */ + boolean contains(String user); + + /** + * Create and return a session SRP key pair for the given user name. + * + * @param user The user name to generate the key pair for. + * @return The session key pair, or null if there is no + * entry for user. + */ + KeyPair getKeyPair(String user); + + /** + * Returns the salt value for the given user. + * + * @param user The user name. + * @return The salt for user's entry, or null. + */ + byte[] getSalt(String user); + + /** + * Returns the password verifier for the given user. + * + * @param user The user name. + * @return user's password verifier, or null. + */ + BigInteger getVerifier(String user); + + /** + * Returns a reference to the SRP {@link PasswordFile} used by this + * {@link TrustManager}. + * + * @return a reference to the SRP password file in use. + */ + PasswordFile getPasswordFile(); +} diff --git a/gnu/javax/net/ssl/StaticTrustAnchors.java b/gnu/javax/net/ssl/StaticTrustAnchors.java new file mode 100644 index 000000000..0c2c3cca8 --- /dev/null +++ b/gnu/javax/net/ssl/StaticTrustAnchors.java @@ -0,0 +1,1942 @@ +/* StaticTrustAnchors.java -- static list of CA certificates. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import java.util.LinkedList; + +import javax.net.ssl.ManagerFactoryParameters; + +/** + * This class implements a simple set of trust anchors suitable for + * initializing a TrustManagerFactory for the "JessieX509" algorithm. + * + *

The important field of this class is the {@link #CA_CERTS} + * constant, which contains an array of commonly accepted CA + * certificates. + */ +public class StaticTrustAnchors implements ManagerFactoryParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + private X509Certificate[] certs; + + // Constructor. + // ------------------------------------------------------------------------- + + public StaticTrustAnchors(X509Certificate[] certs) + { + this.certs = (X509Certificate[]) certs.clone(); + } + + // Class method. + // ------------------------------------------------------------------------- + + public static X509Certificate generate(CertificateFactory factory, + String encoded) + { + try + { + ByteArrayInputStream in = + new ByteArrayInputStream(encoded.getBytes("UTF-8")); + return (X509Certificate) factory.generateCertificate(in); + } + catch (Exception x) + { + return null; + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public X509Certificate[] getCertificates() + { + return (X509Certificate[]) certs.clone(); + } + + // Constant. + // ------------------------------------------------------------------------- + + /** + * A list of known certificate authority certificates. This set of + * certificates is the same as the default CA certificates used by + * Mozilla. + */ + public static final StaticTrustAnchors CA_CERTS; + + // Static initializer. + // ------------------------------------------------------------------------- + + static + { + LinkedList certs = new LinkedList(); + CertificateFactory factory = null; + + try + { + factory = CertificateFactory.getInstance("X.509"); + } + catch (CertificateException ce) + { + throw new Error(ce.toString()); + } + + X509Certificate cert = generate(factory, + // ABAecom_=sub.__Am._Bankers_Assn.=_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEF\n" + + "BQAwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2Fz\n" + + "aGluZ3RvbjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFC\n" + + "QS5FQ09NIFJvb3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3Ry\n" + + "dXN0LmNvbTAeFw05OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQsw\n" + + "CQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24x\n" + + "FzAVBgNVBAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBS\n" + + "b290IENBMSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20w\n" + + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0xHgeVVDBwhMywVC\n" + + "AOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM0KLMsFWWU4RmBQDaREmA2FQK\n" + + "pSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFGPR7wuSw0X4x8TAgpnUBV\n" + + "6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGULOR4SCQaJRk665Wc\n" + + "OQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZsiSrK2jMTecJV\n" + + "jO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU+/94Qby9\n" + + "cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYBAf8C\n" + + "AQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k\n" + + "qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvT\n" + + "ZOirvRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHeg\n" + + "TYjHInYZw8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm\n" + + "/lowdiT/QHI8eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgx\n" + + "fexgeqMiKL0ZJGA/O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJ\n" + + "TzFxiNmIf1Q=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AOL_Time_Warner_Root_Certification_Authority_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC\n" + + "VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB\n" + + "bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg\n" + + "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAw\n" + + "MFoXDTM3MTEyMDE1MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB\n" + + "T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg\n" + + "SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh\n" + + "dGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" + + "ggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U0pPlLYnKhHw/EEMbjIt8hFj4JHxI\n" + + "zyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItITuLCxFlpMGK2MKKMCxGZYTVt\n" + + "fu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAfRC+iYkGzuxgh28pxPIzs\n" + + "trkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqFzQ6axOAAsNUl6twr\n" + + "5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqhBC4aMqiaILGc\n" + + "LCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEAAaNjMGEw\n" + + "DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jYPXy+\n" + + "XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/\n" + + "BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNM\n" + + "eUWn9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7\n" + + "CegCgTXTCt8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77Bf\n" + + "WgDrvq2g+EQFZ7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oT\n" + + "LW4jYYehY0KswsuXn2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCz\n" + + "vhGbRWeDhhmH05i9CBoWH1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmw\n" + + "X7A5KGgOc90lmt4S\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AOL_Time_Warner_Root_Certification_Authority_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC\n" + + "VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB\n" + + "bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg\n" + + "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAw\n" + + "MFoXDTM3MDkyODIzNDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB\n" + + "T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg\n" + + "SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh\n" + + "dGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\n" + + "ggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ7ouZzU9AhqS2TcnZsdw8TQ2FTBVs\n" + + "RotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilbm2BPJoPRYxJWSXakFsKlnUWs\n" + + "i4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOYxFSMFkpBd4aVdQxHAWZg\n" + + "/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZYYCLqJV+FNwSbKTQ\n" + + "2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbqJS5Gr42whTg0\n" + + "ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fxI2rSAG2X\n" + + "+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETzkxml\n" + + "J85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh\n" + + "EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNo\n" + + "Kk/SBtc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJ\n" + + "Kg71ZDIMgtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1Ex\n" + + "MVCgyhwn2RAurda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMB\n" + + "Af8wHQYDVR0OBBYEFE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaA\n" + + "FE9pbQN+nZ8HGEO8txBO1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG\n" + + "9w0BAQUFAAOCAgEAO/Ouyuguh4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0\n" + + "cnAxa8cZmIDJgt43d15Ui47y6mdPyXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRF\n" + + "ASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q7C+qPBR7V8F+GBRn7iTGvboVsNIY\n" + + "vbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKTRuidDV29rs4prWPVVRaAMCf/\n" + + "drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ClTluUI8JPu3B5wwn3la\n" + + "5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyBM5kYJRF3p+v9WAks\n" + + "mWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQmy8YJPamTQr5\n" + + "O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xOAU++CrYD\n" + + "062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT9Y41\n" + + "xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H\n" + + "hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOL\n" + + "Z8/5fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_External_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4\n" + + "dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h\n" + + "bCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzEL\n" + + "MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1B\n" + + "ZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1\n" + + "c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n" + + "AQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8\n" + + "k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50\n" + + "ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504\n" + + "B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDez\n" + + "eWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5\n" + + "aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB\n" + + "3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQD\n" + + "AgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6\n" + + "xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU\n" + + "cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdv\n" + + "cmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJ\n" + + "KoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl\n" + + "j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5R\n" + + "xNKWt9x+Tu5w/Rw56wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjT\n" + + "K3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1\n" + + "n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHx\n" + + "REzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49O\n" + + "hgQ=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Low-Value_Services_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\n" + + "HhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw\n" + + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwze\n" + + "xODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGI\n" + + "gb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0O\n" + + "M3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1Lc\n" + + "sRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5\n" + + "mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG\n" + + "9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCU\n" + + "tr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/\n" + + "MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQsw\n" + + "CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk\n" + + "ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAx\n" + + "IENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0\n" + + "MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph\n" + + "iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9\n" + + "tTEv2dB8Xfjea4MYeDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL\n" + + "/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlV\n" + + "g3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6\n" + + "tkD9xOQ14R0WHNC8K47Wcdk=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Public_Services_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAe\n" + + "Fw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNF\n" + + "MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ\n" + + "IE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIB\n" + + "IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+\n" + + "A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c\n" + + "+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2\n" + + "P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKX\n" + + "C1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8R\n" + + "s3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9\n" + + "BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAf\n" + + "d59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCB\n" + + "jgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkG\n" + + "A1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU\n" + + "cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENB\n" + + "IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmu\n" + + "G7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL\n" + + "+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbj\n" + + "PGsye/Kf8Lb93/AoGEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bY\n" + + "GozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6\n" + + "NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9HEufOX1362Kqx\n" + + "My3ZdvJOOjMMK7MtkAY=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // AddTrust_Qualified_Certificates_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJT\n" + + "RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU\n" + + "UCBOZXR3b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9v\n" + + "dDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYT\n" + + "AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg\n" + + "VFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBS\n" + + "b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoek\n" + + "n0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKk\n" + + "IhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6z\n" + + "sLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1t\n" + + "UvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R\n" + + "+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvES\n" + + "a0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5\n" + + "lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw\n" + + "AwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkw\n" + + "ZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL\n" + + "ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVh\n" + + "bGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2Vh\n" + + "lRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG\n" + + "GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx9\n" + + "5dr6h+sNNVJn0J6XdgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKF\n" + + "Yqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVA\n" + + "wRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQw\n" + + "dOUeqN48Jzd/g66ed8/wMLH/S5noxqE=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // America_Online_Root_Certification_Authority_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l\n" + + "cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4X\n" + + "DTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMx\n" + + "HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp\n" + + "Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw\n" + + "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCa\n" + + "xlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CGv2BlnEtUiMJIxUo5vxTjWVXl\n" + + "GbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44zDyL9Hy7n\n" + + "BzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145Lcx\n" + + "VR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiE\n" + + "mf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCu\n" + + "JKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n" + + "HQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Zo/Z5\n" + + "9m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUA\n" + + "A4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF\n" + + "Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOM\n" + + "IOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTI\n" + + "dGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g\n" + + "Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j\n" + + "8uB9Gr784N/Xx6dssPmuujz9dLQR6FgNgLzTqIA6me11zEZ7\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // America_Online_Root_Certification_Authority_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l\n" + + "cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4X\n" + + "DTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMx\n" + + "HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp\n" + + "Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw\n" + + "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssN\n" + + "t79Hc9PwVU3dxgz6sWYFas14tNwC206B89enfHG8dWOgXeMHDEjsJcQDIPT/\n" + + "DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8f3SkWq7x\n" + + "uhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE\n" + + "18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxr\n" + + "kJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMD\n" + + "bi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8BPeraunzgWGcX\n" + + "uVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn6KVu\n" + + "Y8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9\n" + + "W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ\n" + + "o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48\n" + + "ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124Hhn\n" + + "AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op\n" + + "aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNee\n" + + "MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypL\n" + + "M7PmG2tZTiLMubekJcmnxPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qf\n" + + "tIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjR\n" + + "Ywu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R\n" + + "+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr\n" + + "+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVM\n" + + "nNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMADjMSW7yV5TKQqLPGbIOt\n" + + "d+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh1NolNscI\n" + + "WC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZ\n" + + "ZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y\n" + + "3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz\n" + + "2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw\n" + + "RY8mkaKO/qk=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Code_Signing_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDpjCCAo6gAwIBAgIEAgAAvzANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MS8wLQYDVQQDEyZCYWx0aW1vcmUgQ3liZXJUcnVzdCBDb2RlIFNpZ25pbmcg\n" + + "Um9vdDAeFw0wMDA1MTcxNDAxMDBaFw0yNTA1MTcyMzU5MDBaMGcxCzAJBgNV\n" + + "BAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1\n" + + "c3QxLzAtBgNVBAMTJkJhbHRpbW9yZSBDeWJlclRydXN0IENvZGUgU2lnbmlu\n" + + "ZyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHGaGBKO\n" + + "etv5mvxBr9jy9AmOrT/+Zzc82skmULGxPsvoTnMA8rLc88VG+wnvGJbOp+Cc\n" + + "hF0gDnqgqjaL+ii2eC6z7OhH8wTwkCO06q/lU7gF90ddK4bxp6TGOzW20g1S\n" + + "Qdf0knXhogpQVoe+lwt7M4UQuSgY7jPqSBHXW5FHdiLU7s9d56hOHJ2Wkd2c\n" + + "vXQJqHJhqrAhOvE9LANWCdLB3MO1x1Q3q+YmorJGcXPKEYjuvOdk99ARGnNA\n" + + "WshJLA+375B/aIAEOAsbDzvU9aCzwo7hNLSAmW2edtSSKUCxldI3pGcSf+Bi\n" + + "u641xZk2gkS45ngYM2Fxk1stjZ94lYLrbQIDAQABo1owWDATBgNVHSUEDDAK\n" + + "BggrBgEFBQcDAzAdBgNVHQ4EFgQUyEE0XBUVBOVA8tGrmm8kknqHQlowEgYD\n" + + "VR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEF\n" + + "BQADggEBAFJ0qpVLIozHPZak/l36L7W86/AL6VY4HdFtDaG8aIvwxYClJDT9\n" + + "8pYYEYahNvU351RA1WQfw19wQmstOceeUgXO52py0o1yP0dQg6vHjSXJsOOn\n" + + "UxaVpmpT6hidj3ipd3ca+bSXR1mIJyi1yuEu1z4Oog24IkQD49FjsEE6ofWk\n" + + "Lfd2HgRUmXgyQNcrfE26ppyweW4Hvozs7tc4aVvBDFZon/7r0eHIiPnyzX++\n" + + "hbREZwBQPvQmA2Tqd33oXj4cN0fI1uqk8zY8l8I5cgWUGSXD1zdBD8Efh4r9\n" + + "qr7psWRX5NuSoc/hSeg7H5ETWsOP2SVYSYBHD8YDrqzjv7fAqio=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Mobile_Commerce_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICfTCCAeagAwIBAgIEAgAAuDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MSkwJwYDVQQDEyBCYWx0aW1vcmUgQ3liZXJUcnVzdCBNb2JpbGUgUm9vdDAe\n" + + "Fw0wMDA1MTIxODIwMDBaFw0yMDA1MTIyMzU5MDBaMGExCzAJBgNVBAYTAklF\n" + + "MRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxKTAn\n" + + "BgNVBAMTIEJhbHRpbW9yZSBDeWJlclRydXN0IE1vYmlsZSBSb290MIGfMA0G\n" + + "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjbbE4Vqz8tVYh3sCQXSZHgsZ9jx+g\n" + + "hY8vu9ThHB3yJB8osC+5pKVvoiIgZP6ERzx+K2xparjUwJaOjFINzW9B1L8E\n" + + "rqeBLy2YSNLBlKO1GV1dUWT0jkGwm8AtIqBexthaEmO8EUpeJhId4iYF5g9f\n" + + "Ih96X3aUrs9aKA6rRdoiMQIDAQABo0IwQDAdBgNVHQ4EFgQUyeKPwAImWrbA\n" + + "B+N/lAcY2y6lmnAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw\n" + + "DQYJKoZIhvcNAQEFBQADgYEAUwgLJgl4QnPU7Hp3Rw3jCzNx764zFE37+v0a\n" + + "t1H15JkcBnHXKRnX5hUgUVFGbU/eGEmY0Ph4u3HojQEG1ddkj5TfR/6ghWk2\n" + + "qS9CemhKEtaLC3BECqQE7yaIwTVxOF0bW0hC8OeUHHCVNKir9avieK318FL9\n" + + "m+pCDOjYVL5TZvU=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Baltimore_CyberTrust_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG\n" + + "EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0\n" + + "MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUx\n" + + "MjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNV\n" + + "BAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZ\n" + + "QmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD\n" + + "ggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+h\n" + + "Xe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gR\n" + + "QKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP\n" + + "wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1\n" + + "pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNT\n" + + "Px8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkC\n" + + "AwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1Ud\n" + + "EwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA\n" + + "A4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkT\n" + + "I7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n" + + "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/\n" + + "oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67\n" + + "G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H\n" + + "RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG\n" + + "EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw\n" + + "DwYDVQQLEwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQw\n" + + "MjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy\n" + + "ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEB\n" + + "AQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlR\n" + + "EmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth\n" + + "zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0\n" + + "dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E\n" + + "YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg\n" + + "U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIx\n" + + "MDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3\n" + + "pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNV\n" + + "HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3\n" + + "DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN\n" + + "QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomA\n" + + "sH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6\n" + + "w4pl\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGp\n" + + "MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM\n" + + "YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv\n" + + "LjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx\n" + + "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDEx\n" + + "ODE4NTVaFw0wODExMjgxODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE\n" + + "CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp\n" + + "Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDEx\n" + + "FjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRp\n" + + "Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" + + "ANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdfWvnTLnUv2Chi0ZMv/E3U\n" + + "q4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uKxBmd9LIO/BZsubEF\n" + + "koPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBEzUNKcI5YhZXh\n" + + "TizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F5X5yP4Wd\n" + + "lGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMvOnNn\n" + + "7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG\n" + + "9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+\n" + + "LegzZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvV\n" + + "WlHG4VMElo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX\n" + + "8ngvYzZAOONGDx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn8\n" + + "6Oawde3uPclwx12qgUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsT\n" + + "F7ANUkz+/m9c4pFuHf2kYtdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG\n" + + "EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw\n" + + "DwYDVQQLEwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3\n" + + "MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy\n" + + "ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEB\n" + + "AQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fB\n" + + "w18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e\n" + + "ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd\n" + + "55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E\n" + + "YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg\n" + + "U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIw\n" + + "OTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6s\n" + + "NS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNV\n" + + "HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3\n" + + "DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR\n" + + "xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLb\n" + + "dHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlih\n" + + "w6ID\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Digital_Signature_Trust_Co._Global_CA_4.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGp\n" + + "MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM\n" + + "YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv\n" + + "LjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx\n" + + "ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAy\n" + + "MjQ2MTZaFw0wODExMjcyMjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE\n" + + "CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp\n" + + "Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIx\n" + + "FjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRp\n" + + "Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" + + "ANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbVp9oaBBg5kkp4o4HC9Xd6\n" + + "ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWwBZoPFflrWXJW8vo5\n" + + "/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl5WJp3OXuAFK9\n" + + "MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi3sOP17ih\n" + + "YqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+QVCv\n" + + "bK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG\n" + + "9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWog\n" + + "WxyQ2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6\n" + + "HE3K1GjNI3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV\n" + + "6YyDfFk/xPEL553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8\n" + + "PzGn0EdzMzkbzE5q10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30\n" + + "sPDst2yC7S8xmUJMqbINuBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Global_Secure_Personal_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NB\n" + + "X0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT\n" + + "HChjKSAyMDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1\n" + + "c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAy\n" + + "MDcxNjE2NDBaFw0yMDAyMDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0\n" + + "Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29y\n" + + "cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg\n" + + "RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xp\n" + + "ZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA\n" + + "A4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7NySpj10InJrWPNTTVRaoTU\n" + + "rcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0iJBeAZfv6lOm3fzB\n" + + "3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn5JVn1j+SgF7y\n" + + "NH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHdBgNVHR8E\n" + + "gdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAw\n" + + "PgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy\n" + + "ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0\n" + + "Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2Vy\n" + + "dGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw\n" + + "IoAPMjAwMDAyMDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQD\n" + + "AgEGMB8GA1UdIwQYMBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQW\n" + + "BBSEi3T9xY3A/ydtIDdFfP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2\n" + + "fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWA\n" + + "O9GK9Q6nIMstZVXQkvTnhLUGJoMShAusO7JE7r3PQNsgDrpuFOow4DtifH+L\n" + + "a3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/GpsKkMWr2tGzhtQvJFJcem3G8v7l\n" + + "TRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKdzmVml64mXg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Global_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xf\n" + + "Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc\n" + + "KGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVz\n" + + "dC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe\n" + + "Fw0wMDAyMDQxNzIwMDBaFw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtF\n" + + "bnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMg\n" + + "aW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg\n" + + "MjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5l\n" + + "dCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G\n" + + "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO8GCGD9JYf9Mzly0XonUw\n" + + "tZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaBbL3+qPZ1V1eMkGxK\n" + + "wz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2dWcTC5/oVzbI\n" + + "XQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4QgEBBAQD\n" + + "AgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoTC0Vu\n" + + "dHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp\n" + + "bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAy\n" + + "MDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0\n" + + "IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIw\n" + + "NDE3NTAwMFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc\n" + + "/vuLkpyw8m4iMB0GA1UdDgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNV\n" + + "HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkq\n" + + "hkiG9w0BAQQFAAOBgQBi24GRzsiad0Iv7L0no1MPUBvqTpLwqa+poLpIYcvv\n" + + "yQbvH9X07t9WLebKahlzqlO+krNQAraFJnJj2HVQYnUUt7NQGj/KEQALhUVp\n" + + "bbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1UyrrJzOCE98g+EZfTYAkYvAX/\n" + + "bIkz8OwVDw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Premium_2048_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UE\n" + + "ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNf\n" + + "MjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT\n" + + "HChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1\n" + + "c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEy\n" + + "MjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0\n" + + "Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29y\n" + + "cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkg\n" + + "RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2Vy\n" + + "dGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEF\n" + + "AAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4\n" + + "QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC\n" + + "DNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj\n" + + "/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLP\n" + + "KQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZd\n" + + "enoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH\n" + + "4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB\n" + + "0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ\n" + + "FrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFh\n" + + "fGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVU\n" + + "KcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaoho\n" + + "wXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2\n" + + "+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888\n" + + "6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Secure_Personal_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE\n" + + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50\n" + + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs\n" + + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp\n" + + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0\n" + + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa\n" + + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV\n" + + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw\n" + + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50\n" + + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50\n" + + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL\n" + + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv\n" + + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV\n" + + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173\n" + + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw\n" + + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50\n" + + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff\n" + + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE\n" + + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50\n" + + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD\n" + + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D\n" + + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx\n" + + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW\n" + + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG\n" + + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI\n" + + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ\n" + + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU\n" + + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE\n" + + "PHayXOw=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Entrust.net_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UE\n" + + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50\n" + + "cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl\n" + + "MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UE\n" + + "AxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw\n" + + "CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3\n" + + "dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlh\n" + + "Yi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTow\n" + + "OAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp\n" + + "b24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0\n" + + "VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHIN\n" + + "iC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHk\n" + + "mGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHT\n" + + "MBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHY\n" + + "pIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5\n" + + "BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChs\n" + + "aW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBM\n" + + "aW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl\n" + + "cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNo\n" + + "dHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAi\n" + + "gA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMC\n" + + "AQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYE\n" + + "FPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9\n" + + "B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKn\n" + + "CqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2Zcgx\n" + + "xufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6\n" + + "rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG\n" + + "EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1\n" + + "cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4\n" + + "MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgx\n" + + "LTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0\n" + + "eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2R\n" + + "FGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO\n" + + "/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuv\n" + + "K9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRp\n" + + "MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEt\n" + + "MCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5\n" + + "MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjAL\n" + + "BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9Qw\n" + + "HQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8w\n" + + "GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB\n" + + "AFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y\n" + + "7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2u\n" + + "FHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_Global_eBusiness_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1\n" + + "aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0\n" + + "MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoT\n" + + "E0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJl\n" + + "IEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" + + "gYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQy\n" + + "td4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORR\n" + + "OhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2EC\n" + + "AwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "HwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6o\n" + + "oHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf\n" + + "2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxa\n" + + "z2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1\n" + + "pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_eBusiness_CA_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJV\n" + + "UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1\n" + + "aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcN\n" + + "MjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZh\n" + + "eCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2lu\n" + + "ZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fe\n" + + "k6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5\n" + + "/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXW\n" + + "HXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCG\n" + + "SAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4\n" + + "MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBq\n" + + "R3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnm\n" + + "JXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1\n" + + "tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYr\n" + + "tWKmpj29f5JZzVoqgrI3eQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Equifax_Secure_eBusiness_CA_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG\n" + + "EwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlm\n" + + "YXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5\n" + + "MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXgg\n" + + "U2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0Et\n" + + "MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF\n" + + "7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKD\n" + + "pkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HM\n" + + "HMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRp\n" + + "MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBT\n" + + "ZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y\n" + + "MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjAL\n" + + "BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYw\n" + + "HQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8w\n" + + "GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB\n" + + "AAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy\n" + + "0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkt\n" + + "y3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GTE_CyberTrust_Global_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw\n" + + "FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy\n" + + "dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg\n" + + "R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1\n" + + "MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD\n" + + "VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT\n" + + "GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA\n" + + "A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4\n" + + "ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn\n" + + "ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F\n" + + "LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3\n" + + "46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq\n" + + "81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d\n" + + "XIVtx6quTx8itc2VrbqnzPmrC3p/\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GTE_CyberTrust_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgw\n" + + "FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRy\n" + + "dXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQsw\n" + + "CQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQD\n" + + "ExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n" + + "iQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8K\n" + + "DPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPw\n" + + "KfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwID\n" + + "AQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD\n" + + "+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGv\n" + + "U9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e\n" + + "6bR64eVaH4QwnNOfpSXY\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GeoTrust_Global_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYT\n" + + "AlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVz\n" + + "dCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBC\n" + + "MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE\n" + + "AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + + "MIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEH\n" + + "CIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlC\n" + + "GDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7\n" + + "csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAj\n" + + "Nvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdRe\n" + + "JivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQAB\n" + + "o1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9\n" + + "qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkq\n" + + "hkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Qzxpe\n" + + "R+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWV\n" + + "Yrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n" + + "PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot\n" + + "2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeX\n" + + "xx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm\n" + + "Mw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // GlobalSign_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzEL\n" + + "MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNV\n" + + "BAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05\n" + + "ODA5MDExMjAwMDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkw\n" + + "FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRsw\n" + + "GQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR\n" + + "4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc\n" + + "71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4\n" + + "bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgK\n" + + "OOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMW\n" + + "ea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DP\n" + + "AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQUYHtmGkUNl8qJ\n" + + "UC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOC\n" + + "AQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq75bCd\n" + + "PTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q\n" + + "gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT\n" + + "2iHRrH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlD\n" + + "NPYPhyk7ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBg\n" + + "Hcl5JLL2bP2oZg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Root_Certificate_1.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f\n" + + "NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM\n" + + "MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34\n" + + "t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b\n" + + "e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu\n" + + "PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A\n" + + "PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Security_1024_v3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF\n" + + "ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg\n" + + "U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx\n" + + "NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT\n" + + "QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" + + "gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY\n" + + "rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt\n" + + "bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB\n" + + "o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME\n" + + "GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N\n" + + "AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy\n" + + "HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9\n" + + "am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B\n" + + "qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // RSA_Security_2048_v3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF\n" + + "ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg\n" + + "U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5\n" + + "MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT\n" + + "QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + + "CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37\n" + + "RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E\n" + + "0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J\n" + + "6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq\n" + + "s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD\n" + + "uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw\n" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW\n" + + "gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6\n" + + "/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V\n" + + "EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g\n" + + "EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+\n" + + "f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq\n" + + "aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk\n" + + "llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA\n" + + "pKnXwiJPZ9d37CAFYd4=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // TC_TrustCenter__Germany__Class_2_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT\n" + + "AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD\n" + + "VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3\n" + + "b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENB\n" + + "MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe\n" + + "Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE\n" + + "RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE\n" + + "ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y\n" + + "a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEp\n" + + "MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w\n" + + "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmk\n" + + "qYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJO\n" + + "gtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8/vhYnvgpjbB7\n" + + "zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy\n" + + "dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n" + + "CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+W\n" + + "LDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xR\n" + + "T3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/Ac\n" + + "ASZ4smZHcFFk\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // TC_TrustCenter__Germany__Class_3_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT\n" + + "AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD\n" + + "VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3\n" + + "b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENB\n" + + "MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe\n" + + "Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE\n" + + "RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE\n" + + "ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y\n" + + "a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEp\n" + + "MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w\n" + + "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQ\n" + + "GwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYn\n" + + "v68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDWw1Krj10nnGvA\n" + + "o+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w\n" + + "DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy\n" + + "dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G\n" + + "CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4\n" + + "iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yC\n" + + "GdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQS\n" + + "CdS7kjXvD9s0\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Basic_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl\n" + + "cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp\n" + + "Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow\n" + + "gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV\n" + + "BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm\n" + + "BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV\n" + + "BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ\n" + + "cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB\n" + + "jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK\n" + + "P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ\n" + + "fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j\n" + + "kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB\n" + + "gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7\n" + + "c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95\n" + + "B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Freemail_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl\n" + + "cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m\n" + + "cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz\n" + + "NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx\n" + + "EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp\n" + + "bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x\n" + + "JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG\n" + + "SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq\n" + + "hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N\n" + + "j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef\n" + + "QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY\n" + + "x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq\n" + + "hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP\n" + + "MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC\n" + + "neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr\n" + + "5PjRzneigQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Personal_Premium_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm\n" + + "aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl\n" + + "cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy\n" + + "ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5\n" + + "NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw\n" + + "EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n\n" + + "MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw\n" + + "IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3\n" + + "DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7\n" + + "7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j\n" + + "Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq\n" + + "W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\n" + + "DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH\n" + + "b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx\n" + + "eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1\n" + + "KzGJ\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Premium_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy\n" + + "dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl\n" + + "IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl\n" + + "cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1\n" + + "OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ\n" + + "BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg\n" + + "Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x\n" + + "ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3\n" + + "DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B\n" + + "AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI\n" + + "NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL\n" + + "lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN\n" + + "9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B\n" + + "AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI\n" + + "hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ\n" + + "a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU\n" + + "Qg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du\n" + + "MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy\n" + + "dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl\n" + + "IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0\n" + + "ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG\n" + + "A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw\n" + + "ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE\n" + + "CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ\n" + + "VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz\n" + + "QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I\n" + + "/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC\n" + + "6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX\n" + + "TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G\n" + + "A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD\n" + + "TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e\n" + + "QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni\n" + + "TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Thawte_Time_Stamping_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC\n" + + "WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls\n" + + "bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj\n" + + "YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw\n" + + "MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT\n" + + "BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN\n" + + "BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x\n" + + "HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN\n" + + "AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8\n" + + "WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR\n" + + "5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7\n" + + "X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN\n" + + "AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK\n" + + "0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8\n" + + "zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ\n" + + "SdM=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // UTN-USER_First-Network_Applications.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUF\n" + + "ADCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0\n" + + "IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw\n" + + "HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVU\n" + + "Ti1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0\n" + + "ODM5WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgT\n" + + "AlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVT\n" + + "RVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz\n" + + "dC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNh\n" + + "dGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZV\n" + + "hawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAb\n" + + "GHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZ\n" + + "NaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hAReYFmnjDRy7rh4\n" + + "xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwiP8vv\n" + + "/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7i\n" + + "gEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD\n" + + "AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf\n" + + "8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0\n" + + "LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G\n" + + "CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXh\n" + + "i6r/fWRRzwr/vH3YIWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUq\n" + + "f9FuVSTiuwL7MT++6LzsQCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAf\n" + + "hZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvP\n" + + "NximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+\n" + + "FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjis\n" + + "H8SE\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_Class_1_VA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw\n" + + "8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m\n" + + "+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSN\n" + + "dnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+V\n" + + "YH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8so\n" + + "gTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw\n" + + "nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_Class_2_VA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD\n" + + "ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRp\n" + + "b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv\n" + + "bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy\n" + + "NjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x\n" + + "NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x\n" + + "IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3\n" + + "DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc\n" + + "65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQ\n" + + "b7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcn\n" + + "wbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4\n" + + "OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZ\n" + + "oDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC\n" + + "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // ValiCert_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDSDCCArGgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjEkMCIGA1UEBxMb\n" + + "VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2Vy\n" + + "dCwgSW5jLjEsMCoGA1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0\n" + + "eSAtIE9DU1AxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEg\n" + + "MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb20wHhcNMDAwMjEyMTE1\n" + + "MDA1WhcNMDUwMjEwMTE1MDA1WjCBsjEkMCIGA1UEBxMbVmFsaUNlcnQgVmFs\n" + + "aWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjEsMCoG\n" + + "A1UECxMjQ2xhc3MgMSBWYWxpZGF0aW9uIEF1dGhvcml0eSAtIE9DU1AxITAf\n" + + "BgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQubmV0LzEgMB4GCSqGSIb3DQEJ\n" + + "ARYRaW5mb0B2YWxpY2VydC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ\n" + + "AoGBAMeML6fDQIc7PdfEmlgUZArDCDliGs/S66nxaXSKyg5adsyiUk7Q88R6\n" + + "tfimHLujp6RTh1uNwAC71WYk53TGFsivyANi1TKHolKRRJSVqEdDbaVInPZM\n" + + "ddVPYufJ/3v0JIynvCh2tTKgJXO3Ry94+Eb5hxTwd/wKd+hP/Ywf+mLZAgMB\n" + + "AAGjbDBqMA8GCSsGAQUFBzABBQQCBQAwEwYDVR0lBAwwCgYIKwYBBQUHAwkw\n" + + "CwYDVR0PBAQDAgGGMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0\n" + + "cDovL29jc3AyLnZhbGljZXJ0Lm5ldDANBgkqhkiG9w0BAQUFAAOBgQAVxeC4\n" + + "NHISBiCoYpWT0byTupCr3E6Njo2YTOMy9Ss/s5f7qqKtQJetaL1crVMO0Kaz\n" + + "DawamY2qMB7PDnD/ArB3ZYPN2gdcUs1Zu6LI4rQWg4/UlXmTLei/RJMxkjDT\n" + + "NDTxEPshrC70w11kY3qZ4ZqrQh1IZqZ3N7hVPK3+ZbBi6Q==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8x\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UE\n" + + "CxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eTAeFw05NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNV\n" + + "BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh\n" + + "c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCB\n" + + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3\n" + + "noaACpEO+jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B\n" + + "9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg\n" + + "1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBM\n" + + "P7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZoEWx8QszznC7EBz8UsA9P\n" + + "/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5FvjqBUuUfx3CHMjj\n" + + "t/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89FxlA==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq\n" + + "0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9\n" + + "Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSmFc/IReumXY6c\n" + + "PvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9Zr\n" + + "bWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul\n" + + "uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4i\n" + + "P/68DzFc6PLZ\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRR\n" + + "ZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO8ESlV8dAWB6j\n" + + "Rx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJrKsh\n" + + "JlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7P\n" + + "oBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2\n" + + "6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHh\n" + + "v2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQ\n" + + "BfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N\n" + + "y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUf\n" + + "xJM8/XmPBNQ+T+r3ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFM\n" + + "DSZl4kSAHsef493oCtrspSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5\n" + + "SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXV\n" + + "OBRgmaNL3gaWcSzy27YfpO8/7g==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_1_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnjCCAwegAwIBAgIQK2jUo0aexTsoCas4XX8nIDANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAx\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQC57V56Ondfzl86UvzNZPdxtW9qlsZZklWUXS9bLsER\n" + + "6iaKy6eBPPZaRN56Ey/9WlHZezcmSsAnPwQDalbBgyzhb1upVFAkSsYuekyh\n" + + "WzdUJCExH6F4GHansXDaItBq/gdiQMb39pt9DAa4S8co5GYjhFHvRreT2IEz\n" + + "y+U2rMboBQIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0xMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTEuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF\n" + + "BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n" + + "b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG\n" + + "CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud\n" + + "EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAHCQ3bjkvlMX\n" + + "fH8C6dX3i5mTMWCNfuZgayTvYKzSzpHegG0JpNO4OOVEynJeDS3Bd5y9LAN4\n" + + "KY2kpXeH9fErJq3MB2w6VFoo4AnzTQoEytRYaQuns/XdAaXn3PAfusFdkI2z\n" + + "6k/BEVmXarIrE7HarZehs7GgIFvKMquNzxPwHynD\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL\n" + + "Ey5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n" + + "cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\n" + + "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZM\n" + + "JaLtVRKXxaeAufqDwSCg+i8VDXyhYGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvE\n" + + "erf4Zh+AVPy3wo5ZShRXRtGak75BkQO7FYCTXOvnzAhsPz6zSvz/S2wj1VCC\n" + + "JkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBAIob\n" + + "K/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxgJ8pFUs4W7z8GZOeUaHxg\n" + + "MxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Ncr6Pc5iaAIzy4RHT3\n" + + "Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHB\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNV\n" + + "BAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRo\n" + + "b3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4g\n" + + "LSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24g\n" + + "VHJ1c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTla\n" + + "MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6\n" + + "BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIElu\n" + + "Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNp\n" + + "Z24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" + + "p4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkf\n" + + "rbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjwDqL7MWzJ5m+Z\n" + + "Jwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEAATAN\n" + + "BgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/\n" + + "7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX\n" + + "rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6x\n" + + "RnInjBJ7xUS0rg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcox\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UE\n" + + "CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkg\n" + + "VmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMG\n" + + "A1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp\n" + + "Y2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcx\n" + + "NjIzNTk1OVowgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg\n" + + "SW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UE\n" + + "CxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1\n" + + "c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJp\n" + + "bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG\n" + + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY8\n" + + "1nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDOJxOeBUebMXoT\n" + + "2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7C9UT\n" + + "AJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQ\n" + + "HgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN\n" + + "qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVC\n" + + "YQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekh\n" + + "ktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf\n" + + "0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydE\n" + + "p85EXdQbkJgNHkKUsQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377B\n" + + "MnMiIYtYgXsVkXq642RIsH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab\n" + + "5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//jGHyJizNdrDPX\n" + + "p/naOlXJWBD5qu9ats9LS98q\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_2_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnjCCAwegAwIBAgIQCUYX5h3Y1BygDKBi6HmKpzANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODAxMDAwMDAwWhcNMDQwNzMxMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAy\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQDQymMxYX9ENHwFfQs9apDLeUt3Cj9LxyPlwGItfpx+\n" + + "PoiHkdCs6E1Jh6KWkIrdBKUCP4yb6Yn+YqDiWr3I3bR45qVCkwhnAcAgTddc\n" + + "9F3as+M3plIaLExlTYqH2aij8UlUuzxcgFFoxvtJ/wtVqxXd+5rBuR10DbKM\n" + + "RF2J/J/5gwIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0yMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTIuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF\n" + + "BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j\n" + + "b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG\n" + + "CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud\n" + + "EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAB99CW4kRnUE\n" + + "nPMmm+M5bhfvvL2iG9IChIar0ECXLMRDiDcZayKoA3FQnSDcNmAgmnMtc1Vs\n" + + "WJsswrQ0LHozQsqR2elDr88e4PXEeqs/cmMeqTfhWzuIsxOGgpBXy1f/9Fa+\n" + + "It3jl6jhvCJDwt1N2/aBnpIUnjkPE1TegtjAXjSN\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL\n" + + "Ey5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n" + + "cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf\n" + + "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69q\n" + + "RUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3In\n" + + "zPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a\n" + + "/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtM\n" + + "EivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPw\n" + + "TtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzk\n" + + "uxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM\n" + + "XtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXX\n" + + "wc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GV\n" + + "j0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01U\n" + + "bSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i\n" + + "F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo\n" + + "1KpYoJ2daZH9\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2\n" + + "R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDo\n" + + "vFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwg\n" + + "TS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+V\n" + + "k7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ\n" + + "Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJ\n" + + "OxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my\n" + + "/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f\n" + + "j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoA\n" + + "Wii/gt/4uhMdUIaC/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8S\n" + + "GhJouPtmmRQURVyu565pF4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbb\n" + + "o27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh\n" + + "/sVFuq1ruQp6Tk9LhO5L8X3dEQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_3_Public_Primary_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDojCCAwugAwIBAgIQLpaev7ZibOx76XPM42zBhDANBgkqhkiG9w0BAQUF\n" + + "ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1\n" + + "BgNVBAsTLkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB\n" + + "dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX\n" + + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\n" + + "dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov\n" + + "L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAz\n" + + "IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB\n" + + "AQUAA4GNADCBiQKBgQDx5AgOg7t140jluNum8Lmr6Txix141W9ACVBHYydFW\n" + + "uXZLuat65s269gwE1n7WsAplrE454/H3LaMlOe+wi8++2wxdbnD0B81w9zrA\n" + + "PjUW7XiMQ8/CJi5H1oZ9nPG+1mcMIiWkymXmH3p4KC8/BdsEIb/hRWb+PLeC\n" + + "7Vq4FhW5VQIDAQABo4IBFDCCARAwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT\n" + + "CE9DU1AgMS0zMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwudmVyaXNp\n" + + "Z24uY29tL3BjYTMuMS4xLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCTBCBggr\n" + + "BgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGmJhYkaHR0cDovL29jc3AudmVyaXNp\n" + + "Z24uY29tL29jc3Avc3RhdHVzMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw\n" + + "KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQTAJ\n" + + "BgNVHRMEAjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQUFAAOBgQAC9lNj\n" + + "wKke8tCLMzCPSJtMsFa0g3FKvtxQ2PW24AvbvXhP6c8JNNopSZ0Bc1qRkYJU\n" + + "LBMK03cjzzf8Y96n4/a3tWlFKEnDkdyqRxypiJksBSqNjYr6YuJatwAgXTnE\n" + + "KMLL/J6oia5bPY4S6jKy/OsU1wkVGsDNG9W1FU5B1ZbjTg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_4_Public_Primary_Certification_Authority_-_G2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcEx\n" + + "CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE\n" + + "CxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + + "cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt\n" + + "IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow\n" + + "gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG\n" + + "A1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1\n" + + "dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j\n" + + "LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln\n" + + "biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6\n" + + "8OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDMHO0oW369atyzkSTK\n" + + "QWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtKqsGgtG7rL+VX\n" + + "xbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwIDAQABMA0G\n" + + "CSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwjcSGI\n" + + "L4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y\n" + + "cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckzt\n" + + "ImRPT8qAkbYp\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Class_4_Public_Primary_Certification_Authority_-_G3.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHK\n" + + "MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV\n" + + "BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5\n" + + "IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD\n" + + "BgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlm\n" + + "aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3\n" + + "MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s\n" + + "IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV\n" + + "BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg\n" + + "dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFBy\n" + + "aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\n" + + "hvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYl\n" + + "S+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXC\n" + + "KtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDc\n" + + "VHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdL\n" + + "MEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY\n" + + "ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDD\n" + + "Zq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1Wr\n" + + "IhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt\n" + + "mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csK\n" + + "vE+MW8VLADsfKoKmfjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluP\n" + + "QSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kP\n" + + "mF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr\n" + + "9Xgn2uf3ZkPznoM+IKrDNWCRzg==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_RSA_Secure_Server_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzEL\n" + + "MAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu\n" + + "MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9y\n" + + "aXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UE\n" + + "BhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD\n" + + "VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGb\n" + + "MA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6O\n" + + "LDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZs\n" + + "iAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmC\n" + + "sZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw\n" + + "4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxr\n" + + "l0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1\n" + + "g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Secure_Server_OCSP_Responder.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDnzCCAwygAwIBAgIRAP9F1SddJPuzwjkkU1fhT94wDQYJKoZIhvcNAQEF\n" + + "BQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5\n" + + "LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24g\n" + + "QXV0aG9yaXR5MB4XDTAwMDgwNDAwMDAwMFoXDTA0MDgwMzIzNTk1OVowgZ4x\n" + + "FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU\n" + + "cnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6\n" + + "Ly93d3cudmVyaXNpZ24uY29tL1JQQSAoYykwMDElMCMGA1UEAxMcU2VjdXJl\n" + + "IFNlcnZlciBPQ1NQIFJlc3BvbmRlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" + + "gYkCgYEAuFGZZIUO7rMKaPC/Y3YdU/X8oXiMM+6f9L452psPTUepjyDoS0S9\n" + + "zs17kNEw6JDEJXuJKN699pMd/7n/krWpjeSuzOLDB4Nqo3IQASdiIqY1Jjkt\n" + + "ns9gDPxHpNfQQninHWzQy08VpykKtJVFxLHnWgnXOZXYHTWewr2zXcEMSx8C\n" + + "AwEAAaOCAR0wggEZMCAGA1UdEQQZMBekFTATMREwDwYDVQQDEwhPQ1NQIDEt\n" + + "NDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLnZlcmlzaWduLmNvbS9S\n" + + "U0FTZWN1cmVTZXJ2ZXItcC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwkwQgYI\n" + + "KwYBBQUHAQEENjA0MDIGCCsGAQUFBzABpiYWJGh0dHA6Ly9vY3NwLnZlcmlz\n" + + "aWduLmNvbS9vY3NwL3N0YXR1czBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBwEB\n" + + "MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9SUEEw\n" + + "CQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEFBQADfgAAsxBT\n" + + "ZpxJky4xoAJC0lhXfmah/huKYRhQQCweK0Gl1tv/rAgcWgVtAlwqtpZPR9u+\n" + + "TtvOzLqGuBjOsRKRX2P380g+zPFNE+RtCZR4AJLLoyCdBgtqoEMHztEZbI8Y\n" + + "dZqfFzP9qSa44+LewqjEWop/mNYHBmvMVp6GcM7U7w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Verisign_Time_Stamping_Authority_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUF\n" + + "ADCBwTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTww\n" + + "OgYDVQQLEzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24g\n" + + "QXV0aG9yaXR5IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJ\n" + + "bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlT\n" + + "aWduIFRydXN0IE5ldHdvcmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1\n" + + "OTU5WjCBpTEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl\n" + + "cmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBh\n" + + "dCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTAwMSwwKgYDVQQD\n" + + "EyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1dGhvcml0eSBDQTCBnzANBgkq\n" + + "hkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVlizrQJIkRpivglWtvtDbc2\n" + + "fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU/OB4naCTuQk9I1F/\n" + + "RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11S7zi6ESHzeZB\n" + + "CiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/AgEAMEUG\n" + + "A1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0dHBz\n" + + "Oi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0\n" + + "cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIG\n" + + "CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJp\n" + + "c2lnbi5jb20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2\n" + + "DcIBcBlK0lRWHqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQn\n" + + "Keg3S/LvRJdrF1Eaw1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937n\n" + + "tag+RaypJXUie28/sJyU58dzq6wf7iWbwBbtt8pb8BQ=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Visa_International_Global_Root_2.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMC\n" + + "VVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25h\n" + + "bCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcN\n" + + "MDAwODE2MjI1MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzEN\n" + + "MAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNl\n" + + "cnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJ\n" + + "KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZ\n" + + "DK9vZBv42pWUJGkzEXDK41Z0ohdXZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJ\n" + + "XLB1LRckaeNCYOTudNargFbYiCjh+20i/SN8RnNPflRzHqgsVVh1t0zzWkWl\n" + + "Ahr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU58fy+pmjIlC++QU3o63tmsPm\n" + + "7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/ghalMCXI5Etuz9c9OYmTa\n" + + "xhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E1w0cslSsMoW0ZA3e\n" + + "QbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ca3CBfYDdYDO\n" + + "qU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqG\n" + + "SIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHbmQdp\n" + + "NSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ\n" + + "kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoL\n" + + "axhNdBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/Rt\n" + + "Ldh6yumJivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8\n" + + "ofyrEK9ca3CnB+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // Visa_eCommerce_Root.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUF\n" + + "ADBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlz\n" + + "YSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMT\n" + + "E1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0\n" + + "MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UE\n" + + "CxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAa\n" + + "BgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh\n" + + "28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362\n" + + "rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81\n" + + "q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtF\n" + + "Wsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0\n" + + "lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4t\n" + + "AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\n" + + "A1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOC\n" + + "AQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR\n" + + "zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKht\n" + + "cbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGI\n" + + "xHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu\n" + + "YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/\n" + + "hC3euiInlhBx6yLt398znM/jra6O1I7mT1GvFpLgXPYHDw==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA-Baltimore_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK\n" + + "EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG\n" + + "A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0\n" + + "aW9uMB4XDTAyMDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UE\n" + + "ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx\n" + + "BgNVBAMTKmJlVFJVU1RlZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRh\n" + + "dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALx+xDmcjOPW\n" + + "HIb/ymKt4H8wRXqOGrO4x/nRNv8i805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R\n" + + "9U+jK7wYFuK13XneIviCfsuBH/0nLI/6l2Qijvj/YaOcGx6Sj8CoCd8JEey3\n" + + "fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92BFODEPM2dMPgwqZfT7syj0B9f\n" + + "HBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+YmpkbIq2eszh+6l/ePazIjm\n" + + "iSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7eHgZFLL8kFKJOGJg\n" + + "B7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIaMA8GA1UdEwEB\n" + + "/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4AAAEJKIOR\n" + + "MTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3IgdXNl\n" + + "IG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu\n" + + "dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5k\n" + + "YXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmlj\n" + + "YXRpb24gUHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0\n" + + "eSBBZ3JlZW1lbnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVT\n" + + "VGVkIHdlYiBzaXRlLCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVj\n" + + "dHNfc2VydmljZXMvaW5kZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3\n" + + "dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWww\n" + + "HQYDVR0OBBYEFEU9w6nR3D8kVpgccxiIav+DR+22MB8GA1UdIwQYMBaAFEU9\n" + + "w6nR3D8kVpgccxiIav+DR+22MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B\n" + + "AQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCAWXf82n+0S9/DZEtqTg6t8n1Z\n" + + "dwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu67RMdmgduyzFiEuhjA6p9\n" + + "beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AYgkHNZTfqjjJ+vWuZ\n" + + "XTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb4cV97yHgjQ5d\n" + + "UX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9CReJf8Py\n" + + "05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG\n" + + "EwJXVzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQg\n" + + "Um9vdCBDQXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYy\n" + + "MDE0MjEwNFoXDTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNV\n" + + "BAoTCWJlVFJVU1RlZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRow\n" + + "GAYDVQQDExFiZVRSVVNUZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD\n" + + "ggEPADCCAQoCggEBANS0c3oTCjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4\n" + + "SP+00PpeQY1hRIfo7clY+vyTmt9P6j41ffgzeubx181vSUs9Ty1uDoM6GHh3\n" + + "o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwMjmVZxXH/YgmPqsWPzGCgc0rXOD8V\n" + + "cr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX2P8ZDoMbjNx4RWc0PfSvHI3k\n" + + "bWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2NR47rtMNE5qdMf1ZD6Li8\n" + + "tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5jrEq2I8QBoa2k5MUC\n" + + "AwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNVHSAEggFQMIIB\n" + + "TDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQagfFSZWxp\n" + + "YW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVz\n" + + "IGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0\n" + + "ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9u\n" + + "IHByYWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJl\n" + + "VFJVU1RlZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29t\n" + + "L3ZhdWx0L3Rlcm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNU\n" + + "ZWQuY29tL3ZhdWx0L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYD\n" + + "VQQKEwliZVRSVVNUZWQxCzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub\n" + + "2M3eKjEENGvKBxirZzAfBgNVHSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxir\n" + + "ZzAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQEFBQADggEBAHlh26Nebhax\n" + + "6nZR+csVm8tpvuaBa58oH2U+3RGFktToQb9+M70j5/Egv6S0phkBxoyNNXxl\n" + + "pE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2jCBHOElQBp1yZzrwmAOtlmdE\n" + + "/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe1lMBzW1MaFVA4e5rxyoA\n" + + "AEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5mlWXKWWuGVUlBXJH\n" + + "0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYctmBjRYoQtLpG\n" + + "EK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA_-_Entrust_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK\n" + + "EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG\n" + + "A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0\n" + + "aW9uMB4XDTAyMDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UE\n" + + "ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx\n" + + "BgNVBAMTKmJlVFJVU1RlZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRh\n" + + "dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1\n" + + "Q+xVkrYwfTVXDNvzDSduTPdQqJtOK2/b9a0cS12zqcH+e0TrW6MFDR/FNCsw\n" + + "ACnxeECypP869AGIF37m1CbTukzqMvtDd5eHI8XbQ6P1KqNRXuE70mVpflUV\n" + + "m3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdjDheT389Lrm5zdeDzqrmkwAkb\n" + + "hepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCeyv78IZTuEyhL11xeDGbu\n" + + "6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCktVjMFu5dZfsZJT4nX\n" + + "LySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMBMIIBtwYDVR0g\n" + + "BIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYIKwYBBQUH\n" + + "AgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRpZmlj\n" + + "YXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug\n" + + "b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29u\n" + + "ZGl0aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0\n" + + "YXRlbWVudCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGlj\n" + + "aCBjYW4gYmUgZm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0\n" + + "cHM6Ly93d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRl\n" + + "eC5odG1sMEIGCCsGAQUFBwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29t\n" + + "L3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQD\n" + + "AgAHMIGJBgNVHR8EgYEwfzB9oHugeaR3MHUxEjAQBgNVBAoTCWJlVFJVU1Rl\n" + + "ZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYDVQQDEypiZVRS\n" + + "VVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1wbGVtZW50YXRpb24xDTALBgNV\n" + + "BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEwODI0MjdagQ8yMDIyMDQx\n" + + "MTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFH1w5a44iwY/qhwa\n" + + "j/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQwqoSEFjAMBgNV\n" + + "HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkq\n" + + "hkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ5V04\n" + + "ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB\n" + + "evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220\n" + + "Y/ozADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2\n" + + "KjiS2d2kXgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFi\n" + + "aDrmLzfzgYYhxKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep\n" + + "9w==\n" + + "-----END CERTIFICATE-----\n"); + if (cert != null) certs.add(cert); + + cert = generate(factory, + // beTRUSTed_Root_CA_-_RSA_Implementation.crt + "-----BEGIN CERTIFICATE-----\n" + + "MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUF\n" + + "ADBiMRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBS\n" + + "b290IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1w\n" + + "bGVtZW50YXRpb24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBi\n" + + "MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290\n" + + "IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVt\n" + + "ZW50YXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQw\n" + + "CY5X0LkGLG9uJIAiv11DpvpPrILnHGhwhRujbrWqeNluB0s/6d/16uhUoWGK\n" + + "Di9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I1DpAa5LxmZZk3tv/ePTulh1HiXzU\n" + + "vrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPktPDgaTuID0GQ+NRxQyTBjyZL\n" + + "O1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnUGxlkVgoZ98zh/4avflhe\n" + + "rHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8ercmsl9fNTGwxMLvF1\n" + + "S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIYMIICFDAMBgNV\n" + + "HRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+AAADCSiD\n" + + "kTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20v\n" + + "cHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB\n" + + "OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBj\n" + + "cmVhdGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRo\n" + + "ZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlv\n" + + "bnMgb2YgdXNlLCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1l\n" + + "bnQgYW5kIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2Fu\n" + + "IGJlIGZvdW5kIGF0IHRoZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93\n" + + "d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1s\n" + + "MAsGA1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSp7BR++dlDzFMrFK3P9/BZiUHN\n" + + "GTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxStz/fwWYlBzRkwDQYJKoZIhvcNAQEF\n" + + "BQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g6IHHtt9DwSwddUvUQo3neqh0\n" + + "3GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuKmET7m9cqg5c0Lcd9NUwt\n" + + "NLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbdLrML3kqNWz2rDcI1\n" + + "UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28BbJ1zTcwfBwvNM\n" + + "m2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3SK41ty8y\n" + + "mmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw=\n" + + "-----END CERTIFICATE-----\n"); + + CA_CERTS = new StaticTrustAnchors((X509Certificate[]) certs.toArray(new X509Certificate[0])); + } +} diff --git a/gnu/javax/net/ssl/provider/Alert.java b/gnu/javax/net/ssl/provider/Alert.java new file mode 100644 index 000000000..c31e1bef5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Alert.java @@ -0,0 +1,474 @@ +/* Alert.java -- SSL Alert message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * An alert message in the SSL protocol. Alerts are sent both as warnings + * which may allow execution to continue, or they may be fatal, which will + * halt this session. An alert object is composed of two enums -- the level, + * which indicates the seriousness of the alert, and the description, which + * indicates the reason for the alert. + * + *

+ * struct {
+ *   AlertLevel level;
+ *   AlertDescription description;
+ * }
+ * 
+ */ +final class Alert implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** The alert level enumerated. */ + private final Level level; + + /** The alert description enumerated. */ + private final Description description; + + // Constructor. + // ------------------------------------------------------------------------- + + Alert(Level level, Description description) + { + this.level = level; + this.description = description; + } + + // Class method. + // ------------------------------------------------------------------------- + + static Alert read(InputStream in) throws IOException + { + Level level = Level.read(in); + Description desc = Description.read(in); + return new Alert(level, desc); + } + + static Alert forName(String name) + { + if (name == null) + { + return new Alert(Level.FATAL, Description.INTERNAL_ERROR); + } + Description desc = Description.INTERNAL_ERROR; + if (name.equals("close_notify")) + { + desc = Description.CLOSE_NOTIFY; + } + else if (name.equals("unexpected_message")) + { + desc = Description.UNEXPECTED_MESSAGE; + } + else if (name.equals("bad_record_mac")) + { + desc = Description.BAD_RECORD_MAC; + } + else if (name.equals("DECRYPTION_FAILED")) + { + desc = Description.DECRYPTION_FAILED; + } + else if (name.equals("record_overflow")) + { + desc = Description.RECORD_OVERFLOW; + } + else if (name.equals("decompression_failure")) + { + desc = Description.DECOMPRESSION_FAILURE; + } + else if (name.equals("handshake_failure")) + { + desc = Description.HANDSHAKE_FAILURE; + } + else if (name.equals("no_certificate")) + { + desc = Description.NO_CERTIFICATE; + } + else if (name.equals("bad_certificate")) + { + desc = Description.BAD_CERTIFICATE; + } + else if (name.equals("unsupported_certificate")) + { + desc = Description.UNSUPPORTED_CERTIFICATE; + } + else if (name.equals("certificate_revoked")) + { + desc = Description.CERTIFICATE_REVOKED; + } + else if (name.equals("certificate_expired")) + { + desc = Description.CERTIFICATE_EXPIRED; + } + else if (name.equals("certificate_unknown")) + { + desc = Description.CERTIFICATE_UNKNOWN; + } + else if (name.equals("illegal_parameter")) + { + desc = Description.ILLEGAL_PARAMETER; + } + else if (name.equals("unknown_ca")) + { + desc = Description.UNKNOWN_CA; + } + else if (name.equals("access_denied")) + { + desc = Description.ACCESS_DENIED; + } + else if (name.equals("decode_error")) + { + desc = Description.DECODE_ERROR; + } + else if (name.equals("decrypt_error")) + { + desc = Description.DECRYPT_ERROR; + } + else if (name.equals("export_restriction")) + { + desc = Description.EXPORT_RESTRICTION; + } + else if (name.equals("protocol_version")) + { + desc = Description.PROTOCOL_VERSION; + } + else if (name.equals("insufficient_security")) + { + desc = Description.INSUFFICIENT_SECURITY; + } + else if (name.equals("internal_error")) + { + desc = Description.INTERNAL_ERROR; + } + else if (name.equals("user_canceled")) + { + desc = Description.USER_CANCELED; + } + else if (name.equals("no_renegotiation")) + { + desc = Description.NO_RENEGOTIATION; + } + else if (name.equals("unsupported_extension")) + { + desc = Description.UNSUPPORTED_EXTENSION; + } + else if (name.equals("certificate_unobtainable")) + { + desc = Description.CERTIFICATE_UNOBTAINABLE; + } + else if (name.equals("unrecognized_name")) + { + desc = Description.UNRECOGNIZED_NAME; + } + else if (name.equals("bad_certificate_status_response")) + { + desc = Description.BAD_CERTIFICATE_STATUS_RESPONSE; + } + else if (name.equals("bad_certificate_hash_value")) + { + desc = Description.BAD_CERTIFICATE_HASH_VALUE; + } + else if (name.equals("unknown_srp_username")) + { + desc = Description.UNKNOWN_SRP_USERNAME; + } + else if (name.equals("missing_srp_username")) + { + desc = Description.MISSING_SRP_USERNAME; + } + return new Alert(Level.FATAL, desc); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write((byte) level.getValue()); + out.write((byte) description.getValue()); + } + + byte[] getEncoded() + { + return new byte[] { (byte) level.getValue(), + (byte) description.getValue() }; + } + + Level getLevel() + { + return level; + } + + Description getDescription() + { + return description; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "struct {" + nl + + " level = " + level + ";" + nl + + " description = " + description + ";" + nl + + "} Alert;" + nl; + } + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * The level enumeration. + * + *
+   * enum { warning(1), fatal(2), (255) } AlertLevel;
+   * 
+ */ + static final class Level implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final Level WARNING = new Level(1), FATAL = new Level(2); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Level(int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static Level read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of stream"); + } + switch (i & 0xFF) + { + case 1: return WARNING; + case 2: return FATAL; + default: return new Level(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 1: return "warning"; + case 2: return "fatal"; + default: return "unknown(" + value + ")"; + } + } + } + + /** + * The description enumeration. + */ + static final class Description implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final Description + CLOSE_NOTIFY = new Description( 0), + UNEXPECTED_MESSAGE = new Description( 10), + BAD_RECORD_MAC = new Description( 20), + DECRYPTION_FAILED = new Description( 21), + RECORD_OVERFLOW = new Description( 22), + DECOMPRESSION_FAILURE = new Description( 30), + HANDSHAKE_FAILURE = new Description( 40), + NO_CERTIFICATE = new Description( 41), + BAD_CERTIFICATE = new Description( 42), + UNSUPPORTED_CERTIFICATE = new Description( 43), + CERTIFICATE_REVOKED = new Description( 44), + CERTIFICATE_EXPIRED = new Description( 45), + CERTIFICATE_UNKNOWN = new Description( 46), + ILLEGAL_PARAMETER = new Description( 47), + UNKNOWN_CA = new Description( 48), + ACCESS_DENIED = new Description( 49), + DECODE_ERROR = new Description( 50), + DECRYPT_ERROR = new Description( 51), + EXPORT_RESTRICTION = new Description( 60), + PROTOCOL_VERSION = new Description( 70), + INSUFFICIENT_SECURITY = new Description( 71), + INTERNAL_ERROR = new Description( 80), + USER_CANCELED = new Description( 90), + NO_RENEGOTIATION = new Description(100), + UNSUPPORTED_EXTENSION = new Description(110), + CERTIFICATE_UNOBTAINABLE = new Description(111), + UNRECOGNIZED_NAME = new Description(112), + BAD_CERTIFICATE_STATUS_RESPONSE = new Description(113), + BAD_CERTIFICATE_HASH_VALUE = new Description(114), + UNKNOWN_SRP_USERNAME = new Description(120), + MISSING_SRP_USERNAME = new Description(121); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Description(int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static Description read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (i) + { + case 0: return CLOSE_NOTIFY; + case 10: return UNEXPECTED_MESSAGE; + case 20: return BAD_RECORD_MAC; + case 21: return DECRYPTION_FAILED; + case 22: return RECORD_OVERFLOW; + case 30: return DECOMPRESSION_FAILURE; + case 40: return HANDSHAKE_FAILURE; + case 41: return NO_CERTIFICATE; + case 42: return BAD_CERTIFICATE; + case 43: return UNSUPPORTED_CERTIFICATE; + case 44: return CERTIFICATE_REVOKED; + case 45: return CERTIFICATE_EXPIRED; + case 46: return CERTIFICATE_UNKNOWN; + case 47: return ILLEGAL_PARAMETER; + case 48: return UNKNOWN_CA; + case 49: return ACCESS_DENIED; + case 50: return DECODE_ERROR; + case 51: return DECRYPT_ERROR; + case 60: return EXPORT_RESTRICTION; + case 70: return PROTOCOL_VERSION; + case 71: return INSUFFICIENT_SECURITY; + case 80: return INTERNAL_ERROR; + case 90: return USER_CANCELED; + case 100: return NO_RENEGOTIATION; + case 120: return UNKNOWN_SRP_USERNAME; + case 121: return MISSING_SRP_USERNAME; + default: return new Description(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "close_notify"; + case 10: return "unexpected_message"; + case 20: return "bad_record_mac"; + case 21: return "decryption_failed"; + case 22: return "record_overflow"; + case 30: return "decompression_failure"; + case 40: return "handshake_failure"; + case 42: return "bad_certificate"; + case 43: return "unsupported_certificate"; + case 44: return "certificate_revoked"; + case 45: return "certificate_expired"; + case 46: return "certificate_unknown"; + case 47: return "illegal_parameter"; + case 48: return "unknown_ca"; + case 49: return "access_denied"; + case 50: return "decode_error"; + case 51: return "decrypt_error"; + case 60: return "export_restriction"; + case 70: return "protocol_version"; + case 71: return "insufficient_security"; + case 80: return "internal_error"; + case 90: return "user_canceled"; + case 100: return "no_renegotiation"; + case 110: return "unsupported_extension"; + case 111: return "certificate_unobtainable"; + case 112: return "unrecognized_name"; + case 113: return "bad_certificate_status_response"; + case 114: return "bad_certificate_hash_value"; + case 120: return "unknown_srp_username"; + case 121: return "missing_srp_username"; + default: return "unknown(" + value + ")"; + } + } + } +} diff --git a/gnu/javax/net/ssl/provider/AlertException.java b/gnu/javax/net/ssl/provider/AlertException.java new file mode 100644 index 000000000..666efe5ac --- /dev/null +++ b/gnu/javax/net/ssl/provider/AlertException.java @@ -0,0 +1,76 @@ +/* AlertException.java -- exceptions generated by SSL alerts. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import javax.net.ssl.SSLException; + +class AlertException extends SSLException +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Alert alert; + private final boolean isLocal; + + // Constructor. + // ------------------------------------------------------------------------- + + AlertException(Alert alert, boolean isLocal) + { + super(alert.getDescription().toString()); + this.alert = alert; + this.isLocal = isLocal; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getMessage() + { + return alert.getDescription() + ": " + + (isLocal ? "locally generated; " : "remotely generated; ") + + alert.getLevel(); + } + + public Alert getAlert () + { + return alert; + } +} diff --git a/gnu/javax/net/ssl/provider/Certificate.java b/gnu/javax/net/ssl/provider/Certificate.java new file mode 100644 index 000000000..b1d6b2a01 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Certificate.java @@ -0,0 +1,194 @@ +/* Certificate.java -- SSL Certificate message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import java.util.LinkedList; + +import javax.net.ssl.SSLProtocolException; + +final class Certificate implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final X509Certificate[] certs; + + // Constructors. + // ------------------------------------------------------------------------- + + Certificate(X509Certificate[] certs) + { + if (certs == null) + { + throw new NullPointerException(); + } + this.certs = certs; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Certificate read(InputStream in, CertificateType type) + throws IOException + { + if (type == CertificateType.X509) + { + int len = (in.read() & 0xFF) << 16 | (in.read() & 0xFF) << 8 + | (in.read() & 0xFF); + byte[] buf = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(buf, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of stream"); + } + count += l; + } + try + { + LinkedList certs = new LinkedList(); + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream bin = new ByteArrayInputStream(buf); + count = 0; + while (count < len) + { + int len2 = (bin.read() & 0xFF) << 16 | (bin.read() & 0xFF) << 8 + | (bin.read() & 0xFF); + certs.add(fact.generateCertificate(bin)); + count += len2 + 3; + } + return new Certificate((X509Certificate[]) + certs.toArray(new X509Certificate[certs.size()])); + } + catch (CertificateException ce) + { + SSLProtocolException sslpe = new SSLProtocolException(ce.getMessage()); + sslpe.initCause (ce); + throw sslpe; + } + } + else if (type == CertificateType.OPEN_PGP) + { + throw new UnsupportedOperationException("not yet implemented"); + } + else + throw new Error("unsupported certificate type "+type); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + try + { + for (int i = 0; i < certs.length; i++) + { + byte[] enc = certs[i].getEncoded(); + bout.write((enc.length >>> 16) & 0xFF); + bout.write((enc.length >>> 8) & 0xFF); + bout.write( enc.length & 0xFF); + bout.write(enc); + } + } + catch (CertificateEncodingException cee) + { + throw new Error("cannot encode certificates"); + } + catch (IOException ignored) + { + } + out.write(bout.size() >>> 16 & 0xFF); + out.write(bout.size() >>> 8 & 0xFF); + out.write(bout.size() & 0xFF); + bout.writeTo(out); + } + + X509Certificate[] getCertificates() + { + return certs; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" certificateList ="); + for (int i = 0; i < certs.length; i++) + { + BufferedReader r = + new BufferedReader(new StringReader(certs[i].toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println("} Certificate;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/CertificateRequest.java b/gnu/javax/net/ssl/provider/CertificateRequest.java new file mode 100644 index 000000000..0f788039b --- /dev/null +++ b/gnu/javax/net/ssl/provider/CertificateRequest.java @@ -0,0 +1,285 @@ +/* CertificateRequest.java -- SSL CertificateRequest message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import java.util.LinkedList; +import java.security.Principal; + +final class CertificateRequest implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final ClientType[] types; + private final Principal[] authorities; + + // Constructor. + // ------------------------------------------------------------------------- + + CertificateRequest(ClientType[] types, Principal[] authorities) + { + if (types == null) + { + throw new NullPointerException(); + } + this.types = types; + if (authorities == null) + { + throw new NullPointerException(); + } + this.authorities = authorities; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static CertificateRequest read(InputStream in) throws IOException + { + DataInputStream din = new DataInputStream(in); + ClientType[] types = new ClientType[din.readUnsignedByte()]; + for (int i = 0; i < types.length; i++) + { + types[i] = ClientType.read(din); + } + + LinkedList authorities = new LinkedList(); + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + ByteArrayInputStream bin = new ByteArrayInputStream(buf); + try + { + String x500name = Util.getSecurityProperty("jessie.x500.class"); + if (x500name == null) + { + x500name = "org.metastatic.jessie.pki.X500Name"; + } + Class x500class = null; + ClassLoader cl = ClassLoader.getSystemClassLoader(); + if (cl != null) + { + x500class = cl.loadClass(x500name); + } + else + { + x500class = Class.forName(x500name); + } + Constructor c = x500class.getConstructor(new Class[] { new byte[0].getClass() }); + while (bin.available() > 0) + { + buf = new byte[(bin.read() & 0xFF) << 8 | (bin.read() & 0xFF)]; + bin.read(buf); + authorities.add(c.newInstance(new Object[] { buf })); + } + } + catch (IOException ioe) + { + throw ioe; + } + catch (Exception ex) + { + throw new Error(ex.toString()); + } + return new CertificateRequest(types, + (Principal[]) authorities.toArray(new Principal[authorities.size()])); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + out.write(types.length); + for (int i = 0; i < types.length; i++) + { + out.write(types[i].getValue()); + } + + try + { + Class x500class = authorities[0].getClass(); + Method m = x500class.getMethod("getEncoded", null); + for (int i = 0; i < authorities.length; i++) + { + byte[] buf = (byte[]) m.invoke(authorities[i], null); + bout.write(buf.length >>> 8 & 0xFF); + bout.write(buf.length & 0xFF); + bout.write(buf, 0, buf.length); + } + } + catch (Exception ex) + { + throw new Error(ex.toString()); + } + out.write(bout.size() >>> 8 & 0xFF); + out.write(bout.size() & 0xFF); + bout.writeTo(out); + } + + ClientType[] getTypes() + { + return types; + } + + String[] getTypeStrings() + { + try + { + return (String[]) Util.transform(types, String.class, "toString", null); + } + catch (Exception x) + { + return null; + } + } + + Principal[] getAuthorities() + { + return authorities; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.print(" types = "); + for (int i = 0; i < types.length; i++) + { + out.print(types[i]); + if (i != types.length - 1) + out.print(", "); + } + out.println(";"); + out.println(" authorities ="); + for (int i = 0; i < authorities.length; i++) + { + out.print(" "); + out.print(authorities[i].getName()); + if (i != types.length - 1) + out.println(","); + } + out.println(";"); + out.println("} CertificateRequest;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + static final class ClientType implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final ClientType + RSA_SIGN = new ClientType(1), DSS_SIGN = new ClientType(2), + RSA_FIXED_DH = new ClientType(3), DSS_FIXED_DH = new ClientType(4); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private ClientType(int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static ClientType read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (i & 0xFF) + { + case 1: return RSA_SIGN; + case 2: return DSS_SIGN; + case 3: return RSA_FIXED_DH; + case 4: return DSS_FIXED_DH; + default: return new ClientType(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 1: return "rsa_sign"; + case 2: return "dss_sign"; + case 3: return "rsa_fixed_dh"; + case 4: return "dss_fixed_dh"; + default: return "unknown(" + value + ")"; + } + } + } +} diff --git a/gnu/javax/net/ssl/provider/CertificateType.java b/gnu/javax/net/ssl/provider/CertificateType.java new file mode 100644 index 000000000..c5705939f --- /dev/null +++ b/gnu/javax/net/ssl/provider/CertificateType.java @@ -0,0 +1,104 @@ +/* CertificateType.java -- the certificate type extension. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +final class CertificateType implements Enumerated +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + static final CertificateType X509 = new CertificateType(0); + static final CertificateType OPEN_PGP = new CertificateType(1); + + private final int value; + + // Constructor. + // ------------------------------------------------------------------------- + + private CertificateType(int value) + { + this.value = value; + } + + // Class method. + // ------------------------------------------------------------------------- + + static CertificateType read(InputStream in) throws IOException + { + int value = in.read(); + if (value == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (value & 0xFF) + { + case 0: return X509; + case 1: return OPEN_PGP; + default: return new CertificateType(value); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "X.509"; + case 1: return "OpenPGP"; + default: return "unknown(" + value + ")"; + } + } +} diff --git a/gnu/javax/net/ssl/provider/CertificateVerify.java b/gnu/javax/net/ssl/provider/CertificateVerify.java new file mode 100644 index 000000000..e0bf130f1 --- /dev/null +++ b/gnu/javax/net/ssl/provider/CertificateVerify.java @@ -0,0 +1,95 @@ +/* CertificateVerify.java -- SSL CertificateVerify message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.security.PublicKey; + +final class CertificateVerify extends Signature implements Handshake.Body +{ + + // Contstructor. + // ------------------------------------------------------------------------- + + CertificateVerify(Object sigValue, String sigAlg) + { + super(sigValue, sigAlg); + } + + // Class method. + // -------------------------------------------------------------------------- + + static Signature read(InputStream in, CipherSuite suite, PublicKey key) + throws IOException + { + Signature sig = Signature.read(in, suite, key); + return new CertificateVerify(sig.getSigValue(), sig.getSigAlg()); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + BufferedReader r = new BufferedReader(new StringReader(super.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + out.println("} CertificateVerify;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/CipherSuite.java b/gnu/javax/net/ssl/provider/CipherSuite.java new file mode 100644 index 000000000..de916817b --- /dev/null +++ b/gnu/javax/net/ssl/provider/CipherSuite.java @@ -0,0 +1,754 @@ +/* CipherSuite.java -- Supported cipher suites. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.lang.reflect.Field; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; + +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; + +final class CipherSuite implements Constructed +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final List tlsSuiteNames = new LinkedList(); + private static final HashMap namesToSuites = new HashMap(); + + // SSL CipherSuites. + static final CipherSuite SSL_NULL_WITH_NULL_NULL = + new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00, + "SSL_NULL_WITH_NULL_NULL", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_NULL_MD5 = + new CipherSuite("null", "RSA", "RSA", "SSLMAC-MD5", 0, 0x00, 0x01, + "SSL_RSA_WITH_NULL_MD5", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_NULL_SHA = + new CipherSuite("null", "RSA", "RSA", "SSLMAC-SHA", 0, 0x00, 0x02, + "SSL_RSA_WITH_NULL_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_EXPORT_WITH_RC4_40_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 5, 0x00, 0x03, + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_RC4_128_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 16, 0x00, 0x04, + "SSL_RSA_WITH_RC4_128_MD5", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_RC4_128_SHA = + new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x05, + "SSL_RSA_WITH_RC4_128_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 5, 0x00, 0x08, + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 8, 0x00, 0x09, + "SSL_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "RSA", "RSA", "SSLMAC-SHA", 24, 0x00, 0x0A, + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 5, 0x00, 0x0B, + "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 8, 0x00, 0x0C, + "SSL_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "DSS", "SSLMAC-SHA", 24, 0x00, 0x0D, + "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 5, 0x00, 0x0E, + "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 8, 0x00, 0x0F, + "SSL_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "RSA", "SSLMAC-SHA", 24, 0x00, 0x10, + "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 5, 0x00, 0x11, + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 8, 0x00, 0x12, + "SSL_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "DSS", "SSLMAC-SHA", 24, 0x00, 0x13, + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 5, 0x00, 0x14, + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 8, 0x00, 0x15, + "SSL_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "RSA", "SSLMAC-SHA", 24, 0x00, 0x16, + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3); + + // AES CipherSuites. + static final CipherSuite SSL_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x2F, + "SSL_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 16, 0x00, 0x30, + "SSL_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 16, 0x00, 0x31, + "SSL_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 16, 0x00, 0x32, + "SSL_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 16, 0x00, 0x33, + "SSL_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 32, 0x00, 0x35, + "SSL_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 32, 0x00, 0x36, + "SSL_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DH_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 32, 0x00, 0x37, + "SSL_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 32, 0x00, 0x38, + "SSL_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 32, 0x00, 0x39, + "SSL_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3); + + // Ciphersuites from the OpenPGP extension draft. + static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70, + "SSL_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71, + "SSL_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72, + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73, + "SSL_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74, + "SSL_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75, + "SSL_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76, + "SSL_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77, + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78, + "SSL_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79, + "SSL_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A, + "SSL_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B, + "SSL_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C, + "SSL_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D, + "SSL_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3); + static final CipherSuite SSL_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E, + "SSL_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3); + + static final CipherSuite TLS_NULL_WITH_NULL_NULL = + new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00, + "TLS_NULL_WITH_NULL_NULL", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_NULL_MD5 = + new CipherSuite("null", "RSA", "RSA", "HMAC-MD5", 0, 0x00, 0x01, + "TLS_RSA_WITH_NULL_MD5", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_NULL_SHA = + new CipherSuite("null", "RSA", "RSA", "HMAC-SHA", 0, 0x00, 0x02, + "TLS_RSA_WITH_NULL_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 5, 0x00, 0x03, + "TLS_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 = + new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 16, 0x00, 0x04, + "TLS_RSA_WITH_RC4_128_MD5", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_RC4_128_SHA = + new CipherSuite("RC4", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x05, + "TLS_RSA_WITH_RC4_128_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 5, 0x00, 0x08, + "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 8, 0x00, 0x09, + "TLS_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-SHA", 24, 0x00, 0x0A, + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 5, 0x00, 0x0B, + "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 8, 0x00, 0x0C, + "TLS_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "DSS", "HMAC-SHA", 24, 0x00, 0x0D, + "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 5, 0x00, 0x0E, + "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 8, 0x00, 0x0F, + "TLS_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DH", "RSA", "HMAC-SHA", 24, 0x00, 0x10, + "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 5, 0x00, 0x11, + "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 8, 0x00, 0x12, + "TLS_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-SHA", 24, 0x00, 0x13, + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 5, 0x00, 0x14, + "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = + new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 8, 0x00, 0x15, + "TLS_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-SHA", 24, 0x00, 0x16, + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + + // AES CipherSuites. + static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x2F, + "TLS_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 16, 0x00, 0x30, + "TLS_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 16, 0x00, 0x31, + "TLS_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x32, + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x33, + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 32, 0x00, 0x35, + "TLS_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 32, 0x00, 0x36, + "TLS_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 32, 0x00, 0x37, + "TLS_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 32, 0x00, 0x38, + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 32, 0x00, 0x39, + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + + // Secure remote password (SRP) ciphersuites + static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "SRP", "anon", "HMAC-SHA", 24, 0x00, 0x50, + "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "SRP", "RSA", "HMAC-SHA", 24, 0x00, 0x51, + "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite("TripleDES", "SRP", "DSS", "HMAC-SHA", 24, 0x00, 0x52, + "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 16, 0x00, 0x53, + "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 16, 0x00, 0x54, + "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 16, 0x00, 0x55, + "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 32, 0x00, 0x56, + "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 32, 0x00, 0x57, + "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 32, 0x00, 0x58, + "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1); + + // Ciphersuites from the OpenPGP extension draft. + static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70, + "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71, + "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72, + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73, + "TLS_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74, + "TLS_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75, + "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76, + "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77, + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78, + "TLS_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79, + "TLS_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A, + "TLS_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B, + "TLS_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C, + "TLS_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D, + "TLS_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1); + static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E, + "TLS_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1); + + private final String cipherName; + private final String kexName; + private final String sigName; + private final String macName; + private final boolean exportable; + private final boolean isStream; + private final int keyLength; + private final byte[] id; + private final String name; + private final ProtocolVersion version; + + // Constructors. + // ------------------------------------------------------------------------- + + private CipherSuite(String cipherName, String kexName, String sigName, + String macName, int keyLength, int id1, int id2, + String name, ProtocolVersion version) + { + this.cipherName = cipherName.intern(); + this.kexName = kexName.intern(); + this.sigName = sigName.intern(); + this.macName = macName.intern(); + this.exportable = keyLength <= 5; + this.isStream = cipherName.equals("null") || cipherName.equals("RC4"); + this.keyLength = keyLength; + this.id = new byte[] { (byte) id1, (byte) id2 }; + this.name = name.intern(); + this.version = version; + namesToSuites.put(name, this); + if (name.startsWith("TLS")) + { + tlsSuiteNames.add(name); + } + } + + private CipherSuite(byte[] id) + { + cipherName = null; + kexName = null; + sigName = null; + macName = null; + exportable = false; + isStream = false; + keyLength = 0; + this.id = id; + name = null; + version = null; + } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Returns the cipher suite for the given name, or null if there is no + * such suite. + * + * @return The named cipher suite. + */ + static CipherSuite forName(String name) + { + return (CipherSuite) namesToSuites.get(name); + } + + static List availableSuiteNames() + { + return tlsSuiteNames; + } + + static CipherSuite read(InputStream in) throws IOException + { + DataInputStream din = new DataInputStream(in); + byte[] id = new byte[2]; + din.readFully(id); + return new CipherSuite(id); + } + + static IMode getCipher(String cbcCipherName) + { + IBlockCipher cipher = CipherFactory.getInstance(cbcCipherName); + if (cipher == null) + { + return null; + } + return ModeFactory.getInstance("CBC", cipher, cipher.defaultBlockSize()); + } + + static Cipher getJCECipher (final String name) + throws NoSuchAlgorithmException, NoSuchPaddingException + { + final String provider = Util.getSecurityProperty ("jessie.with.jce.provider"); + if (name.equals ("RC4")) + { + if (provider != null) + { + try + { + return Cipher.getInstance (name, provider); + } + catch (NoSuchProviderException nsae) + { + // Fall through. Try any available provider. + } + } + + return Cipher.getInstance (name); + } + else + { + // Oh, hey! Look! Something else Sun doesn't understand: SSLv3 padding + // is different than TLSv1 in subtle, but important, ways. But they + // sorta look the same, so why not make them equivalent? + // + // There should be a seperate padding "TLS1Padding". + if (provider != null) + { + try + { + return Cipher.getInstance (name + "/CBC/SSL3Padding", provider); + } + catch (NoSuchProviderException nspe) + { + // Fall through. Try any available provider. + } + } + return Cipher.getInstance (name + "/CBC/SSL3Padding"); + } + } + + static IMac getMac(String macName) + { + if (macName.startsWith("SSLMAC-")) + { + return new SSLHMac(macName.substring(7)); + } + else + { + return MacFactory.getInstance(macName); + } + } + + static Mac getJCEMac (final String name) + throws NoSuchAlgorithmException + { + final String provider = Util.getSecurityProperty ("jessie.with.jce.provider"); + if (provider != null) + { + try + { + return Mac.getInstance (name, provider); + } + catch (NoSuchProviderException nspe) + { + // Fall through. Try any available provider. + } + } + return Mac.getInstance (name); + } + + // Intance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write(id); + } + + CipherSuite resolve(ProtocolVersion version) + { + if (version == ProtocolVersion.SSL_3) + { + if (id[0] == 0x00) switch (id[1]) + { + case 0x00: return SSL_NULL_WITH_NULL_NULL; + case 0x01: return SSL_RSA_WITH_NULL_MD5; + case 0x02: return SSL_RSA_WITH_NULL_SHA; + case 0x03: return SSL_RSA_EXPORT_WITH_RC4_40_MD5; + case 0x04: return SSL_RSA_WITH_RC4_128_MD5; + case 0x05: return SSL_RSA_WITH_RC4_128_SHA; + case 0x08: return SSL_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x09: return SSL_RSA_WITH_DES_CBC_SHA; + case 0x0A: return SSL_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x0B: return SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x0C: return SSL_DH_DSS_WITH_DES_CBC_SHA; + case 0x0D: return SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x0E: return SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x0F: return SSL_DH_RSA_WITH_DES_CBC_SHA; + case 0x10: return SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x11: return SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x12: return SSL_DHE_DSS_WITH_DES_CBC_SHA; + case 0x13: return SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x14: return SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x15: return SSL_DHE_RSA_WITH_DES_CBC_SHA; + case 0x16: return SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x2F: return SSL_RSA_WITH_AES_128_CBC_SHA; + case 0x30: return SSL_DH_DSS_WITH_AES_128_CBC_SHA; + case 0x31: return SSL_DH_RSA_WITH_AES_128_CBC_SHA; + case 0x32: return SSL_DHE_DSS_WITH_AES_128_CBC_SHA; + case 0x33: return SSL_DHE_RSA_WITH_AES_128_CBC_SHA; + case 0x35: return SSL_RSA_WITH_AES_256_CBC_SHA; + case 0x36: return SSL_DH_DSS_WITH_AES_256_CBC_SHA; + case 0x37: return SSL_DH_RSA_WITH_AES_256_CBC_SHA; + case 0x38: return SSL_DHE_DSS_WITH_AES_256_CBC_SHA; + case 0x39: return SSL_DHE_RSA_WITH_AES_256_CBC_SHA; + } + } + else if (version == ProtocolVersion.TLS_1 || + version == ProtocolVersion.TLS_1_1) + { + if (id[0] == 0x00) switch (id[1]) + { + case 0x00: return TLS_NULL_WITH_NULL_NULL; + case 0x01: return TLS_RSA_WITH_NULL_MD5; + case 0x02: return TLS_RSA_WITH_NULL_SHA; + case 0x03: return TLS_RSA_EXPORT_WITH_RC4_40_MD5; + case 0x04: return TLS_RSA_WITH_RC4_128_MD5; + case 0x05: return TLS_RSA_WITH_RC4_128_SHA; + case 0x08: return TLS_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x09: return TLS_RSA_WITH_DES_CBC_SHA; + case 0x0A: return TLS_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x0B: return TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x0C: return TLS_DH_DSS_WITH_DES_CBC_SHA; + case 0x0D: return TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x0E: return TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x0F: return TLS_DH_RSA_WITH_DES_CBC_SHA; + case 0x10: return TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x11: return TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; + case 0x12: return TLS_DHE_DSS_WITH_DES_CBC_SHA; + case 0x13: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x14: return TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; + case 0x15: return TLS_DHE_RSA_WITH_DES_CBC_SHA; + case 0x16: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x2F: return TLS_RSA_WITH_AES_128_CBC_SHA; + case 0x30: return TLS_DH_DSS_WITH_AES_128_CBC_SHA; + case 0x31: return TLS_DH_RSA_WITH_AES_128_CBC_SHA; + case 0x32: return TLS_DHE_DSS_WITH_AES_128_CBC_SHA; + case 0x33: return TLS_DHE_RSA_WITH_AES_128_CBC_SHA; + case 0x35: return TLS_RSA_WITH_AES_256_CBC_SHA; + case 0x36: return TLS_DH_DSS_WITH_AES_256_CBC_SHA; + case 0x37: return TLS_DH_RSA_WITH_AES_256_CBC_SHA; + case 0x38: return TLS_DHE_DSS_WITH_AES_256_CBC_SHA; + case 0x39: return TLS_DHE_RSA_WITH_AES_256_CBC_SHA; + case 0x50: return TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA; + case 0x51: return TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA; + case 0x52: return TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA; + case 0x53: return TLS_SRP_SHA_WITH_AES_128_CBC_SHA; + case 0x54: return TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA; + case 0x55: return TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA; + case 0x56: return TLS_SRP_SHA_WITH_AES_256_CBC_SHA; + case 0x57: return TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA; + case 0x58: return TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA; + case 0x70: return TLS_DHE_DSS_WITH_CAST_128_CBC_SHA; + case 0x71: return TLS_DHE_DSS_WITH_CAST_128_CBC_RMD; + case 0x72: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD; + case 0x73: return TLS_DHE_DSS_WITH_AES_128_CBC_RMD; + case 0x74: return TLS_DHE_DSS_WITH_AES_256_CBC_RMD; + case 0x75: return TLS_DHE_RSA_WITH_CAST_128_CBC_SHA; + case 0x76: return TLS_DHE_RSA_WITH_CAST_128_CBC_RMD; + case 0x77: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD; + case 0x78: return TLS_DHE_RSA_WITH_AES_128_CBC_RMD; + case 0x79: return TLS_DHE_RSA_WITH_AES_256_CBC_RMD; + case 0x7A: return TLS_RSA_WITH_CAST_128_CBC_SHA; + case 0x7B: return TLS_RSA_WITH_CAST_128_CBC_RMD; + case 0x7C: return TLS_RSA_WITH_3DES_EDE_CBC_RMD; + case 0x7D: return TLS_RSA_WITH_AES_128_CBC_RMD; + case 0x7E: return TLS_RSA_WITH_AES_256_CBC_RMD; + } + } + return this; + } + + String getCipher() + { + return cipherName; + } + + int getKeyLength() + { + return keyLength; + } + + String getKeyExchange() + { + return kexName; + } + + String getSignature() + { + return sigName; + } + + String getMac() + { + return macName; + } + + boolean isExportable() + { + return exportable; + } + + boolean isStreamCipher() + { + return isStream; + } + + String getAuthType() + { + if (kexName.equals("RSA")) + { + if (isExportable()) + { + return "RSA_EXPORT"; + } + return "RSA"; + } + return kexName + "_" + sigName; + } + + byte[] getId() + { + return id; + } + + ProtocolVersion getVersion() + { + return version; + } + + public boolean equals(Object o) + { + if (!(o instanceof CipherSuite)) + { + return false; + } + if (o == this) + return true; + byte[] id = ((CipherSuite) o).getId(); + return id[0] == this.id[0] && + id[1] == this.id[1]; + } + + public int hashCode() + { + if (version == null) + { + return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF); + } + return version.getMajor() << 24 | version.getMinor() << 16 + | (id[0] & 0xFF) << 8 | (id[1] & 0xFF); + } + + public String toString() + { + if (name == null) + { + return "UNKNOWN { " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }"; + } + return name; + } +} diff --git a/gnu/javax/net/ssl/provider/ClientHello.java b/gnu/javax/net/ssl/provider/ClientHello.java new file mode 100644 index 000000000..259051df1 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ClientHello.java @@ -0,0 +1,253 @@ +/* ClientHello.java -- SSL ClientHello message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.SSLProtocolException; + +final class ClientHello implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private ProtocolVersion version; + private Random random; + private byte[] sessionId; + private List suites; + private List comp; + private List extensions; + + // Constructor. + // ------------------------------------------------------------------------- + + ClientHello(ProtocolVersion version, Random random, + byte[] sessionId, List suites, List comp) + { + this(version, random, sessionId, suites, comp, null); + } + + ClientHello(ProtocolVersion version, Random random, + byte[] sessionId, List suites, List comp, List extensions) + { + this.version = version; + this.random = random; + this.sessionId = sessionId; + this.suites = suites; + this.comp = comp; + this.extensions = extensions; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ClientHello read(InputStream in) throws IOException + { + ProtocolVersion vers = ProtocolVersion.read(in); + Random rand = Random.read(in); + byte[] id = new byte[in.read() & 0xFF]; + in.read(id); + int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + ArrayList suites = new ArrayList(len / 2); + for (int i = 0; i < len; i += 2) + { + suites.add(CipherSuite.read(in).resolve(vers)); + } + len = in.read() & 0xFF; + ArrayList comp = new ArrayList(len); + for (int i = 0; i < len; i++) + { + comp.add(CompressionMethod.read(in)); + } + + List ext = null; + // Since parsing MAY need to continue into the extensions fields, or it + // may end here, the specified input stream MUST be a ByteArrayInputStream + // over all the data this hello contains. Otherwise this will mess up + // the data stream. + if (in.available() > 0) // then we have extensions. + { + ext = new LinkedList(); + len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + int count = 0; + while (count < len) + { + Extension e = Extension.read(in); + ext.add(e); + count += e.getValue().length + 4; + } + } + return new ClientHello(vers, rand, id, suites, comp, ext); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + version.write(out); + random.write(out); + out.write(sessionId.length); + out.write(sessionId); + out.write((suites.size() << 1) >>> 8 & 0xFF); + out.write((suites.size() << 1) & 0xFF); + for (Iterator i = suites.iterator(); i.hasNext(); ) + { + ((CipherSuite) i.next()).write(out); + } + out.write(comp.size()); + for (Iterator i = comp.iterator(); i.hasNext(); ) + { + out.write(((CompressionMethod) i.next()).getValue()); + } + if (extensions != null) + { + ByteArrayOutputStream out2 = new ByteArrayOutputStream(); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + { + ((Extension) i.next()).write(out2); + } + out.write(out2.size() >>> 8 & 0xFF); + out.write(out2.size() & 0xFF); + out2.writeTo(out); + } + } + + ProtocolVersion getVersion() + { + return version; + } + + Random getRandom() + { + return random; + } + + byte[] getSessionId() + { + return sessionId; + } + + List getCipherSuites() + { + return suites; + } + + List getCompressionMethods() + { + return comp; + } + + List getExtensions() + { + return extensions; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" version = " + version + ";"); + BufferedReader r = new BufferedReader(new StringReader(random.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";"); + out.println(" cipherSuites = {"); + for (Iterator i = suites.iterator(); i.hasNext(); ) + { + out.print(" "); + out.println(i.next()); + } + out.println(" };"); + out.print(" compressionMethods = { "); + for (Iterator i = comp.iterator(); i.hasNext(); ) + { + out.print(i.next()); + if (i.hasNext()) + out.print(", "); + } + out.println(" };"); + if (extensions != null) + { + out.println(" extensions = {"); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + { + r = new BufferedReader(new StringReader(i.next().toString())); + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println(" };"); + } + out.println("} ClientHello;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/ClientKeyExchange.java b/gnu/javax/net/ssl/provider/ClientKeyExchange.java new file mode 100644 index 000000000..828aa8d5e --- /dev/null +++ b/gnu/javax/net/ssl/provider/ClientKeyExchange.java @@ -0,0 +1,181 @@ +/* ClientKeyExchange.java -- SSL ClientKeyExchange message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.math.BigInteger; + +import java.security.PublicKey; +import java.security.interfaces.RSAKey; +import javax.crypto.interfaces.DHPublicKey; + +final class ClientKeyExchange implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Object exObject; + + // Constructors. + // ------------------------------------------------------------------------- + + ClientKeyExchange(byte[] encryptedSecret) + { + exObject = encryptedSecret; + } + + ClientKeyExchange(BigInteger bigint) + { + exObject = bigint; + } + + // Class method. + // ------------------------------------------------------------------------- + + static ClientKeyExchange read(InputStream in, CipherSuite suite, + PublicKey key) + throws IOException + { + DataInputStream din = new DataInputStream(in); + if (suite.getKeyExchange().equals("RSA")) + { + int len = 0; + if (suite.getVersion() == ProtocolVersion.SSL_3) + { + len = (((RSAKey) key).getModulus().bitLength()+7) / 8; + } + else + { + len = din.readUnsignedShort(); + } + byte[] buf = new byte[len]; + din.readFully(buf); + return new ClientKeyExchange(buf); + } + else if (suite.getKeyExchange().equals("SRP")) + { + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + return new ClientKeyExchange(new BigInteger(1, buf)); + } + else if (key == null || !(key instanceof DHPublicKey)) // explicit. + { + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + return new ClientKeyExchange(new BigInteger(1, buf)); + } + else + { + return new ClientKeyExchange(new byte[0]); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + throw new UnsupportedOperationException("use write(java.io.OutputStream,ProtocolVersion) instead"); + } + + public void write(OutputStream out, ProtocolVersion version) throws IOException + { + if (exObject instanceof byte[]) + { + byte[] b = (byte[]) exObject; + if (b.length > 0) + { + if (version != ProtocolVersion.SSL_3) + { + out.write(b.length >>> 8 & 0xFF); + out.write(b.length & 0xFF); + } + out.write(b); + } + } + else + { + byte[] bigint = ((BigInteger) exObject).toByteArray(); + if (bigint[0] == 0x00) + { + out.write(bigint.length - 1 >>> 8 & 0xFF); + out.write(bigint.length - 1 & 0xFF); + out.write(bigint, 1, bigint.length - 1); + } + else + { + out.write(bigint.length >>> 8 & 0xFF); + out.write(bigint.length & 0xFF); + out.write(bigint); + } + } + } + + Object getExchangeObject() + { + return exObject; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + if (exObject instanceof byte[] && ((byte[]) exObject).length > 0) + { + out.println(" encryptedPreMasterSecret ="); + out.print(Util.hexDump((byte[]) exObject, " ")); + } + else if (exObject instanceof BigInteger) + { + out.println(" clientPublic = " + ((BigInteger) exObject).toString(16) + ";"); + } + out.println("} ClientKeyExchange;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/CompressionMethod.java b/gnu/javax/net/ssl/provider/CompressionMethod.java new file mode 100644 index 000000000..c2fdf05f9 --- /dev/null +++ b/gnu/javax/net/ssl/provider/CompressionMethod.java @@ -0,0 +1,104 @@ +/* CompressionMethod.java -- the compression method enum. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +final class CompressionMethod implements Enumerated +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + static final CompressionMethod NULL = new CompressionMethod(0), + ZLIB = new CompressionMethod(1); + + private final int value; + + // Constructor. + // ------------------------------------------------------------------------- + + private CompressionMethod(int value) + { + this.value = value; + } + + // Class method. + // ------------------------------------------------------------------------- + + static CompressionMethod read(InputStream in) throws IOException + { + int value = in.read(); + if (value == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (value & 0xFF) + { + case 0: return NULL; + case 1: return ZLIB; + default: return new CompressionMethod(value); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "null"; + case 1: return "zlib"; + default: return "unknown(" + value + ")"; + } + } +} diff --git a/gnu/javax/net/ssl/provider/Constructed.java b/gnu/javax/net/ssl/provider/Constructed.java new file mode 100644 index 000000000..ee3f56a7f --- /dev/null +++ b/gnu/javax/net/ssl/provider/Constructed.java @@ -0,0 +1,57 @@ +/* Constructed.java -- constructed type. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * The base interface to SSL constructed types. + */ +interface Constructed +{ + + /** + * Writes this structure's encoded form to the given output stream. + * + * @param out The output stream. + * @throws IOException If an I/O error occurs. + */ + void write(OutputStream out) throws IOException; +} diff --git a/gnu/javax/net/ssl/provider/ContentType.java b/gnu/javax/net/ssl/provider/ContentType.java new file mode 100644 index 000000000..336809467 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ContentType.java @@ -0,0 +1,135 @@ +/* ContentType.java -- record layer content type. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; + +/** + * The content type enumeration, which marks packets in the record layer. + * + *
enum { change_cipher_spec(20), alert(21), handshake(22),
+ *             application_data(23), (255) } ContentType;
+ * + * @author Casey Marshall (rsdio@metastatic.org) + */ +final class ContentType implements Enumerated +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + static final ContentType CLIENT_HELLO_V2 = new ContentType( 1); + static final ContentType CHANGE_CIPHER_SPEC = new ContentType(20); + static final ContentType ALERT = new ContentType(21); + static final ContentType HANDSHAKE = new ContentType(22); + static final ContentType APPLICATION_DATA = new ContentType(23); + + private int value; + + // Constructors. + // ------------------------------------------------------------------------ + + private ContentType(int value) + { + this.value = value; + } + + // Class methods. + // ------------------------------------------------------------------------ + + static final ContentType read(InputStream in) throws IOException + { + int value = in.read(); + if (value == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (value & 0xFF) + { + case 1: return CLIENT_HELLO_V2; + case 20: return CHANGE_CIPHER_SPEC; + case 21: return ALERT; + case 22: return HANDSHAKE; + case 23: return APPLICATION_DATA; + default: return new ContentType(value); + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public boolean equals(Object o) + { + if (o == null || !(o instanceof ContentType)) + { + return false; + } + return ((ContentType) o).value == value; + } + + public int hashCode() + { + return getValue(); + } + + public String toString() + { + switch (value) + { + case 1: return "v2_client_hello"; + case 20: return "change_cipher_spec"; + case 21: return "alert"; + case 22: return "handshake"; + case 23: return "application_data"; + default: return "unknown(" + value + ")"; + } + } +} diff --git a/gnu/javax/net/ssl/provider/Context.java b/gnu/javax/net/ssl/provider/Context.java new file mode 100644 index 000000000..2bd7193f2 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Context.java @@ -0,0 +1,334 @@ +/* Context.java -- SSLContext implementation. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.File; +import java.io.InputStream; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStoreException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.sql.SQLException; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContextSpi; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.SRPTrustManager; +import gnu.javax.net.ssl.StaticTrustAnchors; + +/** + * This is Jessie's implementation of a {@link javax.net.ssl.SSLContext} + * engine, and is available under the algorithm names ``SSLv3'', ``SSL'', + * ``TLSv1'', and ``TLS''. + */ +public final class Context extends SSLContextSpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + private SessionContext clientSessions; + private SessionContext serverSessions; + private X509KeyManager keyManager; + private X509TrustManager trustManager; + private SRPTrustManager srpTrustManager; + private SecureRandom random; + + // Constructor. + // ------------------------------------------------------------------------- + + public Context() + { + String codec = Util.getSecurityProperty("jessie.clientSessionContext.codec"); + String codecClass = null; + if (codec == null) + { + codec = "null"; + } + if (codec.equalsIgnoreCase("xml")) + { + codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext"; + } + else if (codec.equalsIgnoreCase("jdbc")) + { + codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext"; + } + else if (codec.equalsIgnoreCase("null")) + { + codecClass = "gnu.javax.net.ssl.provider.SessionContext"; + } + else + { + throw new IllegalArgumentException("no such codec: " + codec); + } + try + { + ClassLoader cl = Context.class.getClassLoader(); + if (cl == null) + { + cl = ClassLoader.getSystemClassLoader(); + } + clientSessions = (SessionContext) cl.loadClass(codecClass).newInstance(); + } + catch (Exception ex) + { + ex.printStackTrace(); + throw new IllegalArgumentException(ex.toString()); + } + + codec = Util.getSecurityProperty("jessie.serverSessionContext.codec"); + if (codec == null) + { + codec = "null"; + } + if (codec.equalsIgnoreCase("xml")) + { + codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext"; + } + else if (codec.equalsIgnoreCase("jdbc")) + { + codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext"; + } + else if (codec.equalsIgnoreCase("null")) + { + codecClass = "gnu.javax.net.ssl.provider.SessionContext"; + } + else + { + throw new IllegalArgumentException("no such codec: " + codec); + } + try + { + ClassLoader cl = Context.class.getClassLoader(); + if (cl == null) + { + cl = ClassLoader.getSystemClassLoader(); + } + serverSessions = (SessionContext) cl.loadClass(codecClass).newInstance(); + } + catch (Exception ex) + { + ex.printStackTrace(); + throw new IllegalArgumentException(ex.toString()); + } + } + + // Engine methods. + // ------------------------------------------------------------------------- + + protected SSLSessionContext engineGetClientSessionContext() + { + return clientSessions; + } + + protected SSLSessionContext engineGetServerSessionContext() + { + return serverSessions; + } + + protected javax.net.ssl.SSLServerSocketFactory engineGetServerSocketFactory() + { + if (keyManager == null || (trustManager == null && srpTrustManager == null) + || random == null) + { + throw new IllegalStateException(); + } + return new SSLServerSocketFactory(trustManager, srpTrustManager, keyManager, + random, serverSessions); + } + + protected javax.net.ssl.SSLSocketFactory engineGetSocketFactory() + { + if (keyManager == null || trustManager == null || random == null) + { + throw new IllegalStateException(); + } + return new SSLSocketFactory(trustManager, keyManager, random, clientSessions); + } + + protected void engineInit(KeyManager[] keyManagers, + TrustManager[] trustManagers, SecureRandom random) + throws KeyManagementException + { + keyManager = null; + trustManager = null; + srpTrustManager = null; + if (keyManagers != null) + { + for (int i = 0; i < keyManagers.length; i++) + { + if (keyManagers[i] instanceof X509KeyManager) + { + keyManager = (X509KeyManager) keyManagers[i]; + break; + } + } + } + if (keyManager == null) + { + keyManager = defaultKeyManager(); + } + if (trustManagers != null) + { + for (int i = 0; i < trustManagers.length; i++) + { + if (trustManagers[i] instanceof X509TrustManager) + { + if (trustManager == null) + { + trustManager = (X509TrustManager) trustManagers[i]; + } + } + else if (trustManagers[i] instanceof SRPTrustManager) + { + if (srpTrustManager == null) + { + srpTrustManager = (SRPTrustManager) trustManagers[i]; + } + } + } + } + if (trustManager == null && srpTrustManager == null) + { + trustManager = defaultTrustManager(); + } + if (random != null) + { + this.random = random; + } + else + { + this.random = defaultRandom(); + } + } + + // Own methods. + // ------------------------------------------------------------------------- + + private X509KeyManager defaultKeyManager() throws KeyManagementException + { + KeyManagerFactory fact = null; + try + { + fact = KeyManagerFactory.getInstance("JessieX509", "Jessie"); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(); + } + catch (NoSuchProviderException nspe) + { + throw new KeyManagementException(); + } + try + { + fact.init(null, null); + return (X509KeyManager) fact.getKeyManagers()[0]; + } + catch (NoSuchAlgorithmException nsae) { } + catch (KeyStoreException kse) { } + catch (UnrecoverableKeyException uke) { } + catch (IllegalStateException ise) { } + + try + { + fact.init(new NullManagerParameters()); + return (X509KeyManager) fact.getKeyManagers()[0]; + } + catch (Exception shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + } + + private X509TrustManager defaultTrustManager() throws KeyManagementException + { + try + { + TrustManagerFactory fact = + TrustManagerFactory.getInstance("JessieX509", "Jessie"); + fact.init(StaticTrustAnchors.CA_CERTS); + return (X509TrustManager) fact.getTrustManagers()[0]; + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(nsae.toString()); + } + catch (NoSuchProviderException nspe) + { + throw new KeyManagementException(nspe.toString()); + } + catch (InvalidAlgorithmParameterException kse) + { + throw new KeyManagementException(kse.toString()); + } + } + + private SecureRandom defaultRandom() throws KeyManagementException + { + String alg = Util.getSecurityProperty("jessie.secure.random"); + if (alg == null) + { + alg = "Fortuna"; + } + SecureRandom rand = null; + try + { + rand = SecureRandom.getInstance(alg); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(nsae.toString()); + } + + return rand; + } +} diff --git a/gnu/javax/net/ssl/provider/DiffieHellman.java b/gnu/javax/net/ssl/provider/DiffieHellman.java new file mode 100644 index 000000000..ad48c7959 --- /dev/null +++ b/gnu/javax/net/ssl/provider/DiffieHellman.java @@ -0,0 +1,285 @@ +/* DiffieHellman.java -- Diffie-Hellman key exchange. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.math.BigInteger; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; + +/** + *

Simple implementation of two-party Diffie-Hellman key agreement.

+ * + *

The primes used in this class are from the following documents:

+ * + *
    + *
  • D. Harkins and D. Carrel, "The Internet Key Exchange (IKE)", RFC 2409.
  • + *
  • T. Kivinen and M. Kojo, "More Modular + * Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange + * (IKE)", RFC + * 3526.
  • + * + * + *

    The generator for all these primes is 2.

    + */ +final class DiffieHellman +{ + + // Class method. + // ------------------------------------------------------------------------- + + /** + * Get the system's Diffie-Hellman parameters, in which g is 2 + * and p is determined by the property + * "jessie.keypool.dh.group". The default value for p + * is 18, corresponding to {@link #GROUP_18}. + */ + static GnuDHPrivateKey getParams() + { + BigInteger p = DiffieHellman.GROUP_5; + String group = Util.getSecurityProperty("jessie.key.dh.group"); + if (group != null) + { + group = group.trim(); + if (group.equals("1")) + p = DiffieHellman.GROUP_1; + else if (group.equals("2")) + p = DiffieHellman.GROUP_2; + else if (group.equals("5")) + p = DiffieHellman.GROUP_5; + else if (group.equals("14")) + p = DiffieHellman.GROUP_14; + else if (group.equals("15")) + p = DiffieHellman.GROUP_15; + else if (group.equals("16")) + p = DiffieHellman.GROUP_16; + else if (group.equals("17")) + p = DiffieHellman.GROUP_17; + else if (group.equals("18")) + p = DiffieHellman.GROUP_18; + } + return new GnuDHPrivateKey(null, p, DH_G, null); + } + + // Constants. + // ------------------------------------------------------------------------- + + /** + * The generator for all Diffie Hellman groups below. + */ + static final BigInteger DH_G = BigInteger.valueOf(2L); + + /** + * p = 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } + */ + static final BigInteger GROUP_1 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } + */ + static final BigInteger GROUP_2 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + + "FFFFFFFFFFFFFFFF", 16); + + /** + * This prime p = 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }. + */ + static final BigInteger GROUP_5 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }. + */ + static final BigInteger GROUP_14 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }. + */ + static final BigInteger GROUP_15 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }. + */ + static final BigInteger GROUP_16 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + + "FFFFFFFFFFFFFFFF", 16); + + static final BigInteger GROUP_17 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + + "6DCC4024FFFFFFFFFFFFFFFF", 16); + + /** + * p = 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }. + * + *

    This value, while quite large, is estimated to provide the equivalent + * cryptographic strength of a symmetric key between 190 and 320 bits. + */ + static final BigInteger GROUP_18 = new BigInteger("00" + + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" + + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" + + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" + + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" + + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" + + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" + + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" + + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" + + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" + + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" + + "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" + + "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" + + "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" + + "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" + + "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" + + "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" + + "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" + + "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" + + "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" + + "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 16); + +} diff --git a/gnu/javax/net/ssl/provider/DigestInputStream.java b/gnu/javax/net/ssl/provider/DigestInputStream.java new file mode 100644 index 000000000..dd138b436 --- /dev/null +++ b/gnu/javax/net/ssl/provider/DigestInputStream.java @@ -0,0 +1,103 @@ +/* DigestInputStream.java -- digesting input stream. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +import gnu.java.security.hash.IMessageDigest; + +final class DigestInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private IMessageDigest md5, sha; + private boolean digesting; + + // Constructor. + // ------------------------------------------------------------------------- + + DigestInputStream(InputStream in, IMessageDigest md5, IMessageDigest sha) + { + super(in); + if (md5 == null || sha == null) + throw new NullPointerException(); + this.md5 = md5; + this.sha = sha; + digesting = true; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + void setDigesting(boolean digesting) + { + this.digesting = digesting; + } + + public int read() throws IOException + { + int i = in.read(); + if (digesting && i != -1) + { + md5.update((byte) i); + sha.update((byte) i); + } + return i; + } + + public int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + public int read(byte[] buf, int off, int len) throws IOException + { + int ret = in.read(buf, off, len); + if (digesting && ret != -1) + { + md5.update(buf, off, ret); + sha.update(buf, off, ret); + } + return ret; + } +} diff --git a/gnu/javax/net/ssl/provider/DigestOutputStream.java b/gnu/javax/net/ssl/provider/DigestOutputStream.java new file mode 100644 index 000000000..f1548459e --- /dev/null +++ b/gnu/javax/net/ssl/provider/DigestOutputStream.java @@ -0,0 +1,107 @@ +/* DigestOutputStream.java -- digesting output stream. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import gnu.java.security.hash.IMessageDigest; + +final class DigestOutputStream extends FilterOutputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private IMessageDigest md5, sha; + private boolean digesting; + + // Constructor. + // ------------------------------------------------------------------------- + + DigestOutputStream(OutputStream out, IMessageDigest md5, IMessageDigest sha) + { + super(out); + this.md5 = md5; + this.sha = sha; + digesting = true; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + void setDigesting(boolean digesting) + { + this.digesting = digesting; + } + + public void write(int b) throws IOException + { + if (digesting) + { + md5.update((byte) b); + sha.update((byte) b); + } + out.write(b); + } + + public void write(byte[] buf) throws IOException + { + write(buf, 0, buf.length); + } + + public void write(byte[] buf, int off, int len) throws IOException + { + if (buf == null) + { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || off+len > buf.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + if (digesting) + { + md5.update(buf, off, len); + sha.update(buf, off, len); + } + out.write(buf, off, len); + } +} diff --git a/gnu/javax/net/ssl/provider/Enumerated.java b/gnu/javax/net/ssl/provider/Enumerated.java new file mode 100644 index 000000000..8875addab --- /dev/null +++ b/gnu/javax/net/ssl/provider/Enumerated.java @@ -0,0 +1,79 @@ +/* Enumerated.java -- Interface to enumerated types. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +/** + * An enumerated type in the SSL protocols. Enumerated values take on + * one of a set of possible numeric values, which are not specifically + * ordered, and may be extensible to a maximum value. + * + *

    enum { e1(v1), e2(v2), ... [[, (n) ]] }
    + * + *

    Enumerated types are encoded as big-endian multibyte integers, + * which take up the least possible number of bytes. Thus, an + * enumeration with up to 255 values will be encoded in a single byte, + * and so on. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +interface Enumerated +{ + + /** + * Returns the encoded value of this enumerated value, which is + * appropriate to send over-the-wire. + * + * @return The encoded value. + */ + byte[] getEncoded(); + + /** + * Returns the numeric value of this enumerated value. + * + * @return The numeric value. + */ + int getValue(); + + /** + * Returns a string representation of this enumerated value. + * + * @return The string. + */ + String toString(); +} diff --git a/gnu/javax/net/ssl/provider/Extension.java b/gnu/javax/net/ssl/provider/Extension.java new file mode 100644 index 000000000..1c79dd5cb --- /dev/null +++ b/gnu/javax/net/ssl/provider/Extension.java @@ -0,0 +1,214 @@ +/* Extension.java -- A TLS hello extension. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +final class Extension implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Type type; + private final byte[] value; + + // Constructor. + // ------------------------------------------------------------------------- + + Extension(Type type, byte[] value) + { + if (type == null || value == null) + { + throw new NullPointerException(); + } + this.type = type; + this.value = value; + } + + // Class method. + // ------------------------------------------------------------------------- + + static Extension read(InputStream in) throws IOException + { + Type t = Type.read(in); + int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + byte[] v = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(v, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of extension"); + } + count += l; + } + return new Extension(t, v); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write(type.getEncoded()); + out.write(value.length >>> 8 & 0xFF); + out.write(value.length & 0xFF); + out.write(value); + } + + Type getType() + { + return type; + } + + byte[] getValue() + { + return value; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" type = " + type + ";"); + out.println(" value ="); + out.println(Util.hexDump(value, " ")); + out.println("} Extension;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + static final class Type implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + static final Type SERVER_NAME = new Type(0); + static final Type MAX_FRAGMENT_LENGTH = new Type(1); + static final Type CLIENT_CERTIFICATE_URL = new Type(2); + static final Type TRUSTED_CA_KEYS = new Type(3); + static final Type TRUNCATED_HMAC = new Type(4); + static final Type STATUS_REQUEST = new Type(5); + static final Type SRP = new Type(6); + static final Type CERT_TYPE = new Type(7); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Type(int value) + { + this.value = value; + } + + // Class methods. + // ----------------------------------------------------------------------- + + static Type read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + int value = (i & 0xFF) << 8; + i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + value |= i & 0xFF; + switch (value) + { + case 0: return SERVER_NAME; + case 1: return MAX_FRAGMENT_LENGTH; + case 2: return CLIENT_CERTIFICATE_URL; + case 3: return TRUSTED_CA_KEYS; + case 4: return TRUNCATED_HMAC; + case 5: return STATUS_REQUEST; + case 6: return SRP; + case 7: return CERT_TYPE; + default: return new Type(value); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { + (byte) (value >>> 8 & 0xFF), (byte) (value & 0xFF) + }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "server_name"; + case 1: return "max_fragment_length"; + case 2: return "client_certificate_url"; + case 3: return "trusted_ca_keys"; + case 4: return "truncated_hmac"; + case 5: return "status_request"; + case 6: return "srp"; + case 7: return "cert_type"; + default: return "unknown(" + value + ")"; + } + } + } +} diff --git a/gnu/javax/net/ssl/provider/Extensions.java b/gnu/javax/net/ssl/provider/Extensions.java new file mode 100644 index 000000000..9ed9619f0 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Extensions.java @@ -0,0 +1,159 @@ +/* Extensions.java -- various static extension utilities. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import javax.security.auth.x500.X500Principal; + +import gnu.java.security.x509.X500DistinguishedName; + +final class Extensions +{ + + // Constants. + // ------------------------------------------------------------------------- + + private static final Integer _512 = new Integer(512), + _1024 = new Integer(1024), _2048 = new Integer(2048), + _4096 = new Integer(4096); + + // Class methods only. + private Extensions() { } + + // Class methods. + // ------------------------------------------------------------------------- + + static List getServerName(Extension ex) + { + LinkedList l = new LinkedList(); + byte[] buf = ex.getValue(); + int pos = 0; + try + { + while (pos < buf.length) + { + if (buf[pos++] != 0) + break; + int len = (buf[pos++] & 0xFF) << 8; + len |= buf[pos++] & 0xFF; + l.add(new String(buf, pos, len, "UTF-8")); + pos += len; + } + } + catch (Exception x) + { + } + return Collections.unmodifiableList(l); + } + + static List getClientCertTypes(Extension ex) throws IOException + { + List l = new LinkedList(); + ByteArrayInputStream in = new ByteArrayInputStream(ex.getValue()); + final int len = in.read() & 0xFF; + for (int i = 0; i < len; i++) + { + l.add(CertificateType.read(in)); + } + return Collections.unmodifiableList(l); + } + + static CertificateType getServerCertType(Extension ex) throws IOException + { + return CertificateType.read(new ByteArrayInputStream(ex.getValue())); + } + + static Integer getMaxFragmentLength(Extension ex) + { + switch (ex.getValue()[0] & 0xFF) + { + case 1: return _512; + case 2: return _1024; + case 3: return _2048; + case 4: return _4096; + } + throw new IllegalArgumentException(); + } + + static Object[] getTrustedCA(Extension ex) + { + byte[] buf = ex.getValue(); + int type = buf[0] & 0xFF; + try + { + switch (type) + { + case 0: + return new Object[] { new Integer(type), null }; + case 1: + case 3: + return new Object[] { new Integer(type), + Util.trim(buf, 1, 20) }; + case 2: + return new Object[] { new Integer(type), + new X500Principal(Util.trim(buf, 1, 20)) }; + } + } + catch (Exception x) + { + } + throw new IllegalArgumentException(); + } + + static String getSRPUsername(Extension ex) + { + int len = ex.getValue()[0] & 0xFF; + if (len > ex.getValue().length - 1) + throw new IllegalArgumentException(); + try + { + return new String(ex.getValue(), 1, len, "UTF-8"); + } + catch (UnsupportedEncodingException uee) + { + throw new Error(uee.toString()); + } + } +} diff --git a/gnu/javax/net/ssl/provider/Finished.java b/gnu/javax/net/ssl/provider/Finished.java new file mode 100644 index 000000000..8b9c220a5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Finished.java @@ -0,0 +1,143 @@ +/* Finished.java -- SSL Finished message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +final class Finished implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** TLSv1.x verify data. */ + private final byte[] verifyData; + + /** SSLv3 message digest pair. */ + private final byte[] md5, sha; + + // Constructor. + // ------------------------------------------------------------------------- + + Finished(byte[] verifyData) + { + this.verifyData = verifyData; + md5 = sha = null; + } + + Finished(byte[] md5, byte[] sha) + { + this.md5 = md5; + this.sha = sha; + verifyData = null; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Finished read(InputStream in, CipherSuite suite) + throws IOException + { + DataInputStream din = new DataInputStream(in); + if (suite.getVersion().equals(ProtocolVersion.SSL_3)) + { + byte[] md5 = new byte[16]; + byte[] sha = new byte[20]; + din.readFully(md5); + din.readFully(sha); + return new Finished(md5, sha); + } + else + { + byte[] buf = new byte[12]; + din.readFully(buf); + return new Finished(buf); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + if (verifyData != null) + out.write(verifyData); + else + { + out.write(md5); + out.write(sha); + } + } + + byte[] getVerifyData() + { + return verifyData; + } + + byte[] getMD5Hash() + { + return md5; + } + + byte[] getSHAHash() + { + return sha; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + if (verifyData != null) + { + return "struct {" + nl + + " verifyData = " + Util.toHexString(verifyData, ':') + ";" + nl + + "} Finished;" + nl; + } + else + { + return "struct {" + nl + + " md5Hash = " + Util.toHexString(md5, ':') + ";" + nl + + " shaHash = " + Util.toHexString(sha, ':') + ";" + nl + + "} Finished;" + nl; + } + } +} diff --git a/gnu/javax/net/ssl/provider/GNUSecurityParameters.java b/gnu/javax/net/ssl/provider/GNUSecurityParameters.java new file mode 100644 index 000000000..a04c3fd5c --- /dev/null +++ b/gnu/javax/net/ssl/provider/GNUSecurityParameters.java @@ -0,0 +1,490 @@ +/* GNUSecurityParameters.java -- SSL security parameters. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; + +import java.security.SecureRandom; +import java.security.Security; +import java.util.Arrays; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +import javax.net.ssl.SSLException; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mode.IMode; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +/** + * This class implements the {@link SecurityParameters} interface, using the + * GNU Crypto interface for ciphers and macs, and the JZlib package for + * record compression. + */ +class GNUSecurityParameters implements SecurityParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG_RECORD_LAYER = false; + private static final PrintWriter debug = new PrintWriter (System.err, true); + + /** + * The CBC block cipher, if any. + */ + IMode inCipher, outCipher; + + /** + * The RC4 PRNG, if any. + */ + IRandom inRandom, outRandom; + + /** + * The MAC algorithm. + */ + IMac inMac, outMac; + + long inSequence, outSequence; + Session session; + ProtocolVersion version; + int fragmentLength; + private Inflater inflater; + private Deflater deflater; + + // Constructors. + // ------------------------------------------------------------------------- + + GNUSecurityParameters (Session session) + { + inSequence = 0; + outSequence = 0; + this.session = session; + fragmentLength = 16384; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void reset() + { + inSequence = 0L; + outSequence = 0L; + inCipher = null; + outCipher = null; + inMac = null; + outMac = null; + inRandom = null; + outRandom = null; + deflater = null; + inflater = null; + } + + public ProtocolVersion getVersion() + { + return version; + } + + public void setVersion(ProtocolVersion version) + { + this.version = version; + } + + public void setInCipher(Object inCipher) + { + if (inCipher instanceof IMode) + { + this.inCipher = (IMode) inCipher; + inRandom = null; + } + else + { + inRandom = (IRandom) inCipher; + this.inCipher = null; + } + } + + public void setOutCipher(Object outCipher) + { + if (outCipher instanceof IMode) + { + this.outCipher = (IMode) outCipher; + outRandom = null; + } + else + { + outRandom = (IRandom) outCipher; + this.outCipher = null; + } + } + + public void setInMac(Object inMac) + { + this.inMac = (IMac) inMac; + inSequence = 0L; + } + + public void setOutMac(Object outMac) + { + this.outMac = (IMac) outMac; + outSequence = 0L; + } + + public void setDeflating (boolean deflate) + { + if (deflate) + { + if (deflater == null) + deflater = new Deflater(); + } + else + deflater = null; + } + + public void setInflating (boolean inflate) + { + if (inflate) + { + if (inflater == null) + inflater = new Inflater(); + } + else + inflater = null; + } + + public int getFragmentLength() + { + return fragmentLength; + } + + public void setFragmentLength (int fragmentLength) + { + this.fragmentLength = fragmentLength; + } + + /** + * Decrypt, verify, and decompress a fragment, returning the transformed + * fragment. + * + * @param fragment The fragment to decrypt. + * @param version The protocol version of the fragment's record. + * @param type The content type of the record. + * @return The decrypted fragment. + * @throws MacException If the MAC could not be verified. + * @throws OverflowException If the inflated data is too large. + * @throws SSLException If decompressing fails. + */ + public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version, + ContentType type) + throws MacException, OverflowException, SSLException + { + boolean badPadding = false; + + // Decrypt the ciphertext, if it is encrypted. + if (inCipher != null) + { + int bs = inCipher.currentBlockSize (); + for (int i = 0; i < fragment.length; i += bs) + { + inCipher.update (fragment, i, fragment, i); + } + int padLen = fragment[fragment.length-1] & 0xFF; + int len = fragment.length - padLen - 1; + if (version == ProtocolVersion.SSL_3) + { + // SSLv3 requires that the padding length not exceed the + // cipher's block size. + if (padLen >= bs) + { + badPadding = true; + } + } + else + { + for (int i = len; i < fragment.length; i++) + { + // If the TLS padding is wrong, throw a MAC exception below. + if ((fragment[i] & 0xFF) != padLen) + { + badPadding = true; + } + } + } + fragment = Util.trim (fragment, len); + } + else if (inRandom != null) + { + transformRC4 (fragment, 0, fragment.length, fragment, 0, inRandom); + } + + // Check the MAC. + if (inMac != null) + { + inMac.update ((byte) (inSequence >>> 56)); + inMac.update ((byte) (inSequence >>> 48)); + inMac.update ((byte) (inSequence >>> 40)); + inMac.update ((byte) (inSequence >>> 32)); + inMac.update ((byte) (inSequence >>> 24)); + inMac.update ((byte) (inSequence >>> 16)); + inMac.update ((byte) (inSequence >>> 8)); + inMac.update ((byte) inSequence); + inMac.update ((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + inMac.update ((byte) version.getMajor()); + inMac.update ((byte) version.getMinor()); + } + int macLen = inMac.macSize (); + int fragLen = fragment.length - macLen; + inMac.update ((byte) (fragLen >>> 8)); + inMac.update ((byte) fragLen); + inMac.update (fragment, 0, fragLen); + byte[] mac = inMac.digest (); + inMac.reset (); + for (int i = 0; i < macLen; i++) + { + if (fragment[i + fragLen] != mac[i]) + { + throw new MacException(); + } + } + if (badPadding) + { + throw new MacException(); + } + fragment = Util.trim (fragment, fragLen); + } + + if (inflater != null) + { + byte[] buf = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1); + inflater.setInput (fragment); + int len; + try + { + while ((len = inflater.inflate (buf)) > 0) + { + bout.write (buf, 0, len); + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("inflated data too large"); + } + } + catch (DataFormatException dfe) + { + throw new SSLException (String.valueOf (dfe)); + } + fragment = bout.toByteArray(); + inflater.reset(); + } + + inSequence++; + return fragment; + } + + /** + * Compress, MAC, encrypt, and write a record. The fragment of the + * record is taken from buf as len bytes starting at + * offset. len must be smaller than or equal to + * the configured fragment length. + * + * @param buf The fragment bytes. + * @param off The offset from whence to read. + * @param len The size of the fragment. + * @param type The content-type for this record. + * @param out The output stream to write the record to. + * @throws IOException If an I/O error occurs. + * @throws SSLException If compression fails. + * @throws OverflowException If compression inflates the data beyond + * the fragment length plus 1024 bytes. + */ + public synchronized byte[] encrypt (byte[] buf, int off, int len, + ContentType type) + throws SSLException, OverflowException + { + // If we are compressing, do it. + if (deflater != null) + { + byte[] buf2 = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1); + deflater.setInput (buf, off, len); + deflater.finish(); + len = 0; + while ((len = deflater.deflate (buf2)) > 0) + bout.write (buf2, 0, len); + // This should technically never happen for zlib. + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("deflated data too large"); + buf = bout.toByteArray(); + off = 0; + len = buf.length; + deflater.reset(); + } + + // If there is a MAC, compute it. + byte[] mac = new byte[0]; + if (outMac != null) + { + outMac.update((byte) (outSequence >>> 56)); + outMac.update((byte) (outSequence >>> 48)); + outMac.update((byte) (outSequence >>> 40)); + outMac.update((byte) (outSequence >>> 32)); + outMac.update((byte) (outSequence >>> 24)); + outMac.update((byte) (outSequence >>> 16)); + outMac.update((byte) (outSequence >>> 8)); + outMac.update((byte) outSequence); + outMac.update((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + outMac.update((byte) version.getMajor()); + outMac.update((byte) version.getMinor()); + } + outMac.update((byte) (len >>> 8)); + outMac.update((byte) len); + outMac.update(buf, off, len); + mac = outMac.digest(); + outMac.reset(); + } + outSequence++; + + // Compute padding if needed. + byte[] pad = new byte[0]; + if (outCipher != null) + { + int padLen = outCipher.currentBlockSize() - + ((len + mac.length + 1) % outCipher.currentBlockSize()); + // Use a random amount of padding if the protocol is TLS. + if (version != ProtocolVersion.SSL_3 && session.random != null) + { + padLen += (Math.abs(session.random.nextInt ()) & 7) * + outCipher.currentBlockSize(); + while (padLen > 255) + { + padLen -= outCipher.currentBlockSize(); + } + } + pad = new byte[padLen+1]; + Arrays.fill (pad, (byte) padLen); + } + + // Write the record header. + final int fraglen = len + mac.length + pad.length; + + // Encrypt and write the fragment. + if (outCipher != null) + { + byte[] buf2 = new byte[fraglen]; + System.arraycopy (buf, off, buf2, 0, len); + System.arraycopy (mac, 0, buf2, len, mac.length); + System.arraycopy (pad, 0, buf2, len + mac.length, pad.length); + int bs = outCipher.currentBlockSize (); + for (int i = 0; i < fraglen; i += bs) + { + outCipher.update (buf2, i, buf2, i); + } + return buf2; + } + else if (outRandom != null) + { + byte[] buf2 = new byte[fraglen]; + transformRC4 (buf, off, len, buf2, 0, outRandom); + transformRC4 (mac, 0, mac.length, buf2, len, outRandom); + return buf2; + } + else + { + if (mac.length == 0) + { + return Util.trim (buf, off, len); + } + else + { + return Util.concat (Util.trim (buf, off, len), mac); + } + } + } + + // Own methods. + // ------------------------------------------------------------------------- + + /** + * Encrypt/decrypt a byte array with the RC4 stream cipher. + * + * @param in The input data. + * @param off The input offset. + * @param len The number of bytes to transform. + * @param out The output buffer. + * @param outOffset The offest into the output buffer. + * @param random The ARCFOUR PRNG. + */ + private static void transformRC4(byte[] in, int off, int len, + byte[] out, int outOffset, IRandom random) + { + if (random == null) + { + throw new IllegalStateException(); + } + if (in == null || out == null) + { + throw new NullPointerException(); + } + if (off < 0 || off + len > in.length || + outOffset < 0 || outOffset + len > out.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + + try + { + for (int i = 0; i < len; i++) + { + out[outOffset+i] = (byte) (in[off+i] ^ random.nextByte()); + } + } + catch (LimitReachedException cannotHappen) + { + throw new Error(cannotHappen.toString()); + } + } +} diff --git a/gnu/javax/net/ssl/provider/Handshake.java b/gnu/javax/net/ssl/provider/Handshake.java new file mode 100644 index 000000000..ef9e72381 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Handshake.java @@ -0,0 +1,440 @@ +/* Handshake.java -- SSL handshake message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.security.PublicKey; + +import java.util.ArrayList; +import java.util.Collections; + +import javax.net.ssl.SSLProtocolException; + +final class Handshake implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final buffer BUF = new buffer(); + + private final Type type; + private final Body body; + + // Constructors. + // ------------------------------------------------------------------------- + + Handshake(Type type, Body body) + { + this.type = type; + this.body = body; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Handshake read(byte[] buffer) throws IOException + { + return read(new ByteArrayInputStream(buffer)); + } + + static Handshake read(byte[] buffer, CipherSuite suite, PublicKey key) + throws IOException + { + return read(new ByteArrayInputStream(buffer), suite, key); + } + + static Handshake read(InputStream in) throws IOException + { + return read(in, null, null); + } + + static Handshake read(InputStream in, CipherSuite suite, PublicKey key) + throws IOException + { + return read(in, suite, key, null); + } + + static Handshake read(InputStream in, CertificateType certType) + throws IOException + { + return read(in, null, null, certType); + } + + static Handshake read(InputStream in, CipherSuite suite, PublicKey key, + CertificateType certType) + throws IOException + { + Type type = Type.read(in); + byte[] lenbuf = new byte[3]; + in.read(lenbuf); + int len = (lenbuf[0] & 0xFF) << 16 | (lenbuf[1] & 0xFF) << 8 + | (lenbuf[2] & 0xFF); + Body body = null; + if (type == Type.HELLO_REQUEST) + { + body = null; + } + else if (type == Type.CLIENT_HELLO) + { + // Most likely a V2 hello. If the first byte is 0x30, and if this + // is not a V2 client hello, then it is a V3 client hello with + // at least 1.5 million cipher specs, which is unlikely. + if (lenbuf[0] == 3 && (lenbuf[1] >= 0 && lenbuf[1] <= 2)) + { + ProtocolVersion vers = null; + switch (lenbuf[1]) + { + case 0: + vers = ProtocolVersion.SSL_3; + break; + case 1: + vers = ProtocolVersion.TLS_1; + break; + case 2: + vers = ProtocolVersion.TLS_1_1; + break; + } + int specLen = (lenbuf[2] & 0xFF) << 8 | (in.read() & 0xFF); + int idLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + int chalLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + + ArrayList suites = new ArrayList(specLen / 3); + for (int i = 0; i < specLen; i += 3) + { + if (in.read() == 0) + { + suites.add(CipherSuite.read(in).resolve(vers)); + } + else + { + in.read(); + in.read(); + } + } + byte[] id = new byte[idLen]; + in.read(id); + byte[] challenge = new byte[chalLen]; + in.read(challenge); + if (challenge.length > 32) + challenge = Util.trim(challenge, 32); + else if (challenge.length < 32) + { + byte[] b = new byte[32]; + System.arraycopy(challenge, 0, b, b.length - challenge.length, + challenge.length); + challenge = b; + } + int time = (challenge[0] & 0xFF) << 24 | (challenge[1] & 0xFF) << 16 + | (challenge[2] & 0xFF) << 8 | (challenge[3] & 0xFF); + Random rand = new Random(time, Util.trim(challenge, 4, 28)); + return new Handshake(Handshake.Type.CLIENT_HELLO, + new ClientHello(vers, rand, id, suites, + Collections.singletonList(CompressionMethod.NULL))); + } + // Since hello messages may contain extensions, we read the whole + // thing here. + byte[] buf = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(buf, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of input stream"); + } + count += l; + } + body = ClientHello.read(new ByteArrayInputStream(buf)); + } + else if (type == Type.SERVER_HELLO) + { + byte[] buf = new byte[len]; + int count = 0; + while (count < len) + { + int l = in.read(buf, count, len - count); + if (l == -1) + { + throw new EOFException("unexpected end of input stream"); + } + count += l; + } + body = ServerHello.read(new ByteArrayInputStream(buf)); + } + else if (type == Type.CERTIFICATE) + { + body = Certificate.read(in, certType); + } + else if (type == Type.SERVER_KEY_EXCHANGE) + { + body = ServerKeyExchange.read(in, suite, key); + } + else if (type == Type.CERTIFICATE_REQUEST) + { + body = CertificateRequest.read(in); + } + else if (type == Type.CERTIFICATE_VERIFY) + { + body = (CertificateVerify) CertificateVerify.read(in, suite, key); + } + else if (type == Type.CLIENT_KEY_EXCHANGE) + { + body = ClientKeyExchange.read(in, suite, key); + } + else if (type == Type.SERVER_HELLO_DONE) + { + body = null; + } + else if (type == Type.FINISHED) + { + body = Finished.read(in, suite); + } + else + { + throw new SSLProtocolException("unknown HandshakeType: " + + type.getValue()); + } + + return new Handshake(type, body); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) + { + throw new UnsupportedOperationException(); + } + + public int write(OutputStream out, ProtocolVersion version) + throws IOException + { + out.write(type.getValue()); + if (body == null) + { + out.write(0); + out.write(0); + out.write(0); + return 4; + } + else + { + ByteArrayOutputStream bout = BUF.getBuffer(); + bout.reset(); + if (body instanceof ServerKeyExchange) + { + ((ServerKeyExchange) body).write(bout, version); + } + else if (body instanceof ClientKeyExchange) + { + ((ClientKeyExchange) body).write(bout, version); + } + else if (body instanceof CertificateVerify) + { + ((CertificateVerify) body).write(bout, version); + } + else + { + body.write(bout); + } + out.write(bout.size() >>> 16 & 0xFF); + out.write(bout.size() >>> 8 & 0xFF); + out.write(bout.size() & 0xFF); + bout.writeTo(out); + return 4 + bout.size(); + } + } + + Type getType() + { + return type; + } + + Body getBody() + { + return body; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + String nl = System.getProperty("line.separator"); + StringBuffer buf = new StringBuffer(); + out.println("struct {"); + out.println(" type = " + type + ";"); + if (body != null) + { + BufferedReader r = new BufferedReader(new StringReader(body.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println("} Handshake;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + static interface Body extends Constructed + { + } + + static class Type implements Enumerated + { + + // Constants and fields. + // ----------------------------------------------------------------------- + + public static final Type + HELLO_REQUEST = new Type( 0), CLIENT_HELLO = new Type( 1), + SERVER_HELLO = new Type( 2), CERTIFICATE = new Type(11), + SERVER_KEY_EXCHANGE = new Type(12), CERTIFICATE_REQUEST = new Type(13), + SERVER_HELLO_DONE = new Type(14), CERTIFICATE_VERIFY = new Type(15), + CLIENT_KEY_EXCHANGE = new Type(16), FINISHED = new Type(20), + CERTIFICATE_URL = new Type(21), CERTIFICATE_STATUS = new Type(22); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private Type(int value) + { + this.value = value; + } + + // Class methods. + // ----------------------------------------------------------------------- + + public static Type read(InputStream in) throws IOException + { + int i = in.read(); + if (i == -1) + { + throw new EOFException("unexpected end of input stream"); + } + switch (i & 0xFF) + { + case 0: return HELLO_REQUEST; + case 1: return CLIENT_HELLO; + case 2: return SERVER_HELLO; + case 11: return CERTIFICATE; + case 12: return SERVER_KEY_EXCHANGE; + case 13: return CERTIFICATE_REQUEST; + case 14: return SERVER_HELLO_DONE; + case 15: return CERTIFICATE_VERIFY; + case 16: return CLIENT_KEY_EXCHANGE; + case 20: return FINISHED; + case 21: return CERTIFICATE_URL; + case 22: return CERTIFICATE_STATUS; + default: return new Type(i); + } + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return new byte[] { (byte) value }; + } + + public int getValue() + { + return value; + } + + public String toString() + { + switch (value) + { + case 0: return "hello_request"; + case 1: return "client_hello"; + case 2: return "server_hello"; + case 11: return "certificate"; + case 12: return "server_key_exchange"; + case 13: return "certificate_request"; + case 14: return "server_hello_done"; + case 15: return "certificate_verify"; + case 16: return "client_key_exchange"; + case 20: return "finished"; + case 21: return "certificate_url"; + case 22: return "certificate_status"; + default: return "unknown(" + value + ")"; + } + } + } + + private static class buffer extends ThreadLocal + { + static final int SIZE = 2048; + + protected Object initialValue() + { + return new ByteArrayOutputStream(SIZE); + } + + ByteArrayOutputStream getBuffer() + { + return (ByteArrayOutputStream) get(); + } + } +} diff --git a/gnu/javax/net/ssl/provider/JCESecurityParameters.java b/gnu/javax/net/ssl/provider/JCESecurityParameters.java new file mode 100644 index 000000000..6663c97b5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/JCESecurityParameters.java @@ -0,0 +1,307 @@ +/* JCESecurityParameters.java -- JCE-based security parameters. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.ByteArrayOutputStream; + +import java.util.Arrays; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.Mac; + +import javax.net.ssl.SSLException; + +class JCESecurityParameters implements SecurityParameters +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Cipher inCipher, outCipher; + private Mac inMac, outMac; + private Inflater inflater; + private Deflater deflater; + private int fragmentLength; + private long inSequence, outSequence; + private ProtocolVersion version; + + // Constructors. + // ------------------------------------------------------------------------- + + JCESecurityParameters () + { + fragmentLength = 16384; + inSequence = 0L; + outSequence = 0L; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void reset() + { + inCipher = null; + outCipher = null; + inMac = null; + outMac = null; + deflater = null; + inflater = null; + } + + public void setInCipher (Object inCipher) + { + this.inCipher = (Cipher) inCipher; + } + + public void setOutCipher (Object outCipher) + { + this.outCipher = (Cipher) outCipher; + } + + public void setInMac (Object inMac) + { + this.inMac = (Mac) inMac; + inSequence = 0L; + } + + public void setOutMac (Object outMac) + { + this.outMac = (Mac) outMac; + outSequence = 0L; + } + + public void setDeflating (boolean deflate) + { + if (deflate) + { + if (deflater == null) + deflater = new Deflater(); + } + else + deflater = null; + } + + public void setInflating (boolean inflate) + { + if (inflate) + { + if (inflater == null) + inflater = new Inflater(); + } + else + inflater = null; + } + + public int getFragmentLength() + { + return fragmentLength; + } + + public void setFragmentLength (int fragmentLength) + { + this.fragmentLength = fragmentLength; + } + + public ProtocolVersion getVersion() + { + return version; + } + + public void setVersion (ProtocolVersion version) + { + this.version = version; + } + + public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version, + ContentType type) + throws MacException, OverflowException, SSLException + { + boolean badpad = false; + if (inCipher != null) + { + // We imagine that the JCE would be used in cases where hardware + // acceleration is available, since it isn't really that useful for + // pure Java crypto. We decrypt (and encrypt, below) in one go + // to minimize (potential) calls to native methods. + try + { + fragment = inCipher.doFinal (fragment); + } + catch (BadPaddingException bpe) + { + badpad = true; + } + catch (IllegalBlockSizeException ibse) + { + badpad = true; + } + } + + if (inMac != null) + { + int macLen = inMac.getMacLength(); + int fragLen = fragment.length - macLen; + byte[] mac = Util.trim (fragment, fragLen, macLen); + fragment = Util.trim (fragment, fragLen); + inMac.update ((byte) (inSequence >>> 56)); + inMac.update ((byte) (inSequence >>> 48)); + inMac.update ((byte) (inSequence >>> 40)); + inMac.update ((byte) (inSequence >>> 32)); + inMac.update ((byte) (inSequence >>> 24)); + inMac.update ((byte) (inSequence >>> 16)); + inMac.update ((byte) (inSequence >>> 8)); + inMac.update ((byte) inSequence); + inMac.update ((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + inMac.update ((byte) version.getMajor()); + inMac.update ((byte) version.getMinor()); + } + inMac.update ((byte) (fragLen >>> 8)); + inMac.update ((byte) fragLen); + inMac.update (fragment); + if (!Arrays.equals (mac, inMac.doFinal()) || badpad) + throw new MacException(); + } + + if (inflater != null) + { + byte[] buf = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1); + inflater.setInput (fragment); + int len; + try + { + while ((len = inflater.inflate (buf)) > 0) + { + bout.write (buf, 0, len); + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("inflated data too large"); + } + } + catch (DataFormatException dfe) + { + throw new SSLException (String.valueOf (dfe)); + } + fragment = bout.toByteArray(); + inflater.reset(); + } + + inSequence++; + return fragment; + } + + public synchronized byte[] encrypt (byte[] fragment, int off, int len, + ContentType type) + throws OverflowException, SSLException + { + if (deflater != null) + { + byte[] buf = new byte[1024]; + ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1); + deflater.setInput (fragment, off, len); + deflater.finish(); + len = 0; + while ((len = deflater.deflate (buf)) > 0) + bout.write (buf, 0, len); + // This should technically never happen for zlib. + if (bout.size() > fragmentLength + 1024) + throw new OverflowException ("deflated data too large"); + fragment = bout.toByteArray(); + off = 0; + len = fragment.length; + deflater.reset(); + } + + if (outMac != null) + { + outMac.update ((byte) (inSequence >>> 56)); + outMac.update ((byte) (inSequence >>> 48)); + outMac.update ((byte) (inSequence >>> 40)); + outMac.update ((byte) (inSequence >>> 32)); + outMac.update ((byte) (inSequence >>> 24)); + outMac.update ((byte) (inSequence >>> 16)); + outMac.update ((byte) (inSequence >>> 8)); + outMac.update ((byte) inSequence); + outMac.update ((byte) type.getValue()); + if (version != ProtocolVersion.SSL_3) + { + outMac.update ((byte) version.getMajor()); + outMac.update ((byte) version.getMinor()); + } + outMac.update ((byte) (len >>> 8)); + outMac.update ((byte) len); + outMac.update (fragment, off, len); + fragment = Util.concat (fragment, outMac.doFinal()); + off = 0; + len = fragment.length; + } + + if (outCipher != null) + { + try + { + fragment = outCipher.doFinal (fragment, off, len); + } + catch (BadPaddingException shouldNeverHappen) + { + // This is nonsensical. Don't even pretend that we can handle this. + throw new RuntimeException ("bad padding thrown while encrypting"); + } + catch (IllegalBlockSizeException ibse) + { + // Ditto. + throw new RuntimeException ("illegal block size thrown while encrypting"); + } + off = 0; + len = fragment.length; + } + + outSequence++; + if (off == 0 && len == fragment.length) + return fragment; + else + return Util.trim (fragment, off, len); + } +} diff --git a/gnu/javax/net/ssl/provider/JDBCSessionContext.java b/gnu/javax/net/ssl/provider/JDBCSessionContext.java new file mode 100644 index 000000000..2b9b14034 --- /dev/null +++ b/gnu/javax/net/ssl/provider/JDBCSessionContext.java @@ -0,0 +1,356 @@ +/* JDBCSessionContext.java -- database persistent sessions. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.sql.Types; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.TreeSet; +import java.util.Vector; + +import javax.net.ssl.SSLSession; + +/** + * The SQL table this class stores sessions in, called SESSIONS, + * looks like this: + * + *

    + * TABLE SESSIONS (
    + *   ID             VARBINARY(32) PRIMARY KEY UNIQUE NOT NULL,
    + *   CREATED        TIMESTAMP NOT NULL,
    + *   LAST_ACCESSED  TIMESTAMP NOT NULL,
    + *   PROTOCOL       VARCHAR(7) NOT NULL,
    + *   SUITE          VARCHAR(255) NOT NULL,
    + *   PEER_HOST      TEXT NOT NULL,
    + *   PEER_CERT_TYPE VARCHAR(32),
    + *   PEER_CERTS     BLOB,
    + *   CERT_TYPE      VARCHAR(32),
    + *   CERTS          BLOB,
    + *   SECRET         VARBINARY(48) NOT NULL
    + * )
    + * 
    + * + *

    Note that the master secret for sessions is not protected before + * being inserted into the database; it is up to the system to protect + * the stored data from unauthorized access. + */ +class JDBCSessionContext extends SessionContext +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected Connection connection; + protected PreparedStatement selectById; + protected PreparedStatement insert; + protected PreparedStatement selectTimestamp; + protected PreparedStatement updateTimestamp; + protected PreparedStatement deleteSession; + + // Constructor. + // ------------------------------------------------------------------------- + + JDBCSessionContext() throws SQLException + { + String url = Util.getSecurityProperty("jessie.SessionContext.jdbc.url"); + String user = Util.getSecurityProperty("jessie.SessionContext.jdbc.user"); + String passwd = Util.getSecurityProperty("jessie.SessionContext.jdbc.password"); + if (url == null) + { + throw new IllegalArgumentException("no JDBC URL"); + } + if (user == null || passwd == null) + { + connection = DriverManager.getConnection(url); + } + else + { + connection = DriverManager.getConnection(url, user, passwd); + } + selectById = + connection.prepareStatement("SELECT * FROM SESSIONS WHERE ID = ?"); + insert = connection.prepareStatement("INSERT INTO SESSIONS VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + selectTimestamp = + connection.prepareStatement("SELECT CREATED FROM SESSIONS WHERE ID = ?"); + updateTimestamp = + connection.prepareStatement("UPDATE SESSIONS SET LAST_ACCESSED = ? WHERE ID = ?"); + deleteSession = + connection.prepareStatement("DELETE FROM SESSIONS WHERE ID = ?"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public synchronized Enumeration getIds() + { + Vector ids = new Vector(); + try + { + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT ID FROM SESSIONS"); + while (rs.next()) + { + byte[] id = rs.getBytes("ID"); + ids.add(id); + } + } + catch (SQLException sqle) + { + } + return ids.elements(); + } + + public synchronized SSLSession getSession(byte[] sessionId) + { + Session session = (Session) super.getSession(sessionId); + if (session == null) + { + try + { + selectById.setBytes(1, sessionId); + ResultSet rs = selectById.executeQuery(); + if (rs.next()) + { + session = new Session(rs.getTimestamp("CREATED").getTime()); + session.enabledSuites = new ArrayList(SSLSocket.supportedSuites); + session.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols); + session.random = new SecureRandom(); + session.context = this; + session.sessionId = new Session.ID(rs.getBytes("ID")); + session.setLastAccessedTime(rs.getTimestamp("LAST_ACCESSED").getTime()); + long elapsed = System.currentTimeMillis() - session.getLastAccessedTime(); + if ((int) (elapsed / 1000L) > timeout) + { + removeSession(session.sessionId); + return null; + } + session.peerHost = rs.getString("PEER_HOST"); + String protocol = rs.getString("PROTOCOL"); + if (protocol.equals("SSLv3")) + { + session.protocol = ProtocolVersion.SSL_3; + } + else if (protocol.equals("TLSv1")) + { + session.protocol = ProtocolVersion.TLS_1; + } + else if (protocol.equals("TLSv1.1")) + { + session.protocol = ProtocolVersion.TLS_1_1; + } + else + { + return null; + } + session.cipherSuite = CipherSuite.forName(rs.getString("SUITE")); + String type = rs.getString("PEER_CERT_TYPE"); + boolean wasNull = rs.wasNull(); + InputStream certs = null; + if (!wasNull) + { + certs = rs.getBinaryStream("PEER_CERTS"); + wasNull = rs.wasNull(); + } + if (!wasNull) + { + CertificateFactory cf = CertificateFactory.getInstance(type); + session.peerCerts = (Certificate[]) + cf.generateCertificates(certs).toArray(new Certificate[0]); + session.peerVerified = true; + } + type = rs.getString("CERT_TYPE"); + wasNull = rs.wasNull(); + if (!wasNull) + { + certs = rs.getBinaryStream("CERTS"); + wasNull = rs.wasNull(); + } + if (!wasNull) + { + CertificateFactory cf = CertificateFactory.getInstance(type); + session.localCerts = (Certificate[]) + cf.generateCertificates(certs).toArray(new Certificate[0]); + } + session.masterSecret = rs.getBytes("SECRET"); + if (cacheSize == 0 || sessions.size() < cacheSize) + { + sessions.put(session.sessionId, session); + } + } + } + catch (Exception ex) + { + } + } + return session; + } + + synchronized boolean addSession(Session.ID id, Session s) + { + if (containsSessionID(id)) + { + return false; + } + try + { + insert.setBytes(1, id.getId()); + insert.setTimestamp(2, new Timestamp(s.getCreationTime())); + insert.setTimestamp(3, new Timestamp(s.getLastAccessedTime())); + insert.setString(4, s.getProtocol()); + insert.setString(5, s.getCipherSuite()); + insert.setString(6, s.peerHost); + if (s.peerCerts != null && s.peerCerts.length > 0) + { + insert.setString(7, s.peerCerts[0].getType()); + insert.setBytes(8, certs(s.peerCerts)); + } + else + { + insert.setNull(7, Types.VARCHAR); + insert.setNull(8, Types.LONGVARBINARY); + } + if (s.localCerts != null && s.localCerts.length > 0) + { + insert.setString(9, s.localCerts[0].getType()); + insert.setBytes(10, certs(s.localCerts)); + } + else + { + insert.setNull(9, Types.VARCHAR); + insert.setNull(10, Types.LONGVARBINARY); + } + insert.setBytes(11, s.masterSecret); + insert.executeUpdate(); + super.addSession(id, s); + } + catch (SQLException sqle) + { + return false; + } + return true; + } + + synchronized boolean containsSessionID(Session.ID sessionId) + { + try + { + selectTimestamp.setBytes(1, sessionId.getId()); + ResultSet rs = selectTimestamp.executeQuery(); + if (!rs.next()) + { + return false; + } + Timestamp ts = rs.getTimestamp("CREATED"); + if (rs.wasNull()) + { + return false; + } + long elapsed = System.currentTimeMillis() - ts.getTime(); + if ((int) (elapsed / 1000) > timeout) + { + removeSession(sessionId); + return false; + } + return true; + } + catch (SQLException sqle) + { + return false; + } + } + + protected boolean removeSession(Session.ID sessionId) + { + super.removeSession(sessionId); + try + { + deleteSession.setBytes(1, sessionId.getId()); + return deleteSession.executeUpdate() > 0; + } + catch (SQLException sqle) + { + } + return false; + } + + synchronized void notifyAccess(Session session) + { + try + { + updateTimestamp.setTimestamp(1, new Timestamp(session.getLastAccessedTime())); + updateTimestamp.setBytes(2, session.getId()); + updateTimestamp.executeUpdate(); + } + catch (SQLException sqle) + { + } + } + + private byte[] certs(Certificate[] certs) + { + ByteArrayOutputStream out = new ByteArrayOutputStream(2048); + for (int i = 0; i < certs.length; i++) + { + try + { + out.write(certs[i].getEncoded()); + } + catch (Exception x) + { + } + } + return out.toByteArray(); + } +} diff --git a/gnu/javax/net/ssl/provider/Jessie.java b/gnu/javax/net/ssl/provider/Jessie.java new file mode 100644 index 000000000..14b671d02 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Jessie.java @@ -0,0 +1,91 @@ +/* Jessie.java -- JESSIE's JSSE provider. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; + +/** + * This is the security provider for Jessie. It implements the following + * algorithms: + * + *

    + * {@link javax.net.ssl.SSLContext}.SSLv3
    + * {@link javax.net.ssl.SSLContext}.SSL
    + * {@link javax.net.ssl.SSLContext}.TLSv1
    + * {@link javax.net.ssl.SSLContext}.TLS
    + * {@link javax.net.ssl.KeyManagerFactory}.JessieX509
    + * {@link javax.net.ssl.TrustManagerFactory}.JessieX509
    + * {@link javax.net.ssl.TrustManagerFactory}.SRP
    + * 
    + * + */ +public class Jessie extends Provider +{ + + public static final String VERSION = "1.0.0"; + public static final double VERSION_DOUBLE = 1.0; + + public Jessie() + { + super("Jessie", VERSION_DOUBLE, + "Implementing SSLv3, TLSv1 SSL Contexts; X.509 Key Manager Factories;" + + System.getProperty("line.separator") + + "X.509 and SRP Trust Manager Factories, continuously-seeded secure random." ); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + put("SSLContext.SSLv3", Context.class.getName()); + put("Alg.Alias.SSLContext.SSL", "SSLv3"); + put("Alg.Alias.SSLContext.TLSv1", "SSLv3"); + put("Alg.Alias.SSLContext.TLS", "SSLv3"); + //put("Alg.Alias.SSLContext.TLSv1.1", "SSLv3"); + + put("KeyManagerFactory.JessieX509", X509KeyManagerFactory.class.getName()); + put("TrustManagerFactory.JessieX509", X509TrustManagerFactory.class.getName()); + put("TrustManagerFactory.SRP", SRPTrustManagerFactory.class.getName()); + + return null; + } + }); + } +} diff --git a/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java b/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java new file mode 100644 index 000000000..1997458dd --- /dev/null +++ b/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java @@ -0,0 +1,99 @@ +/* JessieDHPrivateKey.java -- simple DH private key. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.spec.DHParameterSpec; + +class JessieDHPrivateKey implements DHPrivateKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final DHParameterSpec params; + private final BigInteger x; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieDHPrivateKey(DHParameterSpec params, BigInteger x) + { + this.params = params; + this.x = x; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "Diffie-Hellman"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public DHParameterSpec getParams() + { + return params; + } + + public BigInteger getX() + { + return x; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "P: " + params.getP() + nl + + "G: " + params.getG() + nl + + "X: " + x; + } +} diff --git a/gnu/javax/net/ssl/provider/JessieDHPublicKey.java b/gnu/javax/net/ssl/provider/JessieDHPublicKey.java new file mode 100644 index 000000000..dc6587288 --- /dev/null +++ b/gnu/javax/net/ssl/provider/JessieDHPublicKey.java @@ -0,0 +1,99 @@ +/* JessieDHPublicKey.java -- simple DH public key. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.math.BigInteger; + +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; + +class JessieDHPublicKey implements DHPublicKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final DHParameterSpec params; + private final BigInteger y; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieDHPublicKey(DHParameterSpec params, BigInteger y) + { + this.params = params; + this.y = y; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "Diffie-Hellman"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public DHParameterSpec getParams() + { + return params; + } + + public BigInteger getY() + { + return y; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "P: " + params.getP() + nl + + "G: " + params.getG() + nl + + "Y: " + y; + } +} diff --git a/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java b/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java new file mode 100644 index 000000000..4ec71a7aa --- /dev/null +++ b/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java @@ -0,0 +1,98 @@ +/* JessieRSAPrivateKey.java -- simple RSA private key. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.math.BigInteger; +import java.security.interfaces.RSAPrivateKey; + +class JessieRSAPrivateKey implements RSAPrivateKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final BigInteger modulus; + private final BigInteger exponent; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieRSAPrivateKey(BigInteger modulus, BigInteger exponent) + { + this.modulus = modulus; + this.exponent = exponent; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPrivateExponent() + { + return exponent; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "RSAPrivateKey {" + nl + + " modulus = " + modulus.toString(16) + ";" + nl + + " exponent = " + exponent.toString(16) + ";" + nl + + "};"; + } +} diff --git a/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java b/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java new file mode 100644 index 000000000..19921d98c --- /dev/null +++ b/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java @@ -0,0 +1,98 @@ +/* JessieRSAPublicKey.java -- simple RSA public key. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.math.BigInteger; +import java.security.interfaces.RSAPublicKey; + +class JessieRSAPublicKey implements RSAPublicKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final BigInteger modulus; + private final BigInteger exponent; + + // Constructor. + // ------------------------------------------------------------------------- + + JessieRSAPublicKey(BigInteger modulus, BigInteger exponent) + { + this.modulus = modulus; + this.exponent = exponent; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "NONE"; + } + + public byte[] getEncoded() + { + return null; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return exponent; + } + + public String toString() + { + String nl = System.getProperty("line.separator"); + return "RSAPublicKey {" + nl + + " modulus = " + modulus.toString(16) + ";" + nl + + " exponent = " + exponent.toString(16) + ";" + nl + + "};"; + } +} diff --git a/gnu/javax/net/ssl/provider/KeyPool.java b/gnu/javax/net/ssl/provider/KeyPool.java new file mode 100644 index 000000000..e342700c2 --- /dev/null +++ b/gnu/javax/net/ssl/provider/KeyPool.java @@ -0,0 +1,119 @@ +/* KeyPool.java -- A set of ephemeral key pairs. + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.Security; +import java.util.LinkedList; +import javax.crypto.spec.DHParameterSpec; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.Prime2; + +final class KeyPool +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final BigInteger ONE = BigInteger.ONE; + private static final BigInteger TWO = BigInteger.valueOf(2L); + private static final BigInteger E = BigInteger.valueOf(65537L); + private static final SecureRandom RANDOM = new SecureRandom (); + + // Constructor. + // ------------------------------------------------------------------------- + + private KeyPool() + { + } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Generate an export-class (512 bit) RSA key pair. + * + * @return The new key pair. + */ + static KeyPair generateRSAKeyPair() + { + BigInteger p, q, n, d; + + // Simplified version of GNU Crypto's RSAKeyPairGenerator. + + int M = 256; + BigInteger lower = TWO.pow(255); + BigInteger upper = TWO.pow(256).subtract(ONE); + byte[] kb = new byte[32]; + while (true) + { + nextBytes(kb); + p = new BigInteger(1, kb).setBit(0); + if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0 && + Prime2.isProbablePrime(p) && p.gcd(E).equals(ONE)) + break; + } + + while (true) + { + nextBytes(kb); + q = new BigInteger(1, kb).setBit(0); + n = q.multiply(p); + if (n.bitLength() == 512 && Prime2.isProbablePrime(q) && + q.gcd(E).equals(ONE)) + break; + } + + d = E.modInverse(p.subtract(ONE).multiply(q.subtract(ONE))); + + return new KeyPair(new JessieRSAPublicKey(n, E), + new JessieRSAPrivateKey(n, d)); + } + + private static void nextBytes(byte[] buf) + { + RANDOM.nextBytes (buf); + } +} diff --git a/gnu/javax/net/ssl/provider/MacException.java b/gnu/javax/net/ssl/provider/MacException.java new file mode 100644 index 000000000..b8c479fdb --- /dev/null +++ b/gnu/javax/net/ssl/provider/MacException.java @@ -0,0 +1,53 @@ +/* MacException.java -- signals a bad record MAC. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; + +class MacException extends IOException +{ + + // Constructor. + // ------------------------------------------------------------------------- + + MacException() + { + super(); + } +} diff --git a/gnu/javax/net/ssl/provider/OverflowException.java b/gnu/javax/net/ssl/provider/OverflowException.java new file mode 100644 index 000000000..93bdcaec5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/OverflowException.java @@ -0,0 +1,57 @@ +/* OverflowException.java -- signals an input overflow. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; + +class OverflowException extends IOException +{ + + // Constructors. + // ------------------------------------------------------------------------- + + OverflowException() + { + } + + OverflowException(String msg) + { + super(msg); + } +} diff --git a/gnu/javax/net/ssl/provider/ProtocolVersion.java b/gnu/javax/net/ssl/provider/ProtocolVersion.java new file mode 100644 index 000000000..5f5d1d979 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ProtocolVersion.java @@ -0,0 +1,180 @@ +/* ProtocolVersion.java -- An SSL version number. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +final class ProtocolVersion implements Comparable, Constructed +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0); + static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1); + static final ProtocolVersion TLS_1_1 = new ProtocolVersion(3, 2); + + private final int major; + private final int minor; + + // Constructor. + // ------------------------------------------------------------------------- + + private ProtocolVersion(int major, int minor) + { + this.major = major; + this.minor = minor; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ProtocolVersion read(InputStream in) throws IOException + { + int major = in.read() & 0xFF; + int minor = in.read() & 0xFF; + return getInstance(major, minor); + } + + static ProtocolVersion getInstance(int major, int minor) + { + if (major == 3) + { + switch (minor) + { + case 0: return SSL_3; + case 1: return TLS_1; + case 2: return TLS_1_1; + } + } + return new ProtocolVersion(major, minor); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write(major); + out.write(minor); + } + + byte[] getEncoded() + { + return new byte[] { + (byte) major, (byte) minor + }; + } + + int getMajor() + { + return major; + } + + int getMinor() + { + return minor; + } + + public boolean equals(Object o) + { + if (o == null || !(o instanceof ProtocolVersion)) + { + return false; + } + return ((ProtocolVersion) o).major == this.major + && ((ProtocolVersion) o).minor == this.minor; + } + + public int hashCode() + { + return major << 8 | minor; + } + + public int compareTo(Object o) + { + if (o == null || !(o instanceof ProtocolVersion)) + { + return 1; + } + if (this.equals(o)) + { + return 0; + } + if (major > ((ProtocolVersion) o).major) + { + return 1; + } + else if (major < ((ProtocolVersion) o).major) + { + return -1; + } + if (minor > ((ProtocolVersion) o).minor) + { + return 1; + } + else if (minor < ((ProtocolVersion) o).minor) + { + return -1; + } + return 0; + } + + public String toString() + { + if (this == SSL_3) + { + return "SSLv3"; + } + else if (this == TLS_1) + { + return "TLSv1"; + } + else if (this == TLS_1_1) + { + return "TLSv1.1"; + } + else + { + return "Unsupported; major=" + major + " minor=" + minor; + } + } +} diff --git a/gnu/javax/net/ssl/provider/Random.java b/gnu/javax/net/ssl/provider/Random.java new file mode 100644 index 000000000..c42592b14 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Random.java @@ -0,0 +1,124 @@ +/* Random.java -- SSL Random structure. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +class Random implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final int gmtUnixTime; + private final byte[] randomBytes; + + // Constructors. + // ------------------------------------------------------------------------- + + Random(int gmtUnixTime, byte[] randomBytes) + { + this.gmtUnixTime = gmtUnixTime; + this.randomBytes = (byte[]) randomBytes.clone(); + } + + // Class methods. + // ------------------------------------------------------------------------- + + static Random read(InputStream in) throws IOException + { + int time = (in.read() & 0xFF) << 24 | (in.read() & 0xFF) << 16 + | (in.read() & 0xFF) << 8 | (in.read() & 0xFF); + byte[] buf = new byte[28]; + in.read(buf); + return new Random(time, buf); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + out.write((gmtUnixTime >>> 24) & 0xFF); + out.write((gmtUnixTime >>> 16) & 0xFF); + out.write((gmtUnixTime >>> 8) & 0xFF); + out.write(gmtUnixTime & 0xFF); + out.write(randomBytes); + } + + byte[] getEncoded() + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(32); + try + { + write(bout); + } + catch (IOException cantHappen) + { + throw new Error(cantHappen.toString()); + } + return bout.toByteArray(); + } + + int getTime() + { + return gmtUnixTime; + } + + byte[] getRandomBytes() + { + return randomBytes; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" gmt_unix_time = " + gmtUnixTime + ";"); + out.println(" random_bytes = " + Util.toHexString(randomBytes, ':') + ";"); + out.println("} Random;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/RecordInput.java b/gnu/javax/net/ssl/provider/RecordInput.java new file mode 100644 index 000000000..d4ba5b596 --- /dev/null +++ b/gnu/javax/net/ssl/provider/RecordInput.java @@ -0,0 +1,232 @@ +/* RecordInput.java -- record layer input. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import gnu.classpath.SystemProperties; +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.PrintWriter; + +import java.util.logging.Logger; + +import javax.net.ssl.SSLProtocolException; + +class RecordInput +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG_RECORD_LAYER = true; + private static final Logger logger = SystemLogger.SYSTEM; + + private byte[] fragment; + private int index; + private ContentType type; + + private final DataInputStream in; + private Session session; + + // Constructor. + // ------------------------------------------------------------------------- + + RecordInput (final InputStream in, final Session session) + { + this.in = new DataInputStream (in); + this.session = session; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + synchronized int available (ContentType type) throws IOException + { + if (fragment == null) + { + readRecord (); + } + if (type != this.type) + { + return 0; + } + return fragment.length - index; + } + + void setSession (Session session) + { + this.session = session; + } + + synchronized int read (byte[] buf, int off, int len, ContentType type) + throws IOException + { + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException ("size=" + buf.length + + " off=" + off + " len=" + len); + } + if (fragment == null || index >= fragment.length) + { + readRecord (); + } + if (type != this.type) + { + return 0; + } + len = Math.min (len, fragment.length - index); + System.arraycopy (fragment, index, buf, off, len); + index += len; + return len; + } + + boolean pollClose () throws IOException + { + if (fragment == null || index >= fragment.length) + { + try + { + readRecord(); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert(); + if (alert.getDescription() == Alert.Description.CLOSE_NOTIFY) + { + return true; + } + throw ae; + } + } + return false; + } + + private void readRecord() throws IOException + { + type = ContentType.read (in); + if ((type.getValue() & 0x80) != 0 || (type.getValue() & 0x40) != 0) + { + in.read(); + if ((type.getValue() & 0x40) != 0) + { + in.read(); + } + type = ContentType.read(in); + if (type != ContentType.CLIENT_HELLO_V2) + { + throw new SSLProtocolException("unsupported V2 message"); + } + type = ContentType.HANDSHAKE; + // Record this message, and re-present it as a normal handshake + // layer message. ClientHello will handle the real parsing. + ByteArrayOutputStream buffer = new ByteArrayOutputStream (256); + buffer.write(1); // The type we just read. + RecordingInputStream in2 = new RecordingInputStream (in, buffer); + ProtocolVersion version = ProtocolVersion.read (in2); + if (version.compareTo (ProtocolVersion.SSL_3) < 0) + { + throw new SSLProtocolException("unsupported client version"); + } + int len = (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF); + len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF); + len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF); + int count = 0; + while (count < len) + { + int l = (int) in2.skip(len - count); + if (l > 0) + { + count += l; + } + } + fragment = buffer.toByteArray (); + index = 0; + + // We can't be encrypted/MACed/compressed here, since a V2 message + // will only be sent as the first message, and only by the client. + return; + } + ProtocolVersion v = ProtocolVersion.read (in); + int len = in.readUnsignedShort (); + if (len > session.params.getFragmentLength() + 2048) + { + throw new OverflowException(); + } + fragment = new byte [len]; + in.readFully (fragment); + + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + ">> READ RECORD <<{4}" + + "struct {{4}" + + " type = {0};{4}" + + " version = {1};{4}" + + " length = {2};{4}" + + "{3}{4}" + + "} TLSCiphertext;", new Object[] + { + type, v, new Integer (len), + Util.hexDump (fragment, " "), + SystemProperties.getProperty ("line.separator") + }); + } + + fragment = session.params.decrypt (fragment, v, type); + index = 0; + + if (session.random != null) + session.random.setSeed (fragment); + + if (type == ContentType.ALERT) + { + Alert alert = Alert.read (new ByteArrayInputStream (fragment)); + session.currentAlert = alert; + } + if (session.currentAlert != null) + { + throw new AlertException (session.currentAlert, false); + } + } +} diff --git a/gnu/javax/net/ssl/provider/RecordInputStream.java b/gnu/javax/net/ssl/provider/RecordInputStream.java new file mode 100644 index 000000000..14cf829ac --- /dev/null +++ b/gnu/javax/net/ssl/provider/RecordInputStream.java @@ -0,0 +1,106 @@ +/* RecordInputStream.java -- record layer input stream interface. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; +import java.io.InputStream; + +class RecordInputStream extends InputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** + * The record input instance. + */ + private final RecordInput in; + + /** + * The content type this stream is reading. + */ + private final ContentType type; + + // Constructor. + // ------------------------------------------------------------------------- + + RecordInputStream (RecordInput in, ContentType type) + { + this.in = in; + this.type = type; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int available () throws IOException + { + return in.available (type); + } + + public int read () throws IOException + { + byte[] b = new byte[1]; + int ret; + while ((ret = read (b)) != 1) + { + if (ret == -1) + { + return -1; + } + Thread.yield (); + } + return b[0] & 0xFF; + } + + public int read (byte[] buf) throws IOException + { + return read (buf, 0, buf.length); + } + + public int read (byte[] buf, int off, int len) throws IOException + { + return in.read (buf, off, len, type); + } + + public String toString () + { + return RecordInputStream.class.getName () + " [ type=" + type + " ]"; + } +} diff --git a/gnu/javax/net/ssl/provider/RecordOutputStream.java b/gnu/javax/net/ssl/provider/RecordOutputStream.java new file mode 100644 index 000000000..3bf228f2d --- /dev/null +++ b/gnu/javax/net/ssl/provider/RecordOutputStream.java @@ -0,0 +1,189 @@ +/* RecordOutputStream.java -- record layer output. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import gnu.classpath.SystemProperties; +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; + +import java.util.logging.Logger; + +/** + * An output stream for writing data to the record layer. All data written + * to this stream (through any of the write methods) is immediately sent + * as a full record, so it is advisable to write large arrays to the stream + * instead of one byte at a time (alternatively, a {@link + * java.io.BufferedOutputStream} can be used). + */ +class RecordOutputStream extends FilterOutputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG_RECORD_LAYER = true; + private static final Logger logger = SystemLogger.SYSTEM; + + /** + * The content type of this output stream. + */ + private final ContentType type; + + /** + * The security parameters. + */ + private final SecurityParameters params; + + private final boolean emitEmpty; + + private static final byte[] ZERO = new byte[0]; + + // Constructor. + // ------------------------------------------------------------------------- + + RecordOutputStream (final OutputStream out, final ContentType type, + final SecurityParameters params) + { + super (out); + this.type = type; + this.params = params; + String empty = Util.getSecurityProperty ("jessie.emit.empty.records"); + if (empty == null) + { + // IE panics if it gets an empty record; so, leave this false + // for the default. + empty = "false"; + } + emitEmpty = Boolean.valueOf (empty).booleanValue () && + type == ContentType.APPLICATION_DATA; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write (int b) throws IOException + { + write (new byte[] { (byte) b }); + } + + public void write (byte[] buf) throws IOException + { + write (buf, 0, buf.length); + } + + public void write (byte[] buf, int off, int len) throws IOException + { + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException ("size=" + buf.length + + " off=" + off + " len=" + len); + } + + int count = 0; + int len2 = 0; + do + { + if (emitEmpty) + { + byte[] fragment = params.encrypt (ZERO, 0, 0, type); + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + ">> WRITING RECORD <<{4}" + + "struct {{4}" + + " type = {0};{4}" + + " version = {1};{4}" + + " length = {2};{4}" + + "{3}{4}" + + "} TLSCiphertext;", new Object[] + { + type, params.getVersion (), new Integer (fragment.length), + Util.hexDump (fragment, " "), + SystemProperties.getProperty ("line.separator") + }); + } + out.write (type.getValue()); + params.getVersion().write (out); + out.write ((fragment.length >>> 8) & 0xFF); + out.write ( fragment.length & 0xFF); + out.write (fragment); + out.flush (); + } + len2 = Math.min (len - count, params.getFragmentLength()); + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + "writing chunk size={0}", new Integer (len2)); + } + synchronized (out) + { + byte[] fragment = params.encrypt (buf, off + count, len2, type); + if (DEBUG_RECORD_LAYER) + { + logger.log (Component.SSL_RECORD_LAYER, + ">> WRITING RECORD <<{4}" + + "struct {{4}" + + " type = {0};{4}" + + " version = {1};{4}" + + " length = {2};{4}" + + "{3}{4}" + + "} TLSCiphertext;", new Object[] + { + type, params.getVersion (), new Integer (fragment.length), + Util.hexDump (fragment, " "), + SystemProperties.getProperty ("line.separator") + }); + } + out.write (type.getValue()); + params.getVersion().write (out); + out.write ((fragment.length >>> 8) & 0xFF); + out.write ( fragment.length & 0xFF); + out.write (fragment); + out.flush (); + } + count += len2; + } + while (count < len); + } +} diff --git a/gnu/javax/net/ssl/provider/RecordingInputStream.java b/gnu/javax/net/ssl/provider/RecordingInputStream.java new file mode 100644 index 000000000..d81b652d5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/RecordingInputStream.java @@ -0,0 +1,131 @@ +/* RecordingInputStream.java -- Input stream that records data. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * A filter input stream that records every byte read from the underlying + * input stream. This class is useful for protocols that require portions + * of the communication to be saved, such as the handshake and key + * derivation in SSL. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +class RecordingInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected ByteArrayOutputStream sink; + + // Constructors. + // ------------------------------------------------------------------------- + + RecordingInputStream(InputStream in) + { + this(in, new ByteArrayOutputStream()); + } + + RecordingInputStream(InputStream in, ByteArrayOutputStream sink) + { + super(in); + this.sink = sink; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public synchronized int read() throws IOException + { + int i = in.read(); + sink.write(i); + return i; + } + + public synchronized int read(byte[] buf, int off, int len) throws IOException + { + int l = in.read(buf, off, len); + sink.write(buf, off, l); + return l; + } + + public synchronized int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + public synchronized long skip(long len) throws IOException + { + long l = 0; + int i = 0; + byte[] buf = new byte[1024]; + while (l < len) + { + i = read(buf, 0, (int) Math.min((long) buf.length, len - l)); + if (i == -1) + break; + l += i; + } + return l; + } + + /** + * Returns all bytes recorded after this instance was created, or the last + * call to {@link resetSink()}. + * + * @return The recorded bytes. + */ + byte[] getBytes() + { + return sink.toByteArray(); + } + + /** + * Clears the recording buffer off all previously-recorded bytes. + */ + void resetSink() + { + sink.reset(); + } +} diff --git a/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java b/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java new file mode 100644 index 000000000..5822afe05 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java @@ -0,0 +1,225 @@ +/* SRPTrustManagerFactory.java -- trust manager for SRP. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; +import java.math.BigInteger; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.Security; + +import java.util.HashMap; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactorySpi; + +import gnu.java.security.key.IKeyPairGenerator; +import gnu.javax.crypto.key.srp6.SRPKeyPairGenerator; +import gnu.javax.crypto.sasl.srp.PasswordFile; +import gnu.javax.crypto.sasl.srp.SRP; + +import gnu.javax.net.ssl.SRPManagerParameters; +import gnu.javax.net.ssl.SRPTrustManager; + +/** + * This is an implementation of a {@link javax.net.ssl.TrustManagerFactory} + * engine for the ``SRP'' algorithm. You must initialize instances of this + * algorithm with {@link SRPManagerParameters}. + */ +public class SRPTrustManagerFactory extends TrustManagerFactorySpi +{ + + // Field. + // ------------------------------------------------------------------------- + + private Manager current; + + // Constructor. + // ------------------------------------------------------------------------- + + public SRPTrustManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected TrustManager[] engineGetTrustManagers() + { + if (current == null) + throw new IllegalStateException("not initialized"); + return new TrustManager[] { current }; + } + + protected void engineInit(KeyStore ks) + { + throw new IllegalArgumentException("only accepts SRPManagerParameters"); + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params == null) + { + try + { + String srpPasswd = Util.getSecurityProperty("jessie.srp.password.file"); + if (srpPasswd == null) + { + current = new Manager(new PasswordFile()); + return; + } + String srpPasswd2 = Util.getSecurityProperty("jessie.srp.password.file2"); + if (srpPasswd2 == null) + srpPasswd2 = srpPasswd + "2"; + String srpConfig = Util.getSecurityProperty("jessie.srp.config"); + if (srpConfig == null) + srpConfig = srpPasswd + ".conf"; + current = new Manager(new PasswordFile(srpPasswd, srpPasswd2, srpConfig)); + return; + } + catch (IOException ioe) + { + throw new InvalidAlgorithmParameterException("default initialization failed: " + + ioe.toString()); + } + } + if (params instanceof SRPManagerParameters) + { + current = new Manager(((SRPManagerParameters) params).getPasswordFile()); + return; + } + throw new InvalidAlgorithmParameterException(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class Manager implements SRPTrustManager + { + + // Field. + // ----------------------------------------------------------------------- + + private final PasswordFile file; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(PasswordFile file) + { + this.file = file; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public boolean contains(String user) + { + try + { + return file.contains(user); + } + catch (IOException ioe) { } + return false; + } + + public KeyPair getKeyPair(String user) + { + try + { + if (file.contains(user)) + { + SRP srp = SRP.instance("SHA"); + String[] ent = file.lookup(user, "SHA"); + String[] cnf = file.lookupConfig(ent[2]); + BigInteger v, N, g; + v = new BigInteger(1, gnu.java.security.util.Util.fromBase64(ent[0])); + N = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[0])); + g = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[1])); + IKeyPairGenerator kpg = new SRPKeyPairGenerator(); + HashMap attr = new HashMap(); + attr.put(SRPKeyPairGenerator.SHARED_MODULUS, N); + attr.put(SRPKeyPairGenerator.GENERATOR, g); + attr.put(SRPKeyPairGenerator.USER_VERIFIER, v); + kpg.setup(attr); + return kpg.generate(); + } + } + catch (IOException ioe) { } + return null; + } + + public byte[] getSalt(String user) + { + try + { + if (file.contains(user)) + { + return gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[1]); + } + } + catch (IOException ioe) { } + return null; + } + + public BigInteger getVerifier(String user) + { + try + { + if (file.contains(user)) + { + return new BigInteger(1, + gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[0])); + } + } + catch (IOException ioe) { } + return null; + } + + public PasswordFile getPasswordFile() + { + return file; + } + } +} diff --git a/gnu/javax/net/ssl/provider/SSLHMac.java b/gnu/javax/net/ssl/provider/SSLHMac.java new file mode 100644 index 000000000..002b3077f --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLHMac.java @@ -0,0 +1,158 @@ +/* SSLHMac.java -- SSLv3's MAC algorithm. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.util.Arrays; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mac.IMac; + +/** + * The MAC function in SSLv3. This mac is defined as: + * + *
    + * hash(MAC_write_secret, pad_2 +
    + *      hash(MAC_write_secret + pad_1 + data));
    + * + *

    hash is e.g. MD5 or SHA-1, pad_1 is the value + * 0x36 48 times for MD5 and 40 times for SHA-1, and pad_2 is + * the value 0x5c repeated similarly. + */ +class SSLHMac implements IMac, Cloneable +{ + + // Fields. + // ------------------------------------------------------------------------- + + static final byte PAD1 = 0x36; + static final byte PAD2 = 0x5c; + + protected IMessageDigest md; + protected byte[] key; + protected final byte[] pad1, pad2; + + // Constructors. + // ------------------------------------------------------------------------- + + SSLHMac(String mdName) + { + super(); + this.md = HashFactory.getInstance(mdName); + if (mdName.equalsIgnoreCase("MD5")) + { + pad1 = new byte[48]; + pad2 = new byte[48]; + } + else + { + pad1 = new byte[40]; + pad2 = new byte[40]; + } + Arrays.fill(pad1, PAD1); + Arrays.fill(pad2, PAD2); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException cnse) + { + throw new Error(); + } + } + + public String name() + { + return "SSLHMac-" + md.name(); + } + + public int macSize() + { + return md.hashSize(); + } + + public void init(Map attributes) + { + key = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (key == null) + throw new NullPointerException(); + reset(); + } + + public void reset() + { + md.reset(); + md.update(key, 0, key.length); + md.update(pad1, 0, pad1.length); + } + + public byte[] digest() + { + byte[] h1 = md.digest(); + md.update(key, 0, key.length); + md.update(pad2, 0, pad2.length); + md.update(h1, 0, h1.length); + byte[] result = md.digest(); + reset(); + return result; + } + + public void update(byte b) + { + md.update(b); + } + + public void update(byte[] buf, int off, int len) + { + md.update(buf, off, len); + } + + public boolean selfTest() + { + return true; // XXX + } +} diff --git a/gnu/javax/net/ssl/provider/SSLRSASignature.java b/gnu/javax/net/ssl/provider/SSLRSASignature.java new file mode 100644 index 000000000..2f8c6cfe6 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLRSASignature.java @@ -0,0 +1,235 @@ +/* SSLRSASignature.java -- SSL's RSA signature algorithm. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.math.BigInteger; + +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.Arrays; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.ISignature; +import gnu.java.security.sig.rsa.RSA; + +/** + * The RSA signature algorithm as used in the SSL protocol. Note that this + * is different from the RSA signature used to verify certificates. + * + *

    This signature scheme works as follows:

    + * + *

    digitally-signed struct {
    + *     opaque md5_hash[16];
    + *     opaque sha_hash[20];
    + * }

    + * + *

    Where a digitally-signed struct is RSA-encrypted with + * block type 0 or 1 according to PKCS #1, version 1.5.

    + */ +final class SSLRSASignature implements ISignature +{ + + // Fields. + // ------------------------------------------------------------------------- + + private RSAPublicKey pubkey; + private RSAPrivateKey privkey; + private final IMessageDigest md5, sha; + private boolean initVerify = false, initSign = false; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLRSASignature() + { + this(HashFactory.getInstance("MD5"), HashFactory.getInstance("SHA-1")); + } + + SSLRSASignature(IMessageDigest md5, IMessageDigest sha) + { + this.md5 = md5; + this.sha = sha; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String name() + { + return "RSA/SSL"; + } + + public void setupVerify(Map attrib) + { + PublicKey key = (PublicKey) attrib.get(VERIFIER_KEY); + if (key == null) + { + if (initSign) + { + return; // re-use. + } + throw new IllegalArgumentException("no key supplied"); + } + if (!(key instanceof RSAPublicKey)) + { + throw new IllegalArgumentException("not an RSA key"); + } + pubkey = (RSAPublicKey) key; + privkey = null; + initSign = false; + initVerify = true; + } + + public void setupSign(Map attrib) + { + PrivateKey key = (PrivateKey) attrib.get(SIGNER_KEY); + if (key == null) + { + if (initVerify) + { + return; // re-use. + } + throw new IllegalArgumentException("no key supplied"); + } + if (!(key instanceof RSAPrivateKey)) + { + throw new IllegalArgumentException("not an RSA key"); + } + privkey = (RSAPrivateKey) key; + pubkey = null; + initVerify = false; + initSign = true; + } + + public void update(byte b) + { + if (!initVerify && !initSign) + { + throw new IllegalStateException(); + } + md5.update(b); + sha.update(b); + } + + public void update(byte[] buf, int off, int len) + { + if (!initVerify && !initSign) + { + throw new IllegalStateException(); + } + md5.update(buf, off, len); + sha.update(buf, off, len); + } + + public Object sign() + { + if (!initSign) + { + throw new IllegalStateException(); + } + // Pad the hash results with RSA block type 1. + final int k = (privkey.getModulus().bitLength() + 7) >>> 3; + final byte[] d = Util.concat(md5.digest(), sha.digest()); + if (k - 11 < d.length) + { + throw new IllegalArgumentException("message too long"); + } + final byte[] eb = new byte[k]; + eb[0] = 0x00; + eb[1] = 0x01; + for (int i = 2; i < k - d.length - 1; i++) + { + eb[i] = (byte) 0xFF; + } + System.arraycopy(d, 0, eb, k - d.length, d.length); + BigInteger EB = new BigInteger(eb); + + // Private-key encrypt the padded hashes. + BigInteger EM = RSA.sign(privkey, EB); + return Util.trim(EM); + } + + public boolean verify(Object signature) + { + if (!initVerify) + { + throw new IllegalStateException(); + } + // Public-key decrypt the signature representative. + BigInteger EM = new BigInteger(1, (byte[]) signature); + BigInteger EB = RSA.verify(pubkey, EM); + + // Unpad the decrypted message. + int i = 0; + final byte[] eb = EB.toByteArray(); + if (eb[0] == 0x00) + { + for (i = 0; i < eb.length && eb[i] == 0x00; i++); + } + else if (eb[0] == 0x01) + { + for (i = 1; i < eb.length && eb[i] != 0x00; i++) + { + if (eb[i] != (byte) 0xFF) + { + throw new IllegalArgumentException("bad padding"); + } + } + i++; + } + else + { + throw new IllegalArgumentException("decryption failed"); + } + byte[] d1 = Util.trim(eb, i, eb.length - i); + byte[] d2 = Util.concat(md5.digest(), sha.digest()); + return Arrays.equals(d1, d2); + } + + public Object clone() + { + throw new UnsupportedOperationException(); + } +} diff --git a/gnu/javax/net/ssl/provider/SSLRandom.java b/gnu/javax/net/ssl/provider/SSLRandom.java new file mode 100644 index 000000000..0b28f1044 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLRandom.java @@ -0,0 +1,165 @@ +/* SSLRandom.java -- SSLv3 pseudo-random function. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.util.Map; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +class SSLRandom implements IRandom +{ + + // Fields. + // ------------------------------------------------------------------------- + + static final String SECRET = "jessie.sslprng.secret"; + static final String SEED = "jessie.sslprng.seed"; + + private final IMessageDigest md5, sha; + private byte[] secret; + private byte[] buffer; + private byte pad; + private byte[] seed; + private int idx; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLRandom() + { + md5 = HashFactory.getInstance("MD5"); + sha = HashFactory.getInstance("SHA-1"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void init(Map attrib) + { + secret = (byte[]) attrib.get(SECRET); + seed = (byte[]) attrib.get(SEED); + + if (secret == null || seed == null) + throw new NullPointerException(); + + pad = (byte) 'A'; + try { buffer = nextBlock(); } + catch (LimitReachedException cantHappen) { } + } + + public String name() + { + return "SSLRandom"; + } + + public Object clone() + { + throw new UnsupportedOperationException(); + } + + public byte nextByte() throws LimitReachedException + { + if (buffer == null) + throw new IllegalStateException(); + if (idx >= buffer.length) + buffer = nextBlock(); + return buffer[idx++]; + } + + public void nextBytes(byte[] buf, int off, int len) + throws LimitReachedException + { + if (buffer == null) + throw new IllegalStateException(); + if (buf == null) + throw new NullPointerException(); + if (off < 0 || len < 0 || off+len > buf.length) + throw new IndexOutOfBoundsException(); + int count = 0; + while (count < len) + { + if (idx >= buffer.length) + buffer = nextBlock(); + int l = Math.min(buffer.length-idx, len-count); + System.arraycopy(buffer, idx, buf, off+count, l); + count += l; + idx += l; + } + } + + public boolean selfTest() + { + return true; // XXX + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } + + // Own methods. + // ------------------------------------------------------------------------- + + private byte[] nextBlock() throws LimitReachedException + { + int count = pad - 'A' + 1; + if (count > 26) + throw new LimitReachedException(); + for (int i = 0; i < count; i++) + sha.update(pad); + sha.update(secret, 0, secret.length); + sha.update(seed, 0, seed.length); + byte[] b = sha.digest(); + md5.update(secret, 0, secret.length); + md5.update(b, 0, b.length); + idx = 0; + pad++; + return md5.digest(); + } +} diff --git a/gnu/javax/net/ssl/provider/SSLServerSocket.java b/gnu/javax/net/ssl/provider/SSLServerSocket.java new file mode 100644 index 000000000..ee96b8d1b --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLServerSocket.java @@ -0,0 +1,283 @@ +/* SSLServerSocket.java -- SSL server socket. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; + +import java.net.InetAddress; +import java.net.Socket; + +import java.security.SecureRandom; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.SRPTrustManager; + +class SSLServerSocket extends javax.net.ssl.SSLServerSocket +{ + + // Fields. + // ------------------------------------------------------------------------- + + private SessionContext sessions; + private SortedSet enabledProtocols = new TreeSet(SSLSocket.supportedProtocols); + private List enabledSuites = new ArrayList(SSLSocket.supportedSuites); + private boolean clientMode = false; + private boolean needClientAuth = false; + private boolean wantClientAuth = false; + private boolean createSessions = true; + private SRPTrustManager srpTrustManager; + private X509TrustManager trustManager; + private X509KeyManager keyManager; + private SecureRandom random; + + // Constructors. + // ------------------------------------------------------------------------- + + SSLServerSocket() throws IOException + { + super(); + } + + SSLServerSocket(int port) throws IOException + { + super(port); + } + + SSLServerSocket(int port, int backlog) throws IOException + { + super(port, backlog); + } + + SSLServerSocket(int port, int backlog, InetAddress address) + throws IOException + { + super(port, backlog, address); + } + + // SSL methods. + // ------------------------------------------------------------------------- + + public String[] getSupportedCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + public String[] getEnabledCipherSuites() + { + synchronized (enabledSuites) + { + String[] s = new String[enabledSuites.size()]; + int i = 0; + for (Iterator it = enabledSuites.iterator(); it.hasNext(); ) + s[i++] = it.next().toString(); + return s; + } + } + + public void setEnabledCipherSuites(String[] suites) + { + if (suites == null || suites.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < suites.length; i++) + if (CipherSuite.forName(suites[i]) == null) + throw new IllegalArgumentException("unsupported suite: " + + suites[i]); + synchronized (enabledSuites) + { + enabledSuites.clear(); + for (int i = 0; i < suites.length; i++) + { + CipherSuite suite = CipherSuite.forName(suites[i]); + if (!enabledSuites.contains(suite)) + enabledSuites.add(suite); + } + } + } + + public String[] getSupportedProtocols() + { + return new String[] { "SSLv3", "TLSv1", "TLSv1.1" }; + } + + public String[] getEnabledProtocols() + { + synchronized (enabledProtocols) + { + String[] s = new String[enabledProtocols.size()]; + int i = 0; + for (Iterator it = enabledProtocols.iterator(); it.hasNext(); ) + s[i++] = it.next().toString(); + return s; + } + } + + public void setEnabledProtocols(String[] protocols) + { + if (protocols == null || protocols.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < protocols.length; i++) + { + if (!(protocols[i].equalsIgnoreCase("SSLv3") || + protocols[i].equalsIgnoreCase("TLSv1") || + protocols[i].equalsIgnoreCase("TLSv1.1"))) + { + throw new + IllegalArgumentException("unsupported protocol: " + + protocols[i]); + } + } + synchronized (enabledProtocols) + { + enabledProtocols.clear(); + for (int i = 0; i < protocols.length; i++) + { + if (protocols[i].equalsIgnoreCase("SSLv3")) + enabledProtocols.add(ProtocolVersion.SSL_3); + else if (protocols[i].equalsIgnoreCase("TLSv1")) + enabledProtocols.add(ProtocolVersion.TLS_1); + else + enabledProtocols.add(ProtocolVersion.TLS_1_1); + } + } + } + + public void setUseClientMode(boolean clientMode) + { + this.clientMode = clientMode; + } + + public boolean getUseClientMode() + { + return clientMode; + } + + public void setNeedClientAuth(boolean needClientAuth) + { + this.needClientAuth = needClientAuth; + } + + public boolean getNeedClientAuth() + { + return needClientAuth; + } + + public void setWantClientAuth(boolean wantClientAuth) + { + this.wantClientAuth = wantClientAuth; + } + + public boolean getWantClientAuth() + { + return wantClientAuth; + } + + // I misspelled this method in javax.net.SSLServerSocket, and that version + // made it into kaffe 1.1.4. + public void setEnabledSessionCreation(boolean createSessions) + { + setEnableSessionCreation(createSessions); + } + + public void setEnableSessionCreation(boolean createSessions) + { + this.createSessions = createSessions; + } + + public boolean getEnableSessionCreation() + { + return createSessions; + } + + // Socket methods. + // ------------------------------------------------------------------------- + + public Socket accept() throws IOException + { + SSLSocket socket = new SSLSocket(); + implAccept(socket); + socket.setUseClientMode(clientMode); + socket.setNeedClientAuth(needClientAuth); + socket.setWantClientAuth(wantClientAuth); + socket.setEnableSessionCreation(createSessions); + socket.setSessionContext(sessions); + socket.setEnabledCipherSuites(new ArrayList(enabledSuites)); + socket.setEnabledProtocols(new TreeSet(enabledProtocols)); + socket.setSRPTrustManager(srpTrustManager); + socket.setTrustManager(trustManager); + socket.setKeyManager(keyManager); + socket.setRandom(random); + return socket; + } + + // Package methods. + // ------------------------------------------------------------------------- + + void setSessionContext(SessionContext sessions) + { + this.sessions = sessions; + } + + void setKeyManager(X509KeyManager keyManager) + { + this.keyManager = keyManager; + } + + void setTrustManager(X509TrustManager trustManager) + { + this.trustManager = trustManager; + } + + void setSRPTrustManager(SRPTrustManager srpTrustManager) + { + this.srpTrustManager = srpTrustManager; + } + + void setRandom(SecureRandom random) + { + this.random = random; + } +} diff --git a/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java b/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java new file mode 100644 index 000000000..72fb512c5 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java @@ -0,0 +1,136 @@ +/* SSLServerSocketFactory.java -- factory for SSL server sockets. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; + +import java.net.InetAddress; +import java.net.ServerSocket; + +import java.security.SecureRandom; + +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.SRPTrustManager; + +class SSLServerSocketFactory extends javax.net.ssl.SSLServerSocketFactory +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final SessionContext sessions; + private final X509KeyManager keyManager; + private final X509TrustManager trustManager; + private final SRPTrustManager srpTrustManager; + private final SecureRandom random; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLServerSocketFactory(X509TrustManager trustManager, + SRPTrustManager srpTrustManager, + X509KeyManager keyManager, + SecureRandom random, + SessionContext sessions) + { + super(); + this.trustManager = trustManager; + this.srpTrustManager = srpTrustManager; + this.keyManager = keyManager; + this.random = random; + this.sessions = sessions; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String[] getDefaultCipherSuites() + { + return getSupportedCipherSuites(); + } + + public String[] getSupportedCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + public ServerSocket createServerSocket() throws IOException + { + SSLServerSocket socket = new SSLServerSocket(); + setup(socket); + return socket; + } + + public ServerSocket createServerSocket(int port) throws IOException + { + SSLServerSocket socket = new SSLServerSocket(port); + setup(socket); + return socket; + } + + public ServerSocket createServerSocket(int port, int backlog) + throws IOException + { + SSLServerSocket socket = new SSLServerSocket(port, backlog); + setup(socket); + return socket; + } + + public ServerSocket createServerSocket(int port, int backlog, InetAddress addr) + throws IOException + { + SSLServerSocket socket = new SSLServerSocket(port, backlog, addr); + setup(socket); + return socket; + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void setup(SSLServerSocket socket) + { + socket.setSessionContext(sessions); + socket.setKeyManager(keyManager); + socket.setTrustManager(trustManager); + socket.setSRPTrustManager(srpTrustManager); + socket.setRandom(random); + } +} diff --git a/gnu/javax/net/ssl/provider/SSLSocket.java b/gnu/javax/net/ssl/provider/SSLSocket.java new file mode 100644 index 000000000..a564659c0 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLSocket.java @@ -0,0 +1,3530 @@ +/* SSLSocket.java -- the SSL socket class. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.BufferedOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + +import java.math.BigInteger; + +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; + +import java.nio.channels.SocketChannel; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import java.util.logging.Logger; + +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLProtocolException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import gnu.java.security.Registry; +import gnu.javax.security.auth.callback.DefaultCallbackHandler; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.key.IKeyAgreementParty; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.IncomingMessage; +import gnu.javax.crypto.key.dh.DiffieHellmanKeyAgreement; +import gnu.javax.crypto.key.dh.ElGamalKeyAgreement; +import gnu.javax.crypto.key.dh.GnuDHPrivateKey; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; +import gnu.javax.crypto.key.srp6.SRPPrivateKey; +import gnu.javax.crypto.key.srp6.SRPPublicKey; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.prng.ARCFour; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider; +import gnu.javax.crypto.sasl.srp.SRPRegistry; +import gnu.java.security.sig.ISignature; +import gnu.java.security.sig.SignatureFactory; +import gnu.java.security.sig.dss.DSSSignature; +import gnu.java.security.sig.rsa.EME_PKCS1_V1_5; +import gnu.java.security.sig.rsa.RSA; + +import gnu.javax.net.ssl.SRPTrustManager; + +/** + * This is the core of the Jessie SSL implementation; it implements the {@link + * javax.net.ssl.SSLSocket} for normal and "wrapped" sockets, and handles all + * protocols implemented by this library. + */ +final class SSLSocket extends javax.net.ssl.SSLSocket +{ + + // This class is almost unbearably large and complex, but is laid out + // as follows: + // + // 1. Fields. + // 2. Constructors. + // 3. SSLSocket methods. These are the public methods defined in + // javax.net.ssl.SSLSocket. + // 4. Socket methods. These override the public methods of java.net.Socket, + // and delegate the method call to either the underlying socket if this is + // a wrapped socket, or to the superclass. + // 5. Package-private methods that various pieces of Jessie use. + // 6. Private methods. These compose the SSL handshake. + // + // Each part is preceeded by a form feed. + + // Constants and fields. + // ------------------------------------------------------------------------- + + // Debuggery. + private static final boolean DEBUG_HANDSHAKE_LAYER = true; + private static final boolean DEBUG_KEY_EXCHANGE = false; + private static final Logger logger = SystemLogger.SYSTEM; + + // Fields for using this class as a wrapped socket. + private Socket underlyingSocket; + private int underlyingPort; + private boolean autoClose; + + // Cryptography fields. + SessionContext sessionContext; + Session session; + LinkedList handshakeListeners; + private boolean clientMode, wantClientAuth, needClientAuth, createSessions; + private boolean handshakeDone; + + // I/O fields. + private String remoteHost; + private InputStream socketIn; + private OutputStream socketOut; + private InputStream applicationIn; + private OutputStream applicationOut; + private InputStream handshakeIn; + private OutputStream handshakeOut; +// private ThreadGroup recordLayer; + RecordInput recordInput; +// RecordOutput recordOutput; + private long handshakeTime; + + private SocketChannel channel; + + static SortedSet supportedProtocols = new TreeSet(); + static List supportedSuites = new ArrayList(30); + + // Static initializer. + // ------------------------------------------------------------------------- + + static + { + //supportedProtocols.add(ProtocolVersion.TLS_1_1); + supportedProtocols.add(ProtocolVersion.TLS_1); + supportedProtocols.add(ProtocolVersion.SSL_3); + + // These are in preference order. It's my preference order, but I'm not + // a total idiot. + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_MD5); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_DES_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5); + supportedSuites.add(CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_MD5); + supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_SHA); + } + + // Constructors. + // ------------------------------------------------------------------------- + + SSLSocket(Socket socket, String host, int port, boolean autoClose) + throws IOException + { + underlyingSocket = socket; + remoteHost = host; + underlyingPort = port; + this.autoClose = autoClose; + initialize(); + } + + SSLSocket (Socket socket, SocketChannel channel) throws IOException + { + underlyingSocket = socket; + this.channel = channel; + initialize (); + } + + SSLSocket() throws IOException + { + super(); + initialize(); + } + + SSLSocket(InetAddress addr, int port) throws IOException + { + super(addr, port); + initialize(); + remoteHost = addr.getHostName(); + if (remoteHost == null) + { + remoteHost = addr.getHostAddress(); + } + } + + SSLSocket(InetAddress addr, int port, InetAddress laddr, int lport) + throws IOException + { + super(addr, port, laddr, lport); + initialize(); + remoteHost = addr.getHostName(); + if (remoteHost == null) + remoteHost = addr.getHostAddress(); + } + + SSLSocket(String host, int port) throws IOException + { + super(host, port); + initialize(); + remoteHost = host; + } + + SSLSocket(String host, int port, InetAddress laddr, int lport) + throws IOException + { + super(host, port, laddr, lport); + initialize(); + remoteHost = host; + } + + private void initialize() + { + session = new Session(); + session.enabledSuites = new ArrayList(supportedSuites); + session.enabledProtocols = new TreeSet(supportedProtocols); + session.protocol = ProtocolVersion.TLS_1; + session.params.setVersion (ProtocolVersion.TLS_1); + handshakeListeners = new LinkedList(); + handshakeDone = false; + } + + // SSL methods. + // ------------------------------------------------------------------------- + + public void addHandshakeCompletedListener(HandshakeCompletedListener l) + { + synchronized (handshakeListeners) + { + if (l == null) + throw new NullPointerException(); + if (!handshakeListeners.contains(l)) + handshakeListeners.add(l); + } + } + + public void removeHandshakeCompletedListener(HandshakeCompletedListener l) + { + synchronized (handshakeListeners) + { + handshakeListeners.remove(l); + } + } + + public String[] getEnabledProtocols() + { + synchronized (session.enabledProtocols) + { + try + { + return (String[]) Util.transform(session.enabledProtocols.toArray(), + String.class, "toString", null); + } + catch (Exception x) + { + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + } + } + + public void setEnabledProtocols(String[] protocols) + { + if (protocols == null || protocols.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < protocols.length; i++) + { + if (!(protocols[i].equalsIgnoreCase("SSLv3") || + protocols[i].equalsIgnoreCase("TLSv1") || + protocols[i].equalsIgnoreCase("TLSv1.1"))) + { + throw new + IllegalArgumentException("unsupported protocol: " + + protocols[i]); + } + } + synchronized (session.enabledProtocols) + { + session.enabledProtocols.clear(); + for (int i = 0; i < protocols.length; i++) + { + if (protocols[i].equalsIgnoreCase("SSLv3")) + { + session.enabledProtocols.add(ProtocolVersion.SSL_3); + } + else if (protocols[i].equalsIgnoreCase("TLSv1")) + { + session.enabledProtocols.add(ProtocolVersion.TLS_1); + } + else + { + session.enabledProtocols.add(ProtocolVersion.TLS_1_1); + } + } + } + } + + public String[] getSupportedProtocols() + { + return new String[] { /* "TLSv1.1", */ "TLSv1", "SSLv3" }; + } + + public String[] getEnabledCipherSuites() + { + synchronized (session.enabledSuites) + { + try + { + return (String[]) Util.transform(session.enabledSuites.toArray(), + String.class, "toString", null); + } + catch (Exception x) + { + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + } + } + + public void setEnabledCipherSuites(String[] suites) + { + if (suites == null || suites.length == 0) + throw new IllegalArgumentException(); + for (int i = 0; i < suites.length; i++) + if (CipherSuite.forName(suites[i]) == null) + throw new IllegalArgumentException("unsupported suite: " + + suites[i]); + synchronized (session.enabledSuites) + { + session.enabledSuites.clear(); + for (int i = 0; i < suites.length; i++) + { + CipherSuite suite = CipherSuite.forName(suites[i]); + if (!session.enabledSuites.contains(suite)) + { + session.enabledSuites.add(suite); + } + } + } + } + + public String[] getSupportedCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[52]); + } + + public SSLSession getSession() + { + return session; + } + + public boolean getEnableSessionCreation() + { + return createSessions; + } + + public void setEnableSessionCreation(boolean flag) + { + createSessions = flag; + } + + public boolean getNeedClientAuth() + { + return needClientAuth; + } + + public void setNeedClientAuth(boolean flag) + { + needClientAuth = flag; + } + + public boolean getWantClientAuth() + { + return wantClientAuth; + } + + public void setWantClientAuth(boolean flag) + { + wantClientAuth = flag; + } + + public boolean getUseClientMode() + { + return clientMode; + } + + public void setUseClientMode(boolean flag) + { + this.clientMode = flag; + } + + public synchronized void startHandshake() throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "startHandshake called in {0}", + Thread.currentThread()); + handshakeTime = System.currentTimeMillis(); + } + if (handshakeDone) + { + if (clientMode) + { + handshakeDone = false; + doClientHandshake(); + } + else + { + Handshake req = new Handshake(Handshake.Type.HELLO_REQUEST, null); + req.write (handshakeOut, session.protocol); + handshakeOut.flush(); +// recordOutput.setHandshakeAvail(req.write(handshakeOut, session.protocol)); + } + return; + } + if (recordInput == null) + { + setupIO(); + } + if (clientMode) + { + doClientHandshake(); + } + else + { + doServerHandshake(); + } + } + + // Socket methods. + // ------------------------------------------------------------------------- + + public InetAddress getInetAddress() + { + if (underlyingSocket != null) + { + return underlyingSocket.getInetAddress(); + } + else + { + return super.getInetAddress(); + } + } + + public InetAddress getLocalAddress() + { + if (underlyingSocket != null) + { + return underlyingSocket.getLocalAddress(); + } + else + { + return super.getLocalAddress(); + } + } + + public int getPort() + { + if (underlyingSocket != null) + { + return underlyingSocket.getPort(); + } + else + { + return super.getPort(); + } + } + + public int getLocalPort() + { + if (underlyingSocket != null) + { + return underlyingSocket.getLocalPort(); + } + else + { + return super.getLocalPort(); + } + } + + public InputStream getInputStream() throws IOException + { + if (applicationIn == null) + { + setupIO(); + } + return applicationIn; + } + + public OutputStream getOutputStream() throws IOException + { + if (applicationOut == null) + { + setupIO(); + } + return applicationOut; + } + + public void setTcpNoDelay(boolean flag) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setTcpNoDelay(flag); + } + else + { + super.setTcpNoDelay(flag); + } + } + + public boolean getTcpNoDelay() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getTcpNoDelay(); + } + else + { + return super.getTcpNoDelay(); + } + } + + public void setSoLinger(boolean flag, int linger) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setSoLinger(flag, linger); + } + else + { + super.setSoLinger(flag, linger); + } + } + + public int getSoLinger() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getSoLinger(); + } + else + { + return super.getSoLinger(); + } + } + + public void sendUrgentData(int data) throws IOException + { + throw new UnsupportedOperationException("not implemented"); + } + + public void setSoTimeout(int timeout) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setSoTimeout(timeout); + } + else + { + super.setSoTimeout(timeout); + } + } + + public int getSoTimeout() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getSoTimeout(); + } + else + { + return super.getSoTimeout(); + } + } + + public void setSendBufferSize(int size) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setSendBufferSize(size); + } + else + { + super.setSendBufferSize(size); + } + } + + public int getSendBufferSize() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getSendBufferSize(); + } + else + { + return super.getSendBufferSize(); + } + } + + public void setReceiveBufferSize(int size) throws SocketException + { + if (underlyingSocket != null) + { + underlyingSocket.setReceiveBufferSize(size); + } + else + { + super.setReceiveBufferSize(size); + } + } + + public int getReceiveBufferSize() throws SocketException + { + if (underlyingSocket != null) + { + return underlyingSocket.getReceiveBufferSize(); + } + else + { + return super.getReceiveBufferSize(); + } + } + + public synchronized void close() throws IOException + { + if (recordInput == null) + { + if (underlyingSocket != null) + { + if (autoClose) + underlyingSocket.close(); + } + else + super.close(); + return; + } +// while (recordOutput.applicationDataPending()) Thread.yield(); + Alert close = new Alert (Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY); + sendAlert (close); + long wait = System.currentTimeMillis() + 60000L; + while (session.currentAlert == null && !recordInput.pollClose()) + { + + Thread.yield(); + if (wait <= System.currentTimeMillis()) + { + break; + } + } + boolean gotClose = session.currentAlert != null && + session.currentAlert.getDescription() == Alert.Description.CLOSE_NOTIFY; +// recordInput.setRunning(false); +// recordOutput.setRunning(false); +// recordLayer.interrupt(); + recordInput = null; +// recordOutput = null; +// recordLayer = null; + if (underlyingSocket != null) + { + if (autoClose) + underlyingSocket.close(); + } + else + super.close(); + if (!gotClose) + { + session.invalidate(); + throw new SSLException("did not receive close notify"); + } + } + + public String toString() + { + if (underlyingSocket != null) + { + return SSLSocket.class.getName() + " [ " + underlyingSocket + " ]"; + } + else + { + return SSLSocket.class.getName() + " [ " + super.toString() + " ]"; + } + } + + // Configuration insanity begins here. + + public void connect(SocketAddress saddr) throws IOException + { + if (underlyingSocket != null) + { + underlyingSocket.connect(saddr); + } + else + { + super.connect(saddr); + } + } + + public void connect(SocketAddress saddr, int timeout) throws IOException + { + if (underlyingSocket != null) + { + underlyingSocket.connect(saddr, timeout); + } + else + { + super.connect(saddr, timeout); + } + } + + public void bind(SocketAddress saddr) throws IOException + { + if (underlyingSocket != null) + { + underlyingSocket.bind(saddr); + } + else + { + super.bind(saddr); + } + } + + public SocketAddress getLocalSocketAddress() + { + if (underlyingSocket != null) + { + return underlyingSocket.getLocalSocketAddress(); + } + else + { + return super.getLocalSocketAddress(); + } + } + + public SocketChannel getChannel() + { + return channel; + } + + public boolean isBound() + { + if (underlyingSocket != null) + { + return underlyingSocket.isBound(); + } + else + { + return super.isBound(); + } + //throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isClosed() + { + if (underlyingSocket != null) + { + return underlyingSocket.isClosed(); + } + else + { + return super.isClosed(); + } + //throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + //public SocketAddress getRemoteSocketAddress() + //{ + // if (underlyingSocket != null) + // { + // return underlyingSocket.getRemoteSocketAddress(); + // } + // else + // { + // return super.getRemoteSocketAddress(); + // } + //} + + public void setOOBInline(boolean flag) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setOOBInline(flag); + // } + //else + // { + // super.setOOBInline(flag); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean getOOBInline() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getOOBInline(); + // } + //else + // { + // return super.getOOBInline(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void setKeepAlive(boolean flag) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setKeepAlive(flag); + // } + //else + // { + // super.setKeepAlive(flag); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean getKeepAlive() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getKeepAlive(); + // } + //else + // { + // return super.getKeepAlive(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void setTrafficClass(int clazz) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setTrafficClass(clazz); + // } + //else + // { + // super.setTrafficClass(clazz); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public int getTrafficClass() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getTrafficClass(); + // } + //else + // { + // return super.getTrafficClass(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void setReuseAddress(boolean flag) throws SocketException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.setReuseAddress(flag); + // } + //else + // { + // super.setReuseAddress(flag); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean getReuseAddress() throws SocketException + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.getReuseAddress(); + // } + //else + // { + // return super.getReuseAddress(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void shutdownInput() throws IOException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.shutdownInput(); + // } + //else + // { + // super.shutdownInput(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public void shutdownOutput() throws IOException + { + //if (underlyingSocket != null) + // { + // underlyingSocket.shutdownOutput(); + // } + //else + // { + // super.shutdownOutput(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isConnected() + { + if (underlyingSocket != null) + { + return underlyingSocket.isConnected(); + } + else + { + return super.isConnected(); + } + //throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isInputShutdown() + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.isInputShutdown(); + // } + //else + // { + // return super.isInputShutdown(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + public boolean isOutputShutdown() + { + //if (underlyingSocket != null) + // { + // return underlyingSocket.isOutputShutdown(); + // } + //else + // { + // return super.isOutputShutdown(); + // } + throw new UnsupportedOperationException("1.4 methods not enabled"); + } + + protected void finalize() + { + if (session.currentAlert == null) + { + try + { + close(); + } + catch (Exception ignore) { } + } + } + + // Package methods. + // ------------------------------------------------------------------------- + + void setSessionContext(SessionContext sessionContext) + { + this.sessionContext = sessionContext; + } + + void setEnabledCipherSuites(List suites) + { + session.enabledSuites = suites; + } + + void setEnabledProtocols(SortedSet protocols) + { + session.enabledProtocols = protocols; + } + + void setSRPTrustManager(SRPTrustManager srpTrustManager) + { + session.srpTrustManager = srpTrustManager; + } + + void setTrustManager(X509TrustManager trustManager) + { + session.trustManager = trustManager; + } + + void setKeyManager(X509KeyManager keyManager) + { + session.keyManager = keyManager; + } + + void setRandom(SecureRandom random) + { + session.random = random; + } + + void sendAlert (Alert alert) throws IOException + { + RecordOutputStream out = + new RecordOutputStream (socketOut, ContentType.ALERT, session.params); + out.write (alert.getEncoded ()); + } + + /** + * Gets the most-recently-received alert message. + * + * @return The alert message. + */ + Alert checkAlert() + { + return session.currentAlert; + } + + synchronized void checkHandshakeDone() throws IOException + { + if (!handshakeDone) + { + startHandshake(); + } + Alert alert = session.currentAlert; + if (alert != null && alert.getLevel() == Alert.Level.FATAL) + { + throw new AlertException(alert, false); + } + if (handshakeIn.available() > 0 && !clientMode) + { + handshakeDone = false; + startHandshake(); + } + } + + // Own methods. + // ------------------------------------------------------------------------- + + private static final byte[] SENDER_CLIENT = + new byte[] { 0x43, 0x4C, 0x4E, 0x54 }; + private static final byte[] SENDER_SERVER = + new byte[] { 0x53, 0x52, 0x56, 0x52 }; + + private void changeCipherSpec () throws IOException + { + RecordOutputStream out = + new RecordOutputStream (socketOut, ContentType.CHANGE_CIPHER_SPEC, session.params); + out.write (1); + } + + private void readChangeCipherSpec () throws IOException + { + RecordInputStream in = + new RecordInputStream (recordInput, ContentType.CHANGE_CIPHER_SPEC); + if (in.read() != 1) + { + throw new SSLProtocolException ("bad change cipher spec message"); + } + } + + /** + * Initializes the application data streams and starts the record layer + * threads. + */ + private synchronized void setupIO() throws IOException + { + if (recordInput != null) + { + return; + } + if (underlyingSocket != null) + { + socketIn = underlyingSocket.getInputStream(); + socketOut = underlyingSocket.getOutputStream(); + } + else + { + socketIn = super.getInputStream(); + socketOut = super.getOutputStream(); + } +// recordLayer = new ThreadGroup("record_layer"); +// recordInput = new RecordInput(in, session, recordLayer); +// recordOutput = new RecordOutput(out, session, recordLayer); +// recordInput.setRecordOutput(recordOutput); +// recordLayer.setDaemon(true); +// recordInput.start(); +// recordOutput.start(); + recordInput = new RecordInput (socketIn, session); + applicationIn = new SSLSocketInputStream( + new RecordInputStream (recordInput, ContentType.APPLICATION_DATA), this); + applicationOut = new SSLSocketOutputStream( + new RecordOutputStream (socketOut, ContentType.APPLICATION_DATA, session.params), this); + handshakeIn = new SSLSocketInputStream( + new RecordInputStream (recordInput, ContentType.HANDSHAKE), this, false); + handshakeOut = new BufferedOutputStream (new SSLSocketOutputStream( + new RecordOutputStream (socketOut, ContentType.HANDSHAKE, session.params), this, false), 8096); + } + + private void handshakeCompleted () + { + handshakeDone = true; + HandshakeCompletedEvent event = new HandshakeCompletedEvent (this, session); + for (Iterator it = handshakeListeners.iterator (); it.hasNext (); ) + { + try + { + ((HandshakeCompletedListener) it.next ()).handshakeCompleted (event); + } + catch (Throwable t) { } + } + if (createSessions) + { + synchronized (session) + { + sessionContext.addSession (session.sessionId, session); + session.access (); + } + } + + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "Handshake finished in {0}", + Thread.currentThread()); + handshakeTime = System.currentTimeMillis() - handshakeTime; + logger.log (Component.SSL_HANDSHAKE, "Elapsed time {0}s", + new Long (handshakeTime / 1000)); + } + } + + /* + * Perform the client handshake. The process looks like this: + * + * ClientHello --> + * ServerHello <-- + * Certificate* <-- + * ServerKeyExchange* <-- + * CertificateRequest* <-- + * ServerHelloDone* <-- + * Certificate* --> + * ClientKeyExchange --> + * CertificateVerify* --> + * [ChangeCipherSpec] --> + * Finished --> + * [ChangeCipherSpec] <-- + * Finished <-- + * + * With --> denoting output and <-- denoting input. * denotes optional + * messages. + * + * Alternatively, this may be an abbreviated handshake if we are resuming + * a session: + * + * ClientHello --> + * ServerHello <-- + * [ChangeCipherSpec] <-- + * Finished <-- + * [ChangeCipherSpec] --> + * Finished --> + */ + private void doClientHandshake() throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "starting client handshake in {0}", + Thread.currentThread()); + } + + IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH); + IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH); + DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha); + DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha); + Session continuedSession = null; + byte[] sessionId = new byte[0]; + List extensions = null; + String user = null; + CertificateType certType = CertificateType.X509; + + // Look through the available sessions to see if an appropriate one is + // available. + for (Enumeration e = sessionContext.getIds(); e.hasMoreElements(); ) + { + byte[] id = (byte[]) e.nextElement(); + continuedSession = (Session) sessionContext.getSession(id); + if (continuedSession == null) + { + continue; + } + if (!session.enabledProtocols.contains(continuedSession.protocol)) + { + continue; + } + if (continuedSession.getPeerHost().equals(remoteHost)) + { + sessionId = id; + break; + } + } + + // If a SRP suite is enabled, ask for a username so we can include it + // with our extensions list. + for (Iterator i = session.enabledSuites.iterator(); i.hasNext(); ) + { + CipherSuite s = (CipherSuite) i.next(); + if (s.getKeyExchange() == "SRP") + { + extensions = new LinkedList(); + user = askUserName(remoteHost); + byte[] b = user.getBytes("UTF-8"); + if (b.length > 255) + { + handshakeFailure(); + throw new SSLException("SRP username too long"); + } + extensions.add(new Extension(Extension.Type.SRP, + Util.concat(new byte[] { (byte) b.length }, b))); + + break; + } + } + + // If the jessie.fragment.length property is set, add the appropriate + // extension to the list. The fragment length is only actually set if + // the server responds with the same extension. + try + { + int flen = Integer.parseInt(Util.getSecurityProperty("jessie.fragment.length")); + byte[] ext = new byte[1]; + if (flen == 512) + ext[0] = 1; + else if (flen == 1024) + ext[0] = 2; + else if (flen == 2048) + ext[0] = 3; + else if (flen == 4096) + ext[0] = 4; + else + throw new NumberFormatException(); + if (extensions == null) + extensions = new LinkedList(); + extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH, ext)); + } + catch (NumberFormatException nfe) { } + + // FIXME: set certificate types. + + // Send the client hello. + ProtocolVersion version = session.protocol; + Random clientRandom = + new Random(Util.unixTime(), session.random.generateSeed(28)); + session.protocol = (ProtocolVersion) session.enabledProtocols.last(); + List comp = new ArrayList(2); + comp.add(CompressionMethod.ZLIB); + comp.add(CompressionMethod.NULL); + ClientHello clientHello = + new ClientHello(session.protocol, clientRandom, sessionId, + session.enabledSuites, comp, extensions); + Handshake msg = new Handshake(Handshake.Type.CLIENT_HELLO, clientHello); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write (dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version)); + dout.flush(); +// try +// { +// Thread.sleep(150); +// } +// catch (InterruptedException ie) +// { +// } + + // Receive the server hello. + msg = Handshake.read(din); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.SERVER_HELLO) + { + throwUnexpectedMessage(); + } + ServerHello serverHello = (ServerHello) msg.getBody(); + Random serverRandom = serverHello.getRandom(); + version = serverHello.getVersion(); + + // If we don't directly support the server's protocol version, choose + // the highest one we support that is less than the server's version. + if (!session.enabledProtocols.contains(version)) + { + ProtocolVersion v1 = null, v2 = null; + for (Iterator it = session.enabledProtocols.iterator(); + it.hasNext(); ) + { + v1 = (ProtocolVersion) it.next(); + if (v1.compareTo(version) > 0) + break; + v2 = v1; + } + version = v1; + } + + // The server's version is either unsupported by us (unlikely) or the user + // has only enabled incompatible versions. + if (version == null) + { + Alert.Description desc = null; + if (serverHello.getVersion() == ProtocolVersion.SSL_3) + { + desc = Alert.Description.HANDSHAKE_FAILURE; + } + else + { + desc = Alert.Description.PROTOCOL_VERSION; + } + Alert alert = new Alert(Alert.Level.FATAL, desc); + sendAlert(alert); + session.currentAlert = alert; + fatal(); + throw new AlertException(alert, true); + } + + if (serverHello.getExtensions() != null) + { + for (Iterator it = serverHello.getExtensions().iterator(); + it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.getType() == Extension.Type.MAX_FRAGMENT_LENGTH) + { + int len = Extensions.getMaxFragmentLength(e).intValue(); + session.params.setFragmentLength(len); +// recordOutput.setFragmentLength(len); +// recordInput.setFragmentLength(len); + } + else if (e.getType() == Extension.Type.CERT_TYPE) + { + certType = Extensions.getServerCertType(e); + } + } + } + + CipherSuite suite = serverHello.getCipherSuite().resolve(version); + boolean newSession = true; + if (sessionId.length > 0 && + Arrays.equals(sessionId, serverHello.getSessionId())) + { + SecurityParameters params = session.params; + SecureRandom random = session.random; + session = (Session) continuedSession.clone(); + session.params = params; + session.random = random; + recordInput.setSession(session); +// recordOutput.setSession(session); + suite = session.cipherSuite; + newSession = false; + } + else + { + sessionContext.removeSession(new Session.ID(sessionId)); + } + if (newSession) + { + session.peerHost = remoteHost; + session.sessionId = new Session.ID(serverHello.getSessionId()); + session.cipherSuite = suite; + } + session.params.reset(); +// session.params.setInMac(null); +// session.params.setOutMac(null); +// session.params.setInRandom(null); +// session.params.setOutRandom(null); +// session.params.setInCipher(null); +// session.params.setOutCipher(null); + session.currentAlert = null; + session.valid = true; + session.protocol = version; + + // If the server responded with the same session id that we sent, we + // assume that the session will be continued, and skip the bulk of the + // handshake. + if (newSession) + { + PublicKey serverKey = null, serverKex = null; + KeyPair clientKeys = null, clientKex = null; + CertificateRequest certReq; + boolean sendKeyExchange = false; + BigInteger srp_x = null; + IKeyAgreementParty clientKA = null; + IncomingMessage in; // used for key agreement protocol exchange + OutgoingMessage out = null; + + if (suite.getKeyExchange() == "SRP") + { + String password = askPassword(user); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, + "SRP: password read is ''{0}''", password); + } + byte[] userSrpPassword = password.getBytes("UTF-8"); + + // instantiate and setup client-side key agreement party + clientKA = KeyAgreementFactory.getPartyAInstance(Registry.SRP_TLS_KA); + Map clientAttributes = new HashMap(); + clientAttributes.put(SRP6KeyAgreement.HASH_FUNCTION, + Registry.SHA160_HASH); + clientAttributes.put(SRP6KeyAgreement.USER_IDENTITY, user); + clientAttributes.put(SRP6KeyAgreement.USER_PASSWORD, userSrpPassword); + try + { + clientKA.init(clientAttributes); + // initiate the exchange + out = clientKA.processMessage(null); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + } + + if (suite.getSignature() != "anon") + { + msg = Handshake.read(din, certType); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.CERTIFICATE) + { + throwUnexpectedMessage(); + } + Certificate serverCertificate = (Certificate) msg.getBody(); + X509Certificate[] peerCerts = serverCertificate.getCertificates(); + try + { + session.trustManager.checkServerTrusted(peerCerts, + suite.getAuthType()); + if (suite.getSignature() == "RSA" && + !(peerCerts[0].getPublicKey() instanceof RSAPublicKey)) + throw new InvalidKeyException("improper public key"); + if (suite.getKeyExchange() == "DH" && + !(peerCerts[0].getPublicKey() instanceof DHPublicKey)) + throw new InvalidKeyException("improper public key"); + if (suite.getKeyExchange() == "DHE") + { + if (suite.getSignature() == "RSA" && + !(peerCerts[0].getPublicKey() instanceof RSAPublicKey)) + throw new InvalidKeyException("improper public key"); + if (suite.getSignature() == "DSS" && + !(peerCerts[0].getPublicKey() instanceof DSAPublicKey)) + throw new InvalidKeyException("improper public key"); + } + session.peerCerts = peerCerts; + session.peerVerified = true; + } + catch (InvalidKeyException ike) + { + throwHandshakeFailure(); + } + catch (Exception x) + { + if (!checkCertificates(peerCerts)) + { + peerUnverified(peerCerts); + SSLPeerUnverifiedException e = + new SSLPeerUnverifiedException ("could not verify peer certificate: "+ + peerCerts[0].getSubjectDN()); + e.initCause (x); + throw e; + } + session.peerCerts = peerCerts; + session.peerVerified = true; + } + serverKey = peerCerts[0].getPublicKey(); + serverKex = serverKey; + } + + msg = Handshake.read(din, suite, serverKey); + + // Receive the server's key exchange. + if (msg.getType() == Handshake.Type.SERVER_KEY_EXCHANGE) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + ServerKeyExchange skex = (ServerKeyExchange) msg.getBody(); + serverKex = skex.getPublicKey(); + if (suite.getSignature() != "anon") + { + ISignature sig = null; + if (suite.getSignature() == "RSA") + { + sig = new SSLRSASignature(); + } + else if (suite.getSignature() == "DSS") + { + sig = SignatureFactory.getInstance(Registry.DSS_SIG); + } + sig.setupVerify(Collections.singletonMap( + ISignature.VERIFIER_KEY, serverKey)); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + if (suite.getKeyExchange() == "RSA") + { + updateSig(sig, ((RSAPublicKey) serverKex).getModulus()); + updateSig(sig, ((RSAPublicKey) serverKex).getPublicExponent()); + } + else if (suite.getKeyExchange() == "DHE") + { + updateSig(sig, ((DHPublicKey) serverKex).getParams().getP()); + updateSig(sig, ((DHPublicKey) serverKex).getParams().getG()); + updateSig(sig, ((DHPublicKey) serverKex).getY()); + } + else if (suite.getKeyExchange() == "SRP") + { + updateSig(sig, ((SRPPublicKey) serverKex).getN()); + updateSig(sig, ((SRPPublicKey) serverKex).getG()); + byte[] srpSalt = skex.getSRPSalt(); + sig.update((byte) srpSalt.length); + sig.update(srpSalt, 0, srpSalt.length); + updateSig(sig, ((SRPPublicKey) serverKex).getY()); + } + if (!sig.verify(skex.getSignature().getSigValue())) + { + throwHandshakeFailure(); + } + } + + if (suite.getKeyExchange() == "SRP") + { + // use server's key exchange data to continue + // agreement protocol by faking a received incoming + // message. again the following code can be broken + // into multiple blocks for more accurate exception + // handling + try + { + out = new OutgoingMessage(); + out.writeMPI(((SRPPublicKey) serverKex).getN()); + out.writeMPI(((SRPPublicKey) serverKex).getG()); + out.writeMPI(new BigInteger(1, skex.getSRPSalt())); + out.writeMPI(((SRPPublicKey) serverKex).getY()); + + in = new IncomingMessage(out.toByteArray()); + + out = clientKA.processMessage(in); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "clientKA isComplete? {0}", + Boolean.valueOf (clientKA.isComplete())); + } + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + } + msg = Handshake.read(din, suite, serverKey); + } + + // See if the server wants us to send our certificates. + certReq = null; + if (msg.getType() == Handshake.Type.CERTIFICATE_REQUEST) + { + if (suite.getSignature() == "anon") + { + throwHandshakeFailure(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + certReq = (CertificateRequest) msg.getBody(); + msg = Handshake.read(din); + } + + // Read ServerHelloDone. + if (msg.getType() != Handshake.Type.SERVER_HELLO_DONE) + { + throwUnexpectedMessage(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + + // Send our certificate chain if the server asked for it. + if (certReq != null) + { + String alias = session.keyManager.chooseClientAlias( + certReq.getTypeStrings(), certReq.getAuthorities(), null); + if (alias == null && version == ProtocolVersion.SSL_3) + { + Alert alert = + new Alert(Alert.Level.WARNING, Alert.Description.NO_CERTIFICATE); + sendAlert(alert); + } + else + { + X509Certificate[] chain = + session.keyManager.getCertificateChain(alias); + PrivateKey key = session.keyManager.getPrivateKey(alias); + if (chain == null) + { + chain = new X509Certificate[0]; + } + Certificate cert = new Certificate(chain); + msg = new Handshake(Handshake.Type.CERTIFICATE, cert); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + dout.flush(); + if (chain.length > 0) + { + session.localCerts = chain; + clientKeys = new KeyPair(chain[0].getPublicKey(), key); + } + } + } + + // Send our key exchange. + byte[] preMasterSecret = null; + ClientKeyExchange ckex = null; + if (suite.getKeyExchange() == "RSA") + { + ProtocolVersion v = + (ProtocolVersion) session.enabledProtocols.last(); + byte[] b = new byte[46]; + session.random.nextBytes (b); + preMasterSecret = Util.concat(v.getEncoded(), b); + EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance((RSAPublicKey) serverKex); + BigInteger bi = new BigInteger(1, + pkcs1.encode(preMasterSecret, session.random)); + bi = RSA.encrypt((RSAPublicKey) serverKex, bi); + ckex = new ClientKeyExchange(Util.trim(bi)); + } + else if (suite.getKeyExchange().startsWith("DH")) + { + if (clientKeys == null || + !(clientKeys.getPublic() instanceof DHPublicKey)) + { + GnuDHPrivateKey tmpKey = + new GnuDHPrivateKey(null, ((DHPublicKey) serverKex).getParams().getP(), + ((DHPublicKey) serverKex).getParams().getG(), null); + clientKA = KeyAgreementFactory.getPartyBInstance(Registry.DH_KA); + Map attr = new HashMap(); + attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY, + tmpKey); + attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS, + session.random); + try + { + clientKA.init(attr); + out = new OutgoingMessage(); + out.writeMPI(((DHPublicKey) serverKex).getY()); + in = new IncomingMessage(out.toByteArray()); + out = clientKA.processMessage(in); + in = new IncomingMessage(out.toByteArray()); + ckex = new ClientKeyExchange(in.readMPI()); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + } + else + { + clientKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA); + Map attr = new HashMap(); + attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY, + clientKeys.getPrivate()); + try + { + // The key exchange is already complete here; our public + // value was sent with our certificate. + clientKA.init(attr); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + ckex = new ClientKeyExchange(new byte[0]); + } + } + else if (suite.getKeyExchange() == "SRP") + { + // at this point, out --the outgoing message-- already contains + // what we want. so... + BigInteger A = null; + try + { + in = new IncomingMessage(out.toByteArray()); + A = in.readMPI(); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "client A:{0}", A); + } + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + ckex = new ClientKeyExchange(A); + } + msg = new Handshake(Handshake.Type.CLIENT_KEY_EXCHANGE, ckex); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write (dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + + // Generate the master secret. + if (suite.getKeyExchange().startsWith("DH")) + { + try + { + preMasterSecret = clientKA.getSharedSecret(); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + } + else if (suite.getKeyExchange() == "SRP") + { + try + { + preMasterSecret = clientKA.getSharedSecret(); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + finally + { + clientKA = null; + } + } + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}", + Util.toHexString (preMasterSecret, ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}", + Util.toHexString(clientRandom.getEncoded(), ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}", + Util.toHexString(serverRandom.getEncoded(), ':')); + } + IRandom genSecret = null; + if (version == ProtocolVersion.SSL_3) + { + genSecret = new SSLRandom(); + HashMap attr = new HashMap(); + attr.put(SSLRandom.SECRET, preMasterSecret); + attr.put(SSLRandom.SEED, + Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded())); + genSecret.init(attr); + } + else + { + genSecret = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, preMasterSecret); + attr.put(TLSRandom.SEED, + Util.concat(("master secret").getBytes("UTF-8"), + Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded()))); + genSecret.init(attr); + } + session.masterSecret = new byte[48]; + try + { + genSecret.nextBytes(session.masterSecret, 0, 48); + for (int i = 0; i < preMasterSecret.length; i++) + { + preMasterSecret[i] = 0; + } + } + catch (LimitReachedException shouldNotHappen) + { + internalError(); + RuntimeException re = new RuntimeException (shouldNotHappen.getMessage()); + re.initCause (shouldNotHappen); + throw re; + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}", + Util.toHexString(session.masterSecret, ':')); + } + + // Send our certificate verify message. + if (certReq != null && clientKeys != null) + { + IMessageDigest vMD5 = (IMessageDigest) md5.clone(); + IMessageDigest vSHA = (IMessageDigest) sha.clone(); + PrivateKey key = clientKeys.getPrivate(); + Object sig = null; + String sigAlg = null; + try + { + if (key instanceof DSAPrivateKey) + { + sig = DSSSignature.sign((DSAPrivateKey) key, vSHA.digest(), + session.random); + sigAlg = "DSS"; + } + else if (key instanceof RSAPrivateKey) + { + SSLRSASignature rsa = new SSLRSASignature(vMD5, vSHA); + rsa.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, key)); + sig = rsa.sign(); + sigAlg = "RSA"; + } + else + { + throw new InvalidKeyException("no appropriate key"); + } + } + catch (Exception x) + { + throwHandshakeFailure(); + } + CertificateVerify verify = new CertificateVerify(sig, sigAlg); + msg = new Handshake(Handshake.Type.CERTIFICATE_VERIFY, verify); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + } + dout.flush(); + } + + byte[][] keys = null; + try + { + keys = generateKeys(serverRandom.getEncoded(), + clientRandom.getEncoded(), version); + } + catch (Exception x) + { + internalError(); + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + + session.params.setVersion (version); + + // Initialize the algorithms with the derived keys. + Object readMac = null, writeMac = null; + Object readCipher = null, writeCipher = null; + try + { + if (session.params instanceof GNUSecurityParameters) + { + HashMap attr = new HashMap(); + writeMac = CipherSuite.getMac(suite.getMac()); + readMac = CipherSuite.getMac(suite.getMac()); + attr.put(IMac.MAC_KEY_MATERIAL, keys[0]); + ((IMac) writeMac).init(attr); + attr.put(IMac.MAC_KEY_MATERIAL, keys[1]); + ((IMac) readMac).init(attr); + if (suite.getCipher() == "RC4") + { + writeCipher = new ARCFour(); + readCipher = new ARCFour(); + attr.clear(); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]); + ((ARCFour) writeCipher).init(attr); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]); + ((ARCFour) readCipher).init(attr); + } + else if (!suite.isStreamCipher()) + { + writeCipher = CipherSuite.getCipher(suite.getCipher()); + readCipher = CipherSuite.getCipher(suite.getCipher()); + attr.clear(); + attr.put(IMode.KEY_MATERIAL, keys[2]); + attr.put(IMode.IV, keys[4]); + attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + ((IMode) writeCipher).init(attr); + attr.put(IMode.KEY_MATERIAL, keys[3]); + attr.put(IMode.IV, keys[5]); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + ((IMode) readCipher).init(attr); + } + } + else // JCESecurityParameters + { + writeMac = CipherSuite.getJCEMac (suite.getMac()); + readMac = CipherSuite.getJCEMac (suite.getMac()); + writeCipher = CipherSuite.getJCECipher (suite.getCipher()); + readCipher = CipherSuite.getJCECipher (suite.getCipher()); + ((Mac) writeMac).init (new SecretKeySpec (keys[0], suite.getMac())); + ((Mac) readMac).init (new SecretKeySpec (keys[1], suite.getMac())); + if (!suite.isStreamCipher()) + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher()), + new IvParameterSpec (keys[4])); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher()), + new IvParameterSpec (keys[5])); + } + else + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher())); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher())); + } + } + } + // These should technically never happen, if our key generation is not + // broken. + catch (InvalidKeyException ike) + { + internalError(); + RuntimeException re = new RuntimeException (ike.getMessage()); + re.initCause(ike); + throw re; + } + catch (InvalidAlgorithmParameterException iape) + { + internalError(); + RuntimeException re = new RuntimeException (iape.getMessage()); + re.initCause (iape); + throw re; + } + // These indicate a configuration error with the JCA. + catch (NoSuchAlgorithmException nsae) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException x = new SSLException ("suite " + suite + " not available in this configuration"); + x.initCause (nsae); + throw x; + } + catch (NoSuchPaddingException nspe) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException x = new SSLException ("suite " + suite + " not available in this configuration"); + x.initCause (nspe); + throw x; + } + + Finished finis = null; + + if (newSession) + { + changeCipherSpec(); + session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), true); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + if (session.currentAlert != null && + session.currentAlert.getLevel() == Alert.Level.FATAL) + { + fatal(); + throw new AlertException(session.currentAlert, false); + } + + synchronized (session.params) + { + readChangeCipherSpec (); + session.params.setInflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB); + session.params.setInMac(readMac); + session.params.setInCipher(readCipher); + session.params.notifyAll(); + } + + Finished verify = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), false); + + msg = Handshake.read(din, suite, null); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.FINISHED) + { + throwUnexpectedMessage(); + } + finis = (Finished) msg.getBody(); + if (version == ProtocolVersion.SSL_3) + { + if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) || + !Arrays.equals(finis.getSHAHash(), verify.getSHAHash())) + { + throwHandshakeFailure(); + } + } + else + { + if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData())) + { + throwHandshakeFailure(); + } + } + + if (!newSession) + { + changeCipherSpec(); + session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, md5, sha, true); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + handshakeCompleted(); + } + + /** + * Perform the server handshake. + */ + private void doServerHandshake() throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "doing server handshake in {0}", + Thread.currentThread()); + } + + if (remoteHost == null) + { + remoteHost = getInetAddress().getHostName(); + } + if (remoteHost == null) + { + remoteHost = getInetAddress().getHostAddress(); + } + + IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH); + IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH); + DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha); + DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha); + + // Read the client hello. + Handshake msg = Handshake.read(din); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + if (msg.getType() != Handshake.Type.CLIENT_HELLO) + { + throwUnexpectedMessage(); + } + ClientHello clientHello = (ClientHello) msg.getBody(); + Random clientRandom = clientHello.getRandom(); + ProtocolVersion version = clientHello.getVersion(); + ProtocolVersion server = + (ProtocolVersion) session.enabledProtocols.last(); + CompressionMethod comp; + if (clientHello.getCompressionMethods().contains(CompressionMethod.ZLIB)) + comp = CompressionMethod.ZLIB; + else + comp = CompressionMethod.NULL; + if (!session.enabledProtocols.contains(version) + && version.compareTo(server) < 0) + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.PROTOCOL_VERSION); + sendAlert(alert); + session.currentAlert = alert; + throw new AlertException(alert, true); + } + + // Look through the extensions sent by the client (if any), and react to + // them appropriately. + List extensions = null; + String remoteUser = null; + if (clientHello.getExtensions() != null) + { + for (Iterator it = clientHello.getExtensions().iterator(); it.hasNext();) + { + Extension ex = (Extension) it.next(); + if (ex.getType() == Extension.Type.SERVER_NAME) + { + if (extensions == null) + { + extensions = new LinkedList(); + } + extensions.add(ex); + } + else if (ex.getType() == Extension.Type.MAX_FRAGMENT_LENGTH) + { + int maxLen = Extensions.getMaxFragmentLength(ex).intValue(); +// recordInput.setFragmentLength(maxLen); +// recordOutput.setFragmentLength(maxLen); + session.params.setFragmentLength(maxLen); + if (extensions == null) + { + extensions = new LinkedList(); + } + extensions.add(ex); + } + else if (ex.getType() == Extension.Type.SRP) + { + if (extensions == null) + { + extensions = new LinkedList(); + } + byte[] b = ex.getValue(); + remoteUser = new String(ex.getValue(), 1, b[0] & 0xFF, "UTF-8"); + session.putValue("srp-username", remoteUser); + } + } + } + + CipherSuite suite = selectSuite(clientHello.getCipherSuites(), version); + if (suite == null) + { + return; + } + + // If the selected suite turns out to be SRP, set up the key exchange + // objects. + IKeyAgreementParty serverKA = null; + IncomingMessage in; + OutgoingMessage out = null; + if (suite.getKeyExchange() == "SRP") + { + // FIXME + // Uhm, I don't think this can happen, because if remoteUser is null + // we cannot choose an SRP ciphersuite... + if (remoteUser == null) + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.MISSING_SRP_USERNAME); + sendAlert(alert); + throw new AlertException(alert, true); + } + + SRPAuthInfoProvider srpDB = new SRPAuthInfoProvider(); + Map dbAttributes = new HashMap(); + dbAttributes.put(SRPRegistry.PASSWORD_DB, + session.srpTrustManager.getPasswordFile()); + srpDB.activate(dbAttributes); + + // FIXME + // We can also fake that the user exists, and generate a dummy (and + // invalid) master secret, and let the handshake fail at the Finished + // message. This is better than letting the connecting side know that + // the username they sent isn't valid. + // + // But how to implement this? + if (!srpDB.contains(remoteUser)) + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.UNKNOWN_SRP_USERNAME); + sendAlert(alert); + throw new AlertException(alert, true); + } + + serverKA = KeyAgreementFactory.getPartyBInstance(Registry.SRP_TLS_KA); + Map serverAttributes = new HashMap(); + serverAttributes.put(SRP6KeyAgreement.HASH_FUNCTION, + Registry.SHA160_HASH); + serverAttributes.put(SRP6KeyAgreement.HOST_PASSWORD_DB, srpDB); + + try + { + serverKA.init(serverAttributes); + out = new OutgoingMessage(); + out.writeString(remoteUser); + in = new IncomingMessage(out.toByteArray()); + out = serverKA.processMessage(in); + } + catch (KeyAgreementException x) + { + throwHandshakeFailure(); + } + } + + // Check if the session specified by the client's ID corresponds + // to a saved session, and if so, continue it. + boolean newSession = true; + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "saved sessions: {0}", sessionContext); + } + if (sessionContext.containsSessionID( + new Session.ID(clientHello.getSessionId()))) + { + Session old = session; + session = (Session) sessionContext.getSession(clientHello.getSessionId()); + if (!clientHello.getCipherSuites().contains(session.cipherSuite)) + { + throwHandshakeFailure(); + } + if (session.getPeerHost().equals(remoteHost) && + old.enabledProtocols.contains(session.protocol)) + { + session = (Session) session.clone(); + suite = session.cipherSuite; + newSession = false; + recordInput.setSession(session); + session.currentAlert = null; + session.params = old.params; + session.random = old.random; + } + else + { + if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "rejected section; hosts equal? {0}, same suites? {1}", + new Object[] { Boolean.valueOf (session.getPeerHost().equals(remoteHost)), + Boolean.valueOf (old.enabledProtocols.contains(session.protocol)) }); + } + session = old; + session.peerHost = remoteHost; + newSession = true; + } + } + else if (DEBUG_HANDSHAKE_LAYER) + { + logger.log (Component.SSL_HANDSHAKE, "rejected session; have session id? {0}, saved sessions: {1}", + new Object[] { Boolean.valueOf (sessionContext.containsSessionID(new Session.ID(clientHello.getSessionId()))), + sessionContext }); + } + if (newSession) + { + byte[] buf = new byte[32]; + Session.ID sid = null; + do + { + session.random.nextBytes(buf); + sid = new Session.ID(buf); + } + while (sessionContext.containsSessionID(sid)); + session.sessionId = sid; + } + session.valid = true; + session.peerHost = remoteHost; + session.cipherSuite = suite; + session.protocol = version; + session.params.setVersion (version); + + // Send the server hello. + Random serverRandom = new Random(Util.unixTime(), + session.random.generateSeed(28)); + ServerHello serverHello = new ServerHello(version, serverRandom, + session.getId(), suite, + comp, extensions); + msg = new Handshake(Handshake.Type.SERVER_HELLO, serverHello); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version)); + dout.flush(); + + if (newSession) + { + X509Certificate[] certs = null; + PrivateKey serverKey = null; + if (suite.getSignature() != "anon") + { + // Send our CA-issued certificate to the client. + String alias = session.keyManager.chooseServerAlias(suite.getAuthType(), + null, null); + certs = session.keyManager.getCertificateChain(alias); + serverKey = session.keyManager.getPrivateKey(alias); + if (certs == null || serverKey == null) + { + throwHandshakeFailure(); + } + session.localCerts = certs; + Certificate serverCert = new Certificate(certs); + msg = new Handshake(Handshake.Type.CERTIFICATE, serverCert); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + dout.flush(); + } + + // If the certificate we sent does not contain enough information to + // do the key exchange (in the case of ephemeral Diffie-Hellman, + // export RSA, and SRP) we send a signed public key to be used for the + // key exchange. + KeyPair signPair = null; + if (certs != null) + { + signPair = new KeyPair(certs[0].getPublicKey(), serverKey); + } + KeyPair kexPair = signPair; + ServerKeyExchange skex = null; + + // Set up our key exchange, and/or prepare our ServerKeyExchange + // message. + if ((suite.getKeyExchange() == "RSA" && suite.isExportable() && + ((RSAPrivateKey) serverKey).getModulus().bitLength() > 512)) + { + kexPair = KeyPool.generateRSAKeyPair(); + RSAPublicKey pubkey = (RSAPublicKey) kexPair.getPublic(); + Signature s = null; + if (suite.getSignature() != "anon") + { + SSLRSASignature sig = new SSLRSASignature(); + sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, + signPair.getPrivate())); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + updateSig(sig, pubkey.getModulus()); + updateSig(sig, pubkey.getPublicExponent()); + s = new Signature(sig.sign(), "RSA"); + } + skex = new ServerKeyExchange(pubkey, s); + } + else if (suite.getKeyExchange() == "DH") + { + serverKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA); + Map attr = new HashMap(); + attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY, + serverKey); + try + { + serverKA.init(attr); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + // We don't send a ServerKeyExchange for this suite. + } + else if (suite.getKeyExchange() == "DHE") + { + serverKA = KeyAgreementFactory.getPartyAInstance(Registry.DH_KA); + Map attr = new HashMap(); + GnuDHPrivateKey servParams = DiffieHellman.getParams(); + attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY, + servParams); + attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS, + session.random); + BigInteger serv_y = null; + try + { + serverKA.init(attr); + out = serverKA.processMessage(null); + in = new IncomingMessage(out.toByteArray()); + serv_y = in.readMPI(); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DHE exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + GnuDHPublicKey pubkey = + new GnuDHPublicKey(null, servParams.getParams().getP(), + servParams.getParams().getG(), serv_y); + Signature s = null; + if (suite.getSignature() != "anon") + { + ISignature sig = null; + if (suite.getSignature() == "RSA") + { + sig = new SSLRSASignature(); + } + else + { + sig = SignatureFactory.getInstance(Registry.DSS_SIG); + } + sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, + signPair.getPrivate())); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + updateSig(sig, pubkey.getParams().getP()); + updateSig(sig, pubkey.getParams().getG()); + updateSig(sig, pubkey.getY()); + s = new Signature(sig.sign(), suite.getSignature()); + } + skex = new ServerKeyExchange(pubkey, s); + } + else if (suite.getKeyExchange() == "SRP") + { + BigInteger N = null; + BigInteger g = null; + BigInteger salt = null; + BigInteger B = null; + try + { + in = new IncomingMessage(out.toByteArray()); + N = in.readMPI(); + g = in.readMPI(); + salt = in.readMPI(); + B = in.readMPI(); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + Signature s = null; + final byte[] srpSalt = Util.trim(salt); + if (suite.getSignature() != "anon") + { + ISignature sig = null; + if (suite.getSignature() == "RSA") + { + sig = new SSLRSASignature(); + } + else + { + sig = SignatureFactory.getInstance(Registry.DSS_SIG); + } + sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, + signPair.getPrivate())); + byte[] buf = clientRandom.getEncoded(); + sig.update(buf, 0, buf.length); + buf = serverRandom.getEncoded(); + sig.update(buf, 0, buf.length); + updateSig(sig, N); + updateSig(sig, g); + sig.update((byte) srpSalt.length); + sig.update(srpSalt, 0, srpSalt.length); + updateSig(sig, B); + s = new Signature(sig.sign(), suite.getSignature()); + } + final SRPPublicKey pubkey = new SRPPublicKey(N, g, B); + skex = new ServerKeyExchange(pubkey, s, srpSalt); + } + if (skex != null) + { + msg = new Handshake(Handshake.Type.SERVER_KEY_EXCHANGE, skex); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); +// recordOutput.setHandshakeAvail(msg.write(dout, version));; + dout.flush(); + } + + // If we are configured to want or need client authentication, then + // ask for it. + if (wantClientAuth || needClientAuth) + { + Principal[] auths = null; + CertificateRequest.ClientType[] types = + new CertificateRequest.ClientType[] { + CertificateRequest.ClientType.RSA_SIGN, + CertificateRequest.ClientType.DSS_SIGN, + CertificateRequest.ClientType.RSA_FIXED_DH, + CertificateRequest.ClientType.DSS_FIXED_DH + }; + try + { + auths = (Principal[]) + Util.transform(session.trustManager.getAcceptedIssuers(), + Principal.class, "getSubjectDN", null); + } + catch (Exception x) + { + internalError(); + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + CertificateRequest req = new CertificateRequest(types, auths); + msg = new Handshake(Handshake.Type.CERTIFICATE_REQUEST, req); + msg.write(dout, version); + dout.flush(); + } + + // Send our server hello done. + msg = new Handshake(Handshake.Type.SERVER_HELLO_DONE, null); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + + if (suite.getKeyExchange() == "RSA") + { + msg = Handshake.read(din, suite, kexPair.getPublic()); + } + else + { + msg = Handshake.read(din, suite, null); + } + boolean clientCertOk = false; + boolean clientCanSign = false; + X509Certificate[] clientChain = null; + PublicKey clientKey = null; + + // Read the client's certificate, if sent. + if (msg.getType() == Handshake.Type.CERTIFICATE) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + Certificate cliCert = (Certificate) msg.getBody(); + clientChain = cliCert.getCertificates(); + try + { + session.trustManager.checkClientTrusted(clientChain, + suite.getAuthType()); + session.peerCerts = clientChain; + session.peerVerified = true; + clientKey = clientChain[0].getPublicKey(); + } + catch (Exception x) + { + } + clientCanSign = ((clientKey instanceof DSAPublicKey) || + (clientKey instanceof RSAPublicKey)); + if (suite.getKeyExchange().startsWith("DH")) + { + msg = Handshake.read(din, suite, clientKey); + } + else + { + msg = Handshake.read(din, suite, kexPair.getPublic()); + } + } + + // If we require client authentication, and the client sent an + // unverifiable certificate or no certificate at all, drop the + // connection. + if (!session.peerVerified && needClientAuth) + { + throwHandshakeFailure(); + } + + // Read the client key exchange. + if (msg.getType() != Handshake.Type.CLIENT_KEY_EXCHANGE) + { + throwUnexpectedMessage(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + ClientKeyExchange ckex = (ClientKeyExchange) msg.getBody(); + byte[] preMasterSecret = null; + if (suite.getKeyExchange() == "RSA") + { + byte[] enc = (byte[]) ckex.getExchangeObject(); + BigInteger bi = new BigInteger(1, enc); + try + { + bi = RSA.decrypt(kexPair.getPrivate(), bi); + EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance( + (RSAPrivateKey) kexPair.getPrivate()); + preMasterSecret = pkcs1.decode(Util.concat(new byte[1], bi.toByteArray())); + //rsa.init(kexPair); + //preMasterSecret = rsa.decrypt(enc); + } + catch (Exception x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "RSA exception", x); + } + // Generate a fake pre-master secret if the RSA decryption + // fails. + byte[] b = new byte[46]; + session.random.nextBytes (b); + preMasterSecret = Util.concat(version.getEncoded(), b); + } + } + else if (suite.getKeyExchange().startsWith("DH")) + { + try + { + out = new OutgoingMessage(); + if (clientKey == null) + out.writeMPI((BigInteger) ckex.getExchangeObject()); + else + out.writeMPI(((DHPublicKey) clientKey).getY()); + in = new IncomingMessage(out.toByteArray()); + serverKA.processMessage(in); + preMasterSecret = serverKA.getSharedSecret(); + } + catch (KeyAgreementException kae) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae); + } + internalError(); + RuntimeException re = new RuntimeException (kae.getMessage()); + re.initCause (kae); + throw re; + } + } + else if (suite.getKeyExchange() == "SRP") + { + BigInteger A = (BigInteger) ckex.getExchangeObject(); + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP: client A: {0}", A); + } + try + { + out = new OutgoingMessage(); + out.writeMPI(A); + in = new IncomingMessage(out.toByteArray()); + out = serverKA.processMessage(in); + preMasterSecret = serverKA.getSharedSecret(); + } + catch (KeyAgreementException x) + { + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x); + } + throwHandshakeFailure(); + } + finally + { + serverKA = null; + } + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}", + Util.toHexString(preMasterSecret, ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}", + Util.toHexString(clientRandom.getEncoded(), ':')); + logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}", + Util.toHexString(serverRandom.getEncoded(), ':')); + } + + // Generate the master secret. + IRandom genSecret = null; + if (version == ProtocolVersion.SSL_3) + { + genSecret = new SSLRandom(); + HashMap attr = new HashMap(); + attr.put(SSLRandom.SECRET, preMasterSecret); + attr.put(SSLRandom.SEED, Util.concat(clientRandom.getEncoded(), + serverRandom.getEncoded())); + genSecret.init(attr); + } + else + { + genSecret = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, preMasterSecret); + attr.put(TLSRandom.SEED, + Util.concat(("master secret").getBytes("UTF-8"), + Util.concat(clientRandom.getEncoded(), + serverRandom.getEncoded()))); + genSecret.init(attr); + } + session.masterSecret = new byte[48]; + try + { + genSecret.nextBytes(session.masterSecret, 0, 48); + for (int i = 0; i < preMasterSecret.length; i++) + { + preMasterSecret[i] = 0; + } + } + catch (LimitReachedException shouldNotHappen) + { + internalError(); + RuntimeException re = new RuntimeException(); + re.initCause (shouldNotHappen); + throw re; + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}", + Util.toHexString(session.masterSecret, ':')); + } + + // Read the client's certificate verify message, if needed. + if (clientCanSign && (wantClientAuth || needClientAuth)) + { + msg = Handshake.read(din); + if (msg.getType() != Handshake.Type.CERTIFICATE_VERIFY) + { + throwUnexpectedMessage(); + } + CertificateVerify verify = (CertificateVerify) msg.getBody(); + if (clientChain != null && clientChain.length > 0) + { + IMessageDigest cvMD5 = (IMessageDigest) md5.clone(); + IMessageDigest cvSHA = (IMessageDigest) sha.clone(); + clientKey = clientChain[0].getPublicKey(); + if (clientKey instanceof RSAPublicKey) + { + SSLRSASignature sig = new SSLRSASignature(cvMD5, cvSHA); + sig.setupVerify(Collections.singletonMap(ISignature.VERIFIER_KEY, clientKey)); + if (!sig.verify(verify.getSigValue())) + { + handshakeFailure(); + throw new SSLHandshakeException("client certificate verify failed"); + } + } + else if (clientKey instanceof DSAPublicKey) + { + try + { + if (!DSSSignature.verify((DSAPublicKey) clientKey, cvSHA.digest(), + (BigInteger[]) verify.getSigValue())) + { + throw new Exception("client's certificate could not be verified"); + } + } + catch (Exception x) + { + handshakeFailure(); + SSLHandshakeException e = new SSLHandshakeException (x.getMessage()); + e.initCause (x); + throw e; + } + } + } + } + } + + // Generate the session keys. + byte[][] keys = null; + try + { + keys = generateKeys(serverRandom.getEncoded(), + clientRandom.getEncoded(), version); + } + catch (Exception x) + { + internalError(); + RuntimeException re = new RuntimeException (x.getMessage()); + re.initCause (x); + throw re; + } + + // Initialize the algorithms with the derived keys. + Object readMac = null, writeMac = null; + Object readCipher = null, writeCipher = null; + try + { + if (session.params instanceof GNUSecurityParameters) + { + HashMap attr = new HashMap(); + writeMac = CipherSuite.getMac(suite.getMac()); + readMac = CipherSuite.getMac(suite.getMac()); + attr.put(IMac.MAC_KEY_MATERIAL, keys[1]); + ((IMac) writeMac).init(attr); + attr.put(IMac.MAC_KEY_MATERIAL, keys[0]); + ((IMac) readMac).init(attr); + if (suite.getCipher() == "RC4") + { + writeCipher = new ARCFour(); + readCipher = new ARCFour(); + attr.clear(); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]); + ((ARCFour) writeCipher).init(attr); + attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]); + ((ARCFour) readCipher).init(attr); + } + else if (!suite.isStreamCipher()) + { + writeCipher = CipherSuite.getCipher(suite.getCipher()); + readCipher = CipherSuite.getCipher(suite.getCipher()); + attr.clear(); + attr.put(IMode.KEY_MATERIAL, keys[3]); + attr.put(IMode.IV, keys[5]); + attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + ((IMode) writeCipher).init(attr); + attr.put(IMode.KEY_MATERIAL, keys[2]); + attr.put(IMode.IV, keys[4]); + attr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + ((IMode) readCipher).init(attr); + } + } + else // JCESecurityParameters + { + writeMac = CipherSuite.getJCEMac (suite.getMac()); + readMac = CipherSuite.getJCEMac (suite.getMac()); + writeCipher = CipherSuite.getJCECipher (suite.getCipher()); + readCipher = CipherSuite.getJCECipher (suite.getCipher()); + ((Mac) writeMac).init (new SecretKeySpec (keys[1], suite.getMac())); + ((Mac) readMac).init (new SecretKeySpec (keys[0], suite.getMac())); + if (!suite.isStreamCipher()) + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher()), + new IvParameterSpec (keys[5])); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher()), + new IvParameterSpec (keys[4])); + } + else + { + ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE, + new SecretKeySpec (keys[3], suite.getCipher())); + ((Cipher) readCipher).init (Cipher.DECRYPT_MODE, + new SecretKeySpec (keys[2], suite.getCipher())); + } + } + } + // These should technically never happen, if our key generation is not + // broken. + catch (InvalidKeyException ike) + { + internalError(); + RuntimeException re = new RuntimeException (ike.getMessage()); + re.initCause (ike); + throw new RuntimeException (String.valueOf (ike)); + } + catch (InvalidAlgorithmParameterException iape) + { + internalError(); + RuntimeException re = new RuntimeException (iape.getMessage()); + re.initCause (iape); + throw re; + } + // These indicate a configuration error with the JCA. + catch (NoSuchAlgorithmException nsae) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException e = new SSLException ("suite " + suite + " not available in this configuration"); + e.initCause (nsae); + throw e; + } + catch (NoSuchPaddingException nspe) + { + session.enabledSuites.remove (suite); + internalError(); + SSLException e = new SSLException ("suite " + suite + " not available in this configuration"); + e.initCause (nspe); + throw e; + } + + Finished finis = null; + // If we are continuing a session, we send our Finished message first. + if (!newSession) + { + changeCipherSpec(); + session.params.setDeflating(comp == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), false); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + if (session.currentAlert != null && + session.currentAlert.getLevel() == Alert.Level.FATAL) + { + fatal(); + throw new AlertException(session.currentAlert, false); + } + + // Wait until we receive a ChangeCipherSpec, then change the crypto + // algorithms for the incoming side. + synchronized (session.params) + { + readChangeCipherSpec (); + session.params.setInflating(comp == CompressionMethod.ZLIB); + session.params.setInMac(readMac); + session.params.setInCipher(readCipher); + session.params.notifyAll(); + } + + // Receive and verify the client's finished message. + Finished verify = generateFinished(version, (IMessageDigest) md5.clone(), + (IMessageDigest) sha.clone(), true); + msg = Handshake.read(din, suite, null); + if (msg.getType() != Handshake.Type.FINISHED) + { + throwUnexpectedMessage(); + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + finis = (Finished) msg.getBody(); + if (version == ProtocolVersion.SSL_3) + { + if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) || + !Arrays.equals(finis.getSHAHash(), verify.getSHAHash())) + { + throwHandshakeFailure(); + } + } + else + { + if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData())) + { + throwHandshakeFailure(); + } + } + + // Send our Finished message last for new sessions. + if (newSession) + { + changeCipherSpec(); + session.params.setDeflating(comp == CompressionMethod.ZLIB); + session.params.setOutMac(writeMac); + session.params.setOutCipher(writeCipher); + finis = generateFinished(version, md5, sha, false); + msg = new Handshake(Handshake.Type.FINISHED, finis); + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}", msg); + msg.write(dout, version); + dout.flush(); + } + + handshakeCompleted(); + } + + /** + * Generate the keys from the master secret. + * + * @param server The server's random value. + * @param client The client's random value. + * @param activeVersion The negotiated protocol version. + * @return The generated keys. + */ + private byte[][] generateKeys(byte[] server, byte[] client, + ProtocolVersion activeVersion) + throws LimitReachedException, IOException + { + CipherSuite suite = session.cipherSuite; + int macLen = (suite.getMac().indexOf("MD5") >= 0) ? 16 : 20; + int keyLen = suite.getKeyLength(); + int ivLen = 0; + if (suite.getCipher().indexOf("DES") >= 0) + { + ivLen = 8; + } + else if (suite.getCipher() == "AES") + { + ivLen = 16; + } + byte[][] keyMaterial = new byte[6][]; + keyMaterial[0] = new byte[macLen]; // client_write_MAC_secret + keyMaterial[1] = new byte[macLen]; // server_write_MAC_secret + keyMaterial[2] = new byte[keyLen]; // client_write_key + keyMaterial[3] = new byte[keyLen]; // server_write_key + keyMaterial[4] = new byte[ivLen]; // client_write_IV + keyMaterial[5] = new byte[ivLen]; // server_write_IV + IRandom prf = null; + if (activeVersion == ProtocolVersion.SSL_3) + { + prf = new SSLRandom(); + HashMap attr = new HashMap(); + attr.put(SSLRandom.SECRET, session.masterSecret); + attr.put(SSLRandom.SEED, Util.concat(server, client)); + prf.init(attr); + } + else + { + prf = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, session.masterSecret); + attr.put(TLSRandom.SEED, Util.concat("key expansion".getBytes("UTF-8"), + Util.concat(server, client))); + prf.init(attr); + } + for (int i = 0; i < keyMaterial.length; i++) + { + prf.nextBytes(keyMaterial[i], 0, keyMaterial[i].length); + } + + // Exportable ciphers transform their keys once more, and use a + // nonsecret IV for block ciphers. + if (suite.isExportable()) + { + int finalLen = suite.getCipher() == "DES" ? 8 : 16; + if (activeVersion == ProtocolVersion.SSL_3) + { + IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH); + md5.update(keyMaterial[2], 0, keyMaterial[2].length); + md5.update(client, 0, client.length); + md5.update(server, 0, server.length); + keyMaterial[2] = Util.trim(md5.digest(), finalLen); + md5.update(keyMaterial[3], 0, keyMaterial[3].length); + md5.update(server, 0, server.length); + md5.update(client, 0, client.length); + keyMaterial[3] = Util.trim(md5.digest(), finalLen); + if (!suite.isStreamCipher()) + { + md5.update(client, 0, client.length); + md5.update(server, 0, server.length); + keyMaterial[4] = Util.trim(md5.digest(), ivLen); + md5.update(server, 0, server.length); + md5.update(client, 0, client.length); + keyMaterial[5] = Util.trim(md5.digest(), ivLen); + } + } + else + { + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, keyMaterial[2]); + attr.put(TLSRandom.SEED, + Util.concat("client write key".getBytes("UTF-8"), + Util.concat(client, server))); + prf.init(attr); + keyMaterial[2] = new byte[finalLen]; + prf.nextBytes(keyMaterial[2], 0, finalLen); + attr.put(TLSRandom.SECRET, keyMaterial[3]); + attr.put(TLSRandom.SEED, + Util.concat("server write key".getBytes("UTF-8"), + Util.concat(client, server))); + prf.init(attr); + keyMaterial[3] = new byte[finalLen]; + prf.nextBytes(keyMaterial[3], 0, finalLen); + if (!suite.isStreamCipher()) + { + attr.put(TLSRandom.SECRET, new byte[0]); + attr.put(TLSRandom.SEED, Util.concat("IV block".getBytes("UTF-8"), + Util.concat(client, server))); + prf.init(attr); + prf.nextBytes(keyMaterial[4], 0, keyMaterial[4].length); + prf.nextBytes(keyMaterial[5], 0, keyMaterial[5].length); + } + } + } + + if (DEBUG_KEY_EXCHANGE) + { + logger.log (Component.SSL_KEY_EXCHANGE, "Generated keys:"); + for (int i = 0; i < keyMaterial.length; i++) + logger.log (Component.SSL_KEY_EXCHANGE, "[{0}] {1}", + new Object[] { new Integer (i), + Util.toHexString(keyMaterial[i], ':') }); + } + + return keyMaterial; + } + + /** + * Generate a "finished" message, based on the hashes of the handshake + * messages, the agreed version, and a label. + * + * @param version The agreed version. + * @param md5 The current state of the handshake MD5 hash. + * @param sha The current state of the handshake SHA hash. + * @param client Should be true if the message is generated by the client. + */ + private Finished generateFinished(ProtocolVersion version, IMessageDigest md5, + IMessageDigest sha, boolean client) + { + if (version == ProtocolVersion.SSL_3) + { + if (client) + { + md5.update(SENDER_CLIENT, 0, 4); + } + else + { + md5.update(SENDER_SERVER, 0, 4); + } + byte[] ms = session.masterSecret; + md5.update(ms, 0, ms.length); + for (int i = 0; i < 48; i++) + { + md5.update(SSLHMac.PAD1); + } + byte[] b = md5.digest(); + md5.update(ms, 0, ms.length); + for (int i = 0; i < 48; i++) + { + md5.update(SSLHMac.PAD2); + } + md5.update(b, 0, b.length); + + if (client) + { + sha.update(SENDER_CLIENT, 0, 4); + } + else + { + sha.update(SENDER_SERVER, 0, 4); + } + sha.update(ms, 0, ms.length); + for (int i = 0; i < 40; i++) + { + sha.update(SSLHMac.PAD1); + } + b = sha.digest(); + sha.update(ms, 0, ms.length); + for (int i = 0; i < 40; i++) + { + sha.update(SSLHMac.PAD2); + } + sha.update(b, 0, b.length); + return new Finished(md5.digest(), sha.digest()); + } + else + { + byte[] h1 = md5.digest(); + byte[] h2 = sha.digest(); + String label = client ? "client finished" : "server finished"; + byte[] seed = null; + try + { + seed = Util.concat(label.getBytes("UTF-8"), Util.concat(h1, h2)); + } + catch (java.io.UnsupportedEncodingException uee) + { + RuntimeException re = new RuntimeException (uee.getMessage()); + re.initCause (uee); + throw re; + } + IRandom prf = new TLSRandom(); + HashMap attr = new HashMap(); + attr.put(TLSRandom.SECRET, session.masterSecret); + attr.put(TLSRandom.SEED, seed); + prf.init(attr); + byte[] finishedValue = new byte[12]; + try + { + prf.nextBytes(finishedValue, 0, 12); + } + catch (LimitReachedException lre) + { + RuntimeException re = new RuntimeException (lre.getMessage()); + re.initCause (lre); + throw re; + } + return new Finished(finishedValue); + } + } + + /** + * Send a fatal unexpected_message alert. + */ + private Alert unexpectedMessage() throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.UNEXPECTED_MESSAGE); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwUnexpectedMessage() throws IOException + { + throw new AlertException(unexpectedMessage(), true); + } + + /** + * Send a fatal handshake_failure alert. + */ + private Alert handshakeFailure() throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.HANDSHAKE_FAILURE); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwHandshakeFailure() throws IOException + { + throw new AlertException(handshakeFailure(), true); + } + + /** + * Send an internal_error alert. + */ + private Alert internalError() throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.INTERNAL_ERROR); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwInternalError() throws IOException + { + throw new AlertException(internalError(), true); + } + + private Alert peerUnverified(X509Certificate[] chain) throws IOException + { + Alert alert = new Alert(Alert.Level.FATAL, + Alert.Description.HANDSHAKE_FAILURE); + sendAlert(alert); + fatal(); + return alert; + } + + private void throwPeerUnverified(X509Certificate[] chain) throws IOException + { + peerUnverified (chain); + throw new SSLPeerUnverifiedException("could not verify: "+ + chain[0].getSubjectDN()); + } + + /** + * Grab the first suite that is both in the client's requested suites + * and in our enabled suites, and for which we have the proper + * credentials. + * + * @param suites The client's requested suites. + * @param version The version being negotiated. + * @return The selected cipher suite. + * @throws SSLException If no appropriate suite can be selected. + */ + private CipherSuite selectSuite(List suites, ProtocolVersion version) + throws IOException + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "selectSuite req:{0} suites:{1}", + new Object[] { suites, session.enabledSuites }); + boolean srpSuiteNoUser = false; + for (Iterator i = suites.iterator(); i.hasNext(); ) + { + CipherSuite herSuite = (CipherSuite) i.next(); + for (Iterator j = session.enabledSuites.iterator(); j.hasNext(); ) + { + CipherSuite mySuite = (CipherSuite) j.next(); + if (!mySuite.equals(herSuite)) + { + continue; + } + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0} == {1}", + new Object[] { mySuite, herSuite }); + if (mySuite.getSignature() != "anon" && session.keyManager != null && + session.keyManager.chooseServerAlias(mySuite.getAuthType(), null, null) == null) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "{0}: no certificate/private key", + mySuite); + continue; + } + if (mySuite.getKeyExchange() == "SRP") + { + if (session.getValue("srp-username") == null) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "no SRP username"); + srpSuiteNoUser = true; + continue; + } + if (session.srpTrustManager == null) + { + if (DEBUG_HANDSHAKE_LAYER) + logger.log (Component.SSL_HANDSHAKE, "no SRP password file"); + continue; + } + } + return mySuite.resolve(version); + } + } + Alert alert = null; + if (srpSuiteNoUser) + { + alert = new Alert(Alert.Level.WARNING, + Alert.Description.MISSING_SRP_USERNAME); + sendAlert(alert); + return null; + } + else + alert = new Alert(Alert.Level.FATAL, + Alert.Description.INSUFFICIENT_SECURITY); + sendAlert(alert); + fatal(); + throw new AlertException(alert, true); + } + + /** + * Ask the user for their user name. + * + * @param remoteHost The remote host being connected to. + * @return The user name. + */ + private String askUserName(String remoteHost) + { + CallbackHandler handler = new DefaultCallbackHandler(); + try + { + Class c = Class.forName(Util.getSecurityProperty("jessie.srp.user.handler")); + handler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) { } + TextInputCallback user = + new TextInputCallback("User name for " + remoteHost + ": ", + Util.getProperty("user.name")); + try + { + handler.handle(new Callback[] { user }); + } + catch (Exception x) { } + return user.getText(); + } + + /** + * Ask the user for a password. + * + * @param user The user name. + * @return The password. + */ + private String askPassword(String user) + { + CallbackHandler handler = new DefaultCallbackHandler(); + try + { + Class c = Class.forName(Util.getSecurityProperty("jessie.srp.password.handler")); + handler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) { } + PasswordCallback passwd = new PasswordCallback(user + "'s password: ", false); + try + { + handler.handle(new Callback[] { passwd }); + } + catch (Exception x) { } + return new String(passwd.getPassword()); + } + + /** + * Ask the user (via a callback) if they will accept a certificate that + * could not be verified. + * + * @param chain The certificate chain in question. + * @return true if the user accepts the certificate chain. + */ + private boolean checkCertificates(X509Certificate[] chain) + { + CallbackHandler handler = new DefaultCallbackHandler(); + try + { + Class c = Class.forName(Util.getSecurityProperty("jessie.certificate.handler")); + handler = (CallbackHandler) c.newInstance(); + } + catch (Exception x) + { + } + String nl = Util.getProperty("line.separator"); + ConfirmationCallback confirm = new ConfirmationCallback( + "The server's certificate could not be verified. There is no proof" + nl + + "that this server is who it claims to be, or that their certificate" + nl + + "is valid. Do you wish to continue connecting?", + ConfirmationCallback.ERROR, ConfirmationCallback.YES_NO_OPTION, + ConfirmationCallback.NO); + try + { + handler.handle(new Callback[] { confirm }); + } + catch (Exception x) + { + return false; + } + return confirm.getSelectedIndex() == ConfirmationCallback.YES; + } + + /** + * Update a signature object with a BigInteger, trimming the leading + * "00" octet if present. + * + * @param sig The signature being updated. + * @param bi The integer to feed into the signature. + */ + private void updateSig(ISignature sig, BigInteger bi) + { + byte[] buf = Util.trim(bi); + sig.update((byte) (buf.length >>> 8)); + sig.update((byte) buf.length); + sig.update(buf, 0, buf.length); + } + + /** + * Teardown everything on fatal errors. + */ + private void fatal() throws IOException + { + if (session != null) + { + session.invalidate(); + } +// recordInput.setRunning(false); +// recordOutput.setRunning(false); + if (underlyingSocket != null) + { + underlyingSocket.close(); + } + else + { + super.close(); + } + } +} diff --git a/gnu/javax/net/ssl/provider/SSLSocketFactory.java b/gnu/javax/net/ssl/provider/SSLSocketFactory.java new file mode 100644 index 000000000..24a8389c1 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLSocketFactory.java @@ -0,0 +1,133 @@ +/* SSLSocketFactory.java -- factory for SSL sockets. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.SecureRandom; + +import javax.net.ssl.X509TrustManager; +import javax.net.ssl.X509KeyManager; + +class SSLSocketFactory extends javax.net.ssl.SSLSocketFactory +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final X509TrustManager trustManager; + private final X509KeyManager keyManager; + private final SecureRandom random; + private final SessionContext sessionContext; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLSocketFactory(X509TrustManager trustManager, X509KeyManager keyManager, + SecureRandom random, SessionContext sessionContext) + { + this.trustManager = trustManager; + this.keyManager = keyManager; + this.random = random; + this.sessionContext = sessionContext; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String[] getDefaultCipherSuites() + { + return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + public String[] getSupportedCipherSuites() + { + return getDefaultCipherSuites(); + } + + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) + throws IOException + { + return setup(new SSLSocket(socket, host, port, autoClose)); + } + + public Socket createSocket() throws IOException + { + return setup(new SSLSocket()); + } + + public Socket createSocket(String host, int port) + throws IOException, UnknownHostException + { + return setup(new SSLSocket(host, port)); + } + + public Socket createSocket(String host, int port, InetAddress localAddr, int localPort) + throws IOException, UnknownHostException + { + return setup(new SSLSocket(host, port, localAddr, localPort)); + } + + public Socket createSocket(InetAddress address, int port) throws IOException + { + return setup(new SSLSocket(address, port)); + } + + public Socket createSocket(InetAddress address, int port, + InetAddress localAddr, int localPort) + throws IOException + { + return setup(new SSLSocket(address, port, localAddr, localPort)); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private SSLSocket setup(SSLSocket s) + { + s.setTrustManager(trustManager); + s.setKeyManager(keyManager); + s.setRandom(random); + s.setSessionContext(sessionContext); + s.setUseClientMode(true); + return s; + } +} diff --git a/gnu/javax/net/ssl/provider/SSLSocketInputStream.java b/gnu/javax/net/ssl/provider/SSLSocketInputStream.java new file mode 100644 index 000000000..69202ca33 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLSocketInputStream.java @@ -0,0 +1,181 @@ +/* SSLSocketInputStream.java -- InputStream for SSL sockets. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.EOFException; +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; +import javax.net.ssl.SSLException; + +class SSLSocketInputStream extends FilterInputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final SSLSocket socket; + private final boolean checkHandshake; + + // Constructors. + // ------------------------------------------------------------------------- + + SSLSocketInputStream(InputStream in, SSLSocket socket) + { + this(in, socket, true); + } + + SSLSocketInputStream(InputStream in, SSLSocket socket, boolean checkHandshake) + { + super(in); + this.socket = socket; + this.checkHandshake = checkHandshake; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int available() throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + int ret = 0; + try + { + ret = super.available(); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert (); + if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY) + { + return -1; + } + else + { + throw ae; + } + } + return ret; + } + + public int read() throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + int ret = 0; + try + { + ret = in.read(); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert (); + if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY) + { + return -1; + } + else + { + throw ae; + } + } + return ret; + } + + public int read(byte[] buf) throws IOException + { + return read(buf, 0, buf.length); + } + + public int read(byte[] buf, int off, int len) throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + if (buf == null) + { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || off + len > buf.length) + { + throw new ArrayIndexOutOfBoundsException(); + } + int ret = 0; + try + { + ret = in.read(buf, off, len); + } + catch (AlertException ae) + { + Alert alert = ae.getAlert (); + if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY) + { + return -1; + } + else + { + throw ae; + } + } + return ret; + } + + // Own methods. + // ------------------------------------------------------------------------- + + private boolean checkAlert() throws IOException + { + Alert alert = socket.checkAlert(); + if (alert == null) return false; + if (alert.getLevel().equals(Alert.Level.FATAL)) + throw new AlertException(alert, false); + if (alert.getDescription().equals(Alert.Description.CLOSE_NOTIFY)) + { + try { return (in.available() <= 0); } + catch (IOException ioe) { } + } + return false; + } +} diff --git a/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java b/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java new file mode 100644 index 000000000..fe769a85f --- /dev/null +++ b/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java @@ -0,0 +1,115 @@ +/* SSLSocketOutputStream.java -- output stream for SSL sockets. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import javax.net.ssl.SSLException; + +class SSLSocketOutputStream extends FilterOutputStream +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final SSLSocket socket; + private final boolean checkHandshake; + + // Constructor. + // ------------------------------------------------------------------------- + + SSLSocketOutputStream(OutputStream out, SSLSocket socket) + { + this(out, socket, true); + } + + SSLSocketOutputStream(OutputStream out, SSLSocket socket, + boolean checkHandshake) + { + super(out); + this.socket = socket; + this.checkHandshake = checkHandshake; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(int b) throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + checkAlert(); + out.write(b); + checkAlert(); + } + + public void write(byte[] buf) throws IOException + { + write(buf, 0, buf.length); + } + + public void write(byte[] buf, int off, int len) throws IOException + { + if (checkHandshake) + { + socket.checkHandshakeDone(); + } + if (buf == null) + throw new NullPointerException(); + if (off < 0 || len < 0 || off + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + checkAlert(); + out.write(buf, off, len); + checkAlert(); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private synchronized void checkAlert() throws SSLException + { + Alert alert = socket.checkAlert(); + if (alert == null) return; + if (alert.getLevel().equals(Alert.Level.FATAL)) + throw new AlertException(alert, false); + } +} diff --git a/gnu/javax/net/ssl/provider/SecurityParameters.java b/gnu/javax/net/ssl/provider/SecurityParameters.java new file mode 100644 index 000000000..aa06680e2 --- /dev/null +++ b/gnu/javax/net/ssl/provider/SecurityParameters.java @@ -0,0 +1,178 @@ +/* SecurityParameters.java -- SSL security parameters. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import javax.net.ssl.SSLException; + +/** + * The interface that all security parameters used by Jessie must implement. + * Security parameters handle all transforming of data, including encryption, + * authentication, and compression. + */ +interface SecurityParameters +{ + + // Methods. + // ------------------------------------------------------------------------- + + /** + * Decrypts, verifies, and inflates a fragment received. The fragment is + * just the data field of a text object, without the version, type, and + * length fields. An exception is thrown if any step fails. + * + * @param fragment The fragment being decrypted. + * @param version The version field of the received text. + * @param type The type field of the received text. + * @return The decrypted fragment. + * @throws MacException If the MAC could not be verified, or if the padding + * on the decrypted fragment is incorrect. + * @throws OverflowException If the processed text overflows the configured + * maximum fragment size. + * @throws SSLException If any other error occurs. + */ + byte[] decrypt (byte[] fragment, ProtocolVersion version, ContentType type) + throws MacException, OverflowException, SSLException; + + /** + * Deflates, authenticates, and encrypts a fragment to be sent. + * + * @param buf The fragment being encrypted. + * @param off The offset into the buffer to start at. + * @param len The number of bytes in this fragment. + * @param type The content type of this text. + * @return The encrypted fragment. + * @throws OverflowException If deflating increases the size of the fragment + * too much. + * @throws SSLException If any other error occurs. + */ + byte[] encrypt (byte[] buf, int off, int len, ContentType type) + throws OverflowException, SSLException; + + /** + * Set all crypto primitives to null, meaning that any calls + * to {@link #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)} or + * {@link #decrypt(byte[],org.metastatic.jessie.provider.ProtocolVersion,org.metastatic.jessie.provider.ContentType}) + * will perform the identity transformation. + */ + void reset(); + + /** + * Returns the version of texts being sent. + * + * @return The version. + */ + ProtocolVersion getVersion(); + + /** + * Sets the version of texts being sent. This affects the {@link + * #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)} + * method. + * + * @param version The version to set. + */ + void setVersion (ProtocolVersion version); + + /** + * Turns zlib deflating on or off. + * + * @param deflate Whether or not to deflate outgoing fragments. + */ + void setDeflating (boolean deflate); + + /** + * Turns zlib inflating on or off. + * + * @param inflate Whether or not to inflate incoming fragments. + */ + void setInflating (boolean inflate); + + /** + * Returns the maximum size that plaintext fragments may be. + * + * @return The fragment length. + */ + int getFragmentLength(); + + /** + * Sets the maximum size that plaintext fragments may be. + * + * @param fragmentLength The new fragment length. + */ + void setFragmentLength (int fragmentLength); + + /** + * Set the cipher used to decrypt incoming fragments. The parameter must be + * appropriate for the implementation. + * + * @param cipher The cipher. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setInCipher (Object cipher); + + /** + * Set the cipher used to encrypt outgoing fragments. The parameter must be + * appropriate for the implementation. + * + * @param cipher The cipher. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setOutCipher (Object cipher); + + /** + * Set the MAC used to verify incoming fragments. The parameter must be + * appropriate for the implementation. + * + * @param mac The MAC. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setInMac (Object mac); + + /** + * Set the MAC used to authenticating outgoinging fragments. The parameter + * must be appropriate for the implementation. + * + * @param mac The MAC. + * @throws ClassCastException If the argument is not appropriate for the + * implementation. + */ + void setOutMac (Object mac); +} diff --git a/gnu/javax/net/ssl/provider/ServerHello.java b/gnu/javax/net/ssl/provider/ServerHello.java new file mode 100644 index 000000000..8b7853c7f --- /dev/null +++ b/gnu/javax/net/ssl/provider/ServerHello.java @@ -0,0 +1,216 @@ +/* ServerHello.java -- SSL ServerHello message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.SSLProtocolException; + +class ServerHello implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final ProtocolVersion version; + private final Random random; + private final byte[] sessionId; + private final CipherSuite suite; + private final CompressionMethod comp; + private final List extensions; + + // Constructor. + // ------------------------------------------------------------------------- + + ServerHello(ProtocolVersion version, Random random, + byte[] sessionId, CipherSuite suite, + CompressionMethod comp) + { + this(version, random, sessionId, suite, comp, null); + } + + ServerHello(ProtocolVersion version, Random random, + byte[] sessionId, CipherSuite suite, + CompressionMethod comp, List extensions) + { + this.version = version; + this.random = random; + this.sessionId = sessionId; + this.suite = suite; + this.comp = comp; + this.extensions = extensions; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ServerHello read(InputStream in) throws IOException + { + ProtocolVersion vers = ProtocolVersion.read(in); + Random rand = Random.read(in); + byte[] id = new byte[in.read() & 0xFF]; + in.read(id); + CipherSuite suite = CipherSuite.read(in).resolve(vers); + CompressionMethod comp = CompressionMethod.read(in); + List ext = null; + if (in.available() > 0) + { + ext = new LinkedList(); + int len = (in.read() >>> 8 & 0xFF) | (in.read() & 0xFF); + int count = 0; + while (count < len) + { + Extension e = Extension.read(in); + ext.add(e); + count += e.getValue().length + 4; + } + } + return new ServerHello(vers, rand, id, suite, comp, ext); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + version.write(out); + random.write(out); + out.write(sessionId.length); + out.write(sessionId); + suite.write(out); + out.write(comp.getValue()); + if (extensions != null) + { + ByteArrayOutputStream out2 = new ByteArrayOutputStream(); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + ((Extension) i.next()).write(out2); + out.write(out2.size() >>> 8 & 0xFF); + out.write(out2.size() & 0xFF); + out2.writeTo(out); + } + } + + ProtocolVersion getVersion() + { + return version; + } + + Random getRandom() + { + return random; + } + + byte[] getSessionId() + { + return (byte[]) sessionId.clone(); + } + + CipherSuite getCipherSuite() + { + return suite; + } + + CompressionMethod getCompressionMethod() + { + return comp; + } + + List getExtensions() + { + return extensions; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" version = " + version + ";"); + BufferedReader r = new BufferedReader(new StringReader(random.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";"); + out.println(" cipherSuite = " + suite + ";"); + out.println(" compressionMethod = " + comp + ";"); + if (extensions != null) + { + out.println(" extensions = {"); + for (Iterator i = extensions.iterator(); i.hasNext(); ) + { + r = new BufferedReader(new StringReader(i.next().toString())); + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println(" };"); + } + out.println("} ServerHello;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/ServerKeyExchange.java b/gnu/javax/net/ssl/provider/ServerKeyExchange.java new file mode 100644 index 000000000..583041593 --- /dev/null +++ b/gnu/javax/net/ssl/provider/ServerKeyExchange.java @@ -0,0 +1,286 @@ +/* ServerKeyExchange.java -- SSL ServerKeyExchange message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; + +import java.math.BigInteger; + +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; + +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; + +import javax.net.ssl.SSLProtocolException; + +import gnu.javax.crypto.key.dh.GnuDHPublicKey; +import gnu.javax.crypto.key.srp6.SRPPublicKey; + +class ServerKeyExchange implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private PublicKey publicKey; + private Signature signature; + private byte[] srpSalt; + + // Constructor. + // ------------------------------------------------------------------------- + + ServerKeyExchange(PublicKey publicKey, Signature signature) + { + this(publicKey, signature, null); + } + + ServerKeyExchange(PublicKey publicKey, Signature signature, byte[] srpSalt) + { + this.publicKey = publicKey; + this.signature = signature; + this.srpSalt = srpSalt; + } + + // Class methods. + // ------------------------------------------------------------------------- + + static ServerKeyExchange read(InputStream in, CipherSuite suite, + PublicKey serverKey) + throws IOException + { + DataInputStream din = new DataInputStream(in); + PublicKey key = null; + byte[] salt = null; + String kex = suite.getKeyExchange(); + if (kex.equals("DHE")) + { + BigInteger p, g, y; + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + p = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + g = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + y = new BigInteger(1, buf); + key = new GnuDHPublicKey(null, p, g, y); + } + else if (kex.equals("RSA")) + { + BigInteger n, e; + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + n = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + e = new BigInteger(1, buf); + key = new JessieRSAPublicKey(n, e); + } + else if (kex.equals("SRP")) + { + BigInteger N, g, B; + byte[] buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + N = new BigInteger(1, buf); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + g = new BigInteger(1, buf); + salt = new byte[din.readUnsignedByte()]; + din.readFully(salt); + buf = new byte[din.readUnsignedShort()]; + din.readFully(buf); + B = new BigInteger(1, buf); + try + { + key = new SRPPublicKey(N, g, B); + } + catch (IllegalArgumentException iae) + { + throw new SSLProtocolException(iae.getMessage()); + } + } + else + { + throw new SSLProtocolException("invalid kex algorithm"); + } + + Signature sig = null; + if (!suite.getSignature().equals("anon")) + { + sig = Signature.read(in, suite, serverKey); + } + return new ServerKeyExchange(key, sig, salt); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + write(out, ProtocolVersion.TLS_1); + } + + public void write(OutputStream out, ProtocolVersion version) + throws IOException + { + if (publicKey instanceof DHPublicKey) + { + writeBigint(out, ((DHPublicKey) publicKey).getParams().getP()); + writeBigint(out, ((DHPublicKey) publicKey).getParams().getG()); + writeBigint(out, ((DHPublicKey) publicKey).getY()); + } + else if (publicKey instanceof RSAPublicKey) + { + writeBigint(out, ((RSAPublicKey) publicKey).getModulus()); + writeBigint(out, ((RSAPublicKey) publicKey).getPublicExponent()); + } + else if (publicKey instanceof SRPPublicKey) + { + writeBigint(out, ((SRPPublicKey) publicKey).getN()); + writeBigint(out, ((SRPPublicKey) publicKey).getG()); + out.write(srpSalt.length); + out.write(srpSalt); + writeBigint(out, ((SRPPublicKey) publicKey).getY()); + } + if (signature != null) + { + signature.write(out, version); + } + } + + PublicKey getPublicKey() + { + return publicKey; + } + + Signature getSignature() + { + return signature; + } + + byte[] getSRPSalt() + { + return srpSalt; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + out.println(" publicKey = struct {"); + if (publicKey instanceof DHPublicKey) + { + out.println(" p = " + + ((DHPublicKey) publicKey).getParams().getP().toString(16) + + ";"); + out.println(" g = " + + ((DHPublicKey) publicKey).getParams().getG().toString(16) + + ";"); + out.println(" y = " + ((DHPublicKey) publicKey).getY().toString(16) + + ";"); + out.println(" } DHPublicKey;"); + } + else if (publicKey instanceof RSAPublicKey) + { + out.println(" modulus = " + + ((RSAPublicKey) publicKey).getModulus().toString(16) + + ";"); + out.println(" exponent = " + + ((RSAPublicKey) publicKey).getPublicExponent().toString(16) + + ";"); + out.println(" } RSAPublicKey;"); + } + else if (publicKey instanceof SRPPublicKey) + { + out.println(" N = "+((SRPPublicKey) publicKey).getN().toString(16)+";"); + out.println(" g = "+((SRPPublicKey) publicKey).getG().toString(16)+";"); + out.println(" salt = " + Util.toHexString(srpSalt, ':') + ";"); + out.println(" B = "+((SRPPublicKey) publicKey).getY().toString(16)+";"); + out.println(" } SRPPublicKey;"); + } + if (signature != null) + { + out.println(" signature ="); + BufferedReader r = new BufferedReader(new StringReader(signature.toString())); + String s; + try + { + while ((s = r.readLine()) != null) + { + out.print(" "); + out.println(s); + } + } + catch (IOException ignored) + { + } + } + out.println("} ServerKeyExchange;"); + return str.toString(); + } + + private void writeBigint(OutputStream out, BigInteger bigint) + throws IOException + { + byte[] b = bigint.toByteArray(); + if (b[0] == 0x00) + { + out.write((b.length - 1) >>> 8 & 0xFF); + out.write((b.length - 1) & 0xFF); + out.write(b, 1, b.length - 1); + } + else + { + out.write(b.length >>> 8 & 0xFF); + out.write(b.length & 0xFF); + out.write(b); + } + } +} diff --git a/gnu/javax/net/ssl/provider/Session.java b/gnu/javax/net/ssl/provider/Session.java new file mode 100644 index 000000000..e13758b03 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Session.java @@ -0,0 +1,381 @@ +/* Session.java -- SSL and TLS session data. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLPermission; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionBindingEvent; +import javax.net.ssl.SSLSessionBindingListener; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.X509KeyManager; +import javax.net.ssl.X509TrustManager; +import javax.security.cert.X509Certificate; + +import gnu.javax.net.ssl.SRPTrustManager; + +/** + * A generic SSL session implementation for SSL and TLS. + */ +final class Session implements SSLSession +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final SSLPermission GET_SESSION_CONTEXT_PERMISSION = + new SSLPermission("getSSLSessionContext"); + + private final long creationTime; + private Date lastAccessedTime; + ID sessionId; + Certificate[] localCerts; + Certificate[] peerCerts; + X509Certificate[] peerCertChain; + String peerHost; + boolean peerVerified; + SessionContext context; + HashMap values; + boolean valid; + List enabledSuites; + CipherSuite cipherSuite; + SortedSet enabledProtocols; + ProtocolVersion protocol; + byte[] masterSecret; + SRPTrustManager srpTrustManager; + X509TrustManager trustManager; + X509KeyManager keyManager; + SecureRandom random; + SecurityParameters params; + Alert currentAlert; + + // Constructor. + // ------------------------------------------------------------------------- + + Session() + { + this(System.currentTimeMillis()); + } + + Session(long creationTime) + { + peerVerified = false; + valid = true; + this.creationTime = creationTime; + lastAccessedTime = new Date(0L); + values = new HashMap(); + if (("true").equalsIgnoreCase (Util.getSecurityProperty ("jessie.with.jce"))) + params = new JCESecurityParameters(); + else + params = new GNUSecurityParameters (this); + } + + // Public instance methods. + // ------------------------------------------------------------------------- + + protected Object clone() + { + Session result = new Session(creationTime); + result.lastAccessedTime = lastAccessedTime; + result.sessionId = sessionId; + result.localCerts = (localCerts != null ? (Certificate[]) localCerts.clone() : null); + result.peerCerts = (peerCerts != null ? (Certificate[]) peerCerts.clone() : null); + result.peerHost = peerHost; + result.peerVerified = peerVerified; + result.context = context; + result.values = values; + result.enabledSuites = new ArrayList(enabledSuites); + result.cipherSuite = cipherSuite; + result.enabledProtocols = new TreeSet(enabledProtocols); + result.protocol = protocol; + result.masterSecret = masterSecret; + result.keyManager = keyManager; + result.srpTrustManager = srpTrustManager; + result.trustManager = trustManager; + result.random = random; + return result; + } + + public String getCipherSuite() + { + return cipherSuite.toString(); + } + + public long getCreationTime() + { + return creationTime; + } + + public byte[] getId() + { + return (sessionId != null ? sessionId.getId() : null); + } + + public long getLastAccessedTime() + { + return lastAccessedTime.getTime(); + } + + public Certificate[] getLocalCertificates() + { + return (Certificate[]) (localCerts != null ? localCerts.clone() : null); + } + + public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException + { + if (!peerVerified) + { + throw new SSLPeerUnverifiedException("peer not verified"); + } + return (Certificate[]) (peerCerts != null ? peerCerts.clone() : null); + } + + public X509Certificate[] getPeerCertificateChain() + throws SSLPeerUnverifiedException + { + if (!peerVerified) + { + throw new SSLPeerUnverifiedException("peer not verified"); + } + if (peerCerts == null) + { + return null; + } + if (peerCertChain != null) + { + return (X509Certificate[]) peerCertChain.clone(); + } + try + { + peerCertChain = new X509Certificate[peerCerts.length]; + for (int i = 0; i < peerCerts.length; i++) + { + peerCertChain[i] = X509Certificate.getInstance(peerCerts[i].getEncoded()); + } + return (X509Certificate[]) peerCertChain.clone(); + } + catch (javax.security.cert.CertificateException ce) + { + return null; + } + catch (CertificateException ce2) + { + return null; + } + } + + public String getPeerHost() + { + return peerHost; + } + + public String getProtocol() + { + return protocol.toString(); + } + + public SSLSessionContext getSessionContext() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + sm.checkPermission(GET_SESSION_CONTEXT_PERMISSION); + } + return context; + } + + public String[] getValueNames() + { + Set names = values.keySet(); + return (String[]) names.toArray(new String[names.size()]); + } + + public Object getValue(String name) + { + return values.get(name); + } + + public void putValue(String name, Object value) + { + values.put(name, value); + if (value instanceof SSLSessionBindingListener) + { + ((SSLSessionBindingListener) value).valueBound( + new SSLSessionBindingEvent(this, name)); + } + } + + public void removeValue(String name) + { + Object value = values.remove(name); + if (value != null && (value instanceof SSLSessionBindingListener)) + { + ((SSLSessionBindingListener) value).valueUnbound( + new SSLSessionBindingEvent(this, name)); + } + } + + public void invalidate() + { + if (masterSecret != null) + { + for (int i = 0; i < masterSecret.length; i++) + { + masterSecret[i] = 0; + } + masterSecret = null; + } + valid = false; + } + + synchronized void access() + { + lastAccessedTime.setTime(System.currentTimeMillis()); + context.notifyAccess(this); + } + + void setLastAccessedTime(long lastAccessedTime) + { + this.lastAccessedTime.setTime(lastAccessedTime); + } + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * A byte array with appropriate equals(), + * hashCode(), and compareTo() semantics. + */ + static final class ID implements Comparable + { + + // Fields. + // ----------------------------------------------------------------------- + + /** The ID itself. */ + private final byte[] id; + + // Constructor. + // ----------------------------------------------------------------------- + + /** + * Creates a new ID. + * + * @param id The ID. The array is not cloned. + */ + ID(byte[] id) + { + if (id == null) + { + throw new IllegalArgumentException(); + } + this.id = id; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getId() + { + return (byte[]) id.clone(); + } + + public boolean equals(Object other) + { + if (other == null || !(other instanceof ID)) + { + return false; + } + return Arrays.equals(id, ((ID) other).id); + } + + public int hashCode() + { + int code = 0; + for (int i = 0; i < id.length; i++) + { + code |= (id[i] & 0xFF) << ((i & 3) << 3); + } + return code; + } + + public int compareTo(Object other) + { + if (other == null || !(other instanceof ID)) + { + return 1; + } + byte[] id2 = ((ID) other).id; + if (id.length != id2.length) + { + return (id.length < id2.length) ? -1 : 1; + } + for (int i = 0; i < id.length; i++) + { + if (id[i] < id2[i]) + { + return -1; + } + else if (id[i] > id2[i]) + { + return 1; + } + } + return 0; + } + + public String toString() + { + return Util.toHexString(id, ':'); + } + } +} diff --git a/gnu/javax/net/ssl/provider/SessionContext.java b/gnu/javax/net/ssl/provider/SessionContext.java new file mode 100644 index 000000000..9e265429a --- /dev/null +++ b/gnu/javax/net/ssl/provider/SessionContext.java @@ -0,0 +1,250 @@ +/* SessionContext.java -- Implementation of a session context. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.security.Security; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Vector; + +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; + +/** + * A collection of SSL sessions. This implementation is a memory-only + * store; subclasses may implement persistent storage. + */ +class SessionContext implements SSLSessionContext +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** The map of Session.ID objects to Sessions. */ + protected final HashMap sessions; + + /** The number of sessions to cache. */ + protected int cacheSize; + + /** The session timeout, in seconds. */ + protected int timeout; + + // Constructor. + // ------------------------------------------------------------------------- + + SessionContext() + { + sessions = new HashMap(); + cacheSize = 0; + try + { + timeout = Integer.parseInt(Util.getSecurityProperty("jessie.session.timeout")); + } + catch (Exception x) + { + // Default 24-hour timeout. + timeout = 86400; + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public synchronized Enumeration getIds() + { + Vector ids = new Vector(); + for(Iterator i = sessions.keySet().iterator(); i.hasNext(); ) + { + Session.ID id = (Session.ID) i.next(); + ids.add(id.getId()); + } + return ids.elements(); + } + + public synchronized SSLSession getSession(byte[] sessionId) + { + Session session = (Session) sessions.get(new Session.ID(sessionId)); + if (session == null) + return null; + long elapsed = System.currentTimeMillis() - session.getLastAccessedTime(); + if ((int) (elapsed / 1000) > timeout) + { + removeSession(session.sessionId); + session.invalidate(); + return null; + } + if (!session.valid) + { + removeSession(session.sessionId); + session.invalidate(); + return null; + } + return session; + } + + public int getSessionCacheSize() + { + return cacheSize; + } + + public void setSessionCacheSize(int cacheSize) + { + if (cacheSize < 0) + throw new IllegalArgumentException(); + this.cacheSize = cacheSize; + } + + public int getSessionTimeout() + { + return timeout; + } + + public void setSessionTimeout(int timeout) + { + if (timeout <= 0) + throw new IllegalArgumentException(); + this.timeout = timeout; + } + + public String toString() + { + return sessions.keySet().toString(); + } + + // Package methods. + // ------------------------------------------------------------------------- + + /** + * Adds a session to this context. This method: + * + *
      + *
    1. Will do nothing if the cache already contains the given ID.
    2. + *
    3. Will do nothing if the cache limit has been reached (and is + * not zero).
    4. + *
    5. Will remove any invalid sessions in the cache before trying to insert + * the new one.
    6. + *
    7. Will remove any expired sessions before trying to insert the new + * one.
    8. + *
    + * + * @param sessionId This session's ID. + * @param session The session to add. + * @return True if the session was added, false otherwise. + */ + synchronized boolean addSession(Session.ID sessionId, Session session) + { + if (sessions.containsKey(sessionId)) + return false; + if (cacheSize > 0 && sessions.size() > cacheSize) + { + boolean removed = false; + for (Iterator i = sessions.values().iterator(); i.hasNext(); ) + { + Session s = (Session) i.next(); + long elapsed = System.currentTimeMillis() - s.getCreationTime(); + if (!s.valid) + { + removeSession(session.sessionId); + removed = true; + } + else if ((int) (elapsed / 1000) > timeout) + { + removeSession(session.sessionId); + removed = true; + } + } + if (removed) + { + sessions.put(sessionId, session); + session.context = this; + session.sessionId = sessionId; + return true; + } + return false; + } + else + { + sessions.put(sessionId, session); + session.context = this; + session.sessionId = sessionId; + return true; + } + } + + /** + * Returns whether or not a session with the given ID is cached by this + * context. + */ + synchronized boolean containsSessionID(Session.ID sessionId) + { + Session s = (Session) sessions.get(sessionId); + if (s == null) + { + return false; + } + long elapsed = System.currentTimeMillis() - s.getCreationTime(); + if (!s.valid || (int) (elapsed / 1000) > timeout) + { + removeSession(sessionId); + return false; + } + return true; + } + + /** + * Removes a session from this context. + * + * @param sessionId The ID of the session to remove. + */ + synchronized boolean removeSession(Session.ID sessionId) + { + return sessions.remove(sessionId) != null; + } + + /** + * Notifies this context of an access event on a session. + * + * @param session The session that was accessed. + */ + void notifyAccess(Session session) + { + } +} diff --git a/gnu/javax/net/ssl/provider/Signature.java b/gnu/javax/net/ssl/provider/Signature.java new file mode 100644 index 000000000..c9be64143 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Signature.java @@ -0,0 +1,158 @@ +/* Signature.java -- SSL signature message. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.math.BigInteger; + +import java.security.PublicKey; +import java.security.interfaces.RSAKey; + +import java.util.Arrays; + +import gnu.java.security.der.*; + +class Signature implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Object sigValue; + private final String sigAlg; + + // Constructor. + // ------------------------------------------------------------------------- + + Signature(Object sigValue, String sigAlg) + { + this.sigValue = sigValue; + this.sigAlg = sigAlg; + } + + // Class method. + // ------------------------------------------------------------------------- + + static Signature read(InputStream in, CipherSuite suite, PublicKey key) + throws IOException + { + Object sigValue = null; + DataInputStream din = new DataInputStream(in); + int len = din.readUnsignedShort(); + sigValue = new byte[len]; + din.readFully((byte[]) sigValue); + if (suite.getSignature() == "DSS") + { + DERReader der = new DERReader(new ByteArrayInputStream((byte[]) sigValue)); + if (der.read().getTag() != DER.SEQUENCE) + { + throw new IOException("expecting DER SEQUENCE"); + } + BigInteger r = (BigInteger) der.read().getValue(); + BigInteger s = (BigInteger) der.read().getValue(); + sigValue = new BigInteger[] { r, s }; + } + return new Signature(sigValue, suite.getSignature()); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void write(OutputStream out) throws IOException + { + write(out, ProtocolVersion.TLS_1); + } + + public void write(OutputStream out, ProtocolVersion version) + throws IOException + { + byte[] result = null; + if (sigValue instanceof byte[]) + { + result = (byte[]) sigValue; + } + else + { + DERValue r = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[0]); + DERValue s = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[1]); + DERValue sig = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, + Arrays.asList(new Object[] { r, s })); + result = sig.getEncoded(); + } + out.write(result.length >>> 8 & 0xFF); + out.write(result.length & 0xFF); + out.write(result); + } + + Object getSigValue() + { + return sigValue; + } + + String getSigAlg() + { + return sigAlg; + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println("struct {"); + if (sigAlg.equals("RSA")) + { + out.print(Util.hexDump((byte[]) sigValue, " ")); + } + else + { + out.println(" r = " + ((BigInteger[]) sigValue)[0].toString(16) + ";"); + out.println(" s = " + ((BigInteger[]) sigValue)[1].toString(16) + ";"); + } + out.println("} Signature;"); + return str.toString(); + } +} diff --git a/gnu/javax/net/ssl/provider/SynchronizedRandom.java b/gnu/javax/net/ssl/provider/SynchronizedRandom.java new file mode 100644 index 000000000..4e22f08be --- /dev/null +++ b/gnu/javax/net/ssl/provider/SynchronizedRandom.java @@ -0,0 +1,104 @@ +/* SynchronizedRandom.java -- Thread-safe IRandom wrapper. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.util.Map; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +class SynchronizedRandom implements IRandom +{ + + // Field. + // ------------------------------------------------------------------------- + + private final IRandom random; + + // Constructor. + // ------------------------------------------------------------------------- + + SynchronizedRandom(IRandom random) + { + this.random = random; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String name() + { + return random.name(); + } + + public synchronized void init(Map attrib) + { + random.init(attrib); + } + + public synchronized byte nextByte() + throws IllegalStateException, LimitReachedException + { + return random.nextByte(); + } + + public synchronized void nextBytes(byte[] buf, int off, int len) + throws IllegalStateException, LimitReachedException + { + random.nextBytes(buf, off, len); + } + + public synchronized Object clone() + throws CloneNotSupportedException + { + return new SynchronizedRandom((IRandom) random.clone()); + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } +} diff --git a/gnu/javax/net/ssl/provider/TLSHMac.java b/gnu/javax/net/ssl/provider/TLSHMac.java new file mode 100644 index 000000000..18aa8f5f4 --- /dev/null +++ b/gnu/javax/net/ssl/provider/TLSHMac.java @@ -0,0 +1,138 @@ +/* TLSHMac.java -- HMAC used in TLS. + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +import gnu.java.security.hash.IMessageDigest; +import gnu.javax.crypto.mac.HMac; + +/** + * The operation of this HMac is identical to normal HMacs, but this one + * allows keys with short lengths (including zero). + */ +class TLSHMac extends HMac +{ + + // Constants. + // ------------------------------------------------------------------------- + + private static final byte IPAD_BYTE = 0x36; + private static final byte OPAD_BYTE = 0x5C; + + // Constructor. + // ------------------------------------------------------------------------- + + TLSHMac(IMessageDigest hash) + { + super(hash); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void init(Map attributes) + throws InvalidKeyException, IllegalStateException + { + Integer ts = (Integer) attributes.get(TRUNCATED_SIZE); + truncatedSize = (ts == null ? macSize : ts.intValue()); + if (truncatedSize < (macSize / 2)) { + throw new IllegalArgumentException("Truncated size too small"); + } else if (truncatedSize < 10) { + throw new IllegalArgumentException("Truncated size less than 80 bits"); + } + + // we dont use/save the key outside this method + byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL); + if (K == null) { // take it as an indication to re-use previous key if set + if (ipadHash == null) + { + throw new InvalidKeyException("Null key"); + } + // we already went through the motions; ie. up to step #4. re-use + underlyingHash = (IMessageDigest) ipadHash.clone(); + return; + } + + if (K.length > blockSize) + { + // (0) replace K with HASH(K) if K is larger than the hash's + // block size. Then pad with zeros until it is the correct + // size (the next `if'). + underlyingHash.update(K, 0, K.length); + K = underlyingHash.digest(); + } + if (K.length < blockSize) + { + // (1) append zeros to the end of K to create a B byte string + // (e.g., if K is of length 20 bytes and B=64, then K will be + // appended with 44 zero bytes 0x00) + int limit = (K.length > blockSize) ? blockSize : K.length; + byte[] newK = new byte[blockSize]; + System.arraycopy(K, 0, newK, 0, limit); + K = newK; + } + + underlyingHash.reset(); + opadHash = (IMessageDigest) underlyingHash.clone(); + if (ipad == null) + { + ipad = new byte[blockSize]; + } + // (2) XOR (bitwise exclusive-OR) the B byte string computed in step + // (1) with ipad + // (3) append the stream of data 'text' to the B byte string resulting + // from step (2) + // (4) apply H to the stream generated in step (3) + for (int i = 0; i < blockSize; i++) + { + ipad[i] = (byte)(K[i] ^ IPAD_BYTE); + } + for (int i = 0; i < blockSize; i++) + { + opadHash.update((byte)(K[i] ^ OPAD_BYTE)); + } + + underlyingHash.update(ipad, 0, blockSize); + ipadHash = (IMessageDigest) underlyingHash.clone(); + K = null; + } +} diff --git a/gnu/javax/net/ssl/provider/TLSRandom.java b/gnu/javax/net/ssl/provider/TLSRandom.java new file mode 100644 index 000000000..ded632928 --- /dev/null +++ b/gnu/javax/net/ssl/provider/TLSRandom.java @@ -0,0 +1,252 @@ +/* TLSRandom.java -- The TLS pseudo-random function. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.security.InvalidKeyException; +import java.util.HashMap; +import java.util.Map; + +import gnu.java.security.hash.HashFactory; +import gnu.javax.crypto.mac.IMac; +import gnu.java.security.prng.IRandom; + +class TLSRandom implements IRandom +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** + * Property name for the secret that will be used to initialize the HMACs. + */ + static final String SECRET = "jessie.tls.prng.secret"; + + /** + * Property name for the seed. + */ + static final String SEED = "jessie.tls.prng.seed"; + + private final IMac hmac_sha, hmac_md5; + private byte[] sha_a, md5_a; + private byte[] seed; + private final byte[] buffer; + private int idx; + private boolean init; + + // Constructors. + // ------------------------------------------------------------------------- + + TLSRandom() + { + hmac_sha = new TLSHMac(HashFactory.getInstance("SHA1")); + hmac_md5 = new TLSHMac(HashFactory.getInstance("MD5")); + buffer = new byte[80]; // 80 == LCM of 16 and 20. + idx = 0; + init = false; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException shouldNotHappen) + { + throw new Error(); + } + } + + public void init(Map attributes) + { + HashMap sha_attr = new HashMap(); + HashMap md5_attr = new HashMap(); + byte[] secret = (byte[]) attributes.get(SECRET); + if (secret != null) + { + int l = (secret.length >>> 1) + (secret.length & 1); + byte[] s1 = Util.trim(secret, 0, l); + byte[] s2 = Util.trim(secret, secret.length - l, l); + md5_attr.put(IMac.MAC_KEY_MATERIAL, s1); + sha_attr.put(IMac.MAC_KEY_MATERIAL, s2); + try + { + hmac_md5.init(md5_attr); + hmac_sha.init(sha_attr); + } + catch (InvalidKeyException ike) + { + throw new Error(ike.toString()); + } + } + else if (!init) + { + throw new IllegalArgumentException("no secret supplied"); + } + // else re-use + + byte[] seeed = (byte[]) attributes.get(SEED); + if (seeed != null) + { + seed = (byte[]) seeed.clone(); + } + else if (!init) + { + throw new IllegalArgumentException("no seed supplied"); + } + // else re-use + + // A(0) is the seed, A(1) = HMAC_hash(secret, A(0)). + hmac_md5.update(seed, 0, seed.length); + md5_a = hmac_md5.digest(); + hmac_md5.reset(); + hmac_sha.update(seed, 0, seed.length); + sha_a = hmac_sha.digest(); + hmac_sha.reset(); + fillBuffer(); + init = true; + } + + public String name() + { + return "TLSRandom"; + } + + public byte nextByte() + { + if (!init) + throw new IllegalStateException(); + if (idx >= buffer.length) + fillBuffer(); + return buffer[idx++]; + } + + public void nextBytes(byte[] buf, int off, int len) + { + if (!init) + throw new IllegalStateException(); + if (buf == null) + throw new NullPointerException(); + if (off < 0 || off > buf.length || off + len > buf.length) + throw new ArrayIndexOutOfBoundsException(); + int count = 0; + if (idx >= buffer.length) + fillBuffer(); + while (count < len) + { + int l = Math.min(buffer.length-idx, len-count); + System.arraycopy(buffer, idx, buf, off+count, l); + idx += l; + count += l; + if (count < len && idx >= buffer.length) + fillBuffer(); + } + } + + // For future versions of GNU Crypto. No-ops. + public void addRandomByte (byte b) + { + } + + public void addRandomBytes(byte[] buffer) { + addRandomBytes(buffer, 0, buffer.length); + } + + public void addRandomBytes (byte[] b, int i, int j) + { + } + + // Own methods. + // ------------------------------------------------------------------------- + + /* + * The PRF is defined as: + * + * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR + * P_SHA-1(S2, label + seed); + * + * P_hash is defined as: + * + * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + + * HMAC_hash(secret, A(2) + seed) + + * HMAC_hash(secret, A(3) + seed) + ... + * + * And A() is defined as: + * + * A(0) = seed + * A(i) = HMAC_hash(secret, A(i-1)) + * + * For simplicity, we compute an 80-byte block on each call, which + * corresponds to five iterations of MD5, and four of SHA-1. + */ + private synchronized void fillBuffer() + { + int len = hmac_md5.macSize(); + for (int i = 0; i < buffer.length; i += len) + { + hmac_md5.update(md5_a, 0, md5_a.length); + hmac_md5.update(seed, 0, seed.length); + byte[] b = hmac_md5.digest(); + hmac_md5.reset(); + System.arraycopy(b, 0, buffer, i, len); + hmac_md5.update(md5_a, 0, md5_a.length); + md5_a = hmac_md5.digest(); + hmac_md5.reset(); + } + len = hmac_sha.macSize(); + for (int i = 0; i < buffer.length; i += len) + { + hmac_sha.update(sha_a, 0, sha_a.length); + hmac_sha.update(seed, 0, seed.length); + byte[] b = hmac_sha.digest(); + hmac_sha.reset(); + for (int j = 0; j < len; j++) + { + buffer[j + i] ^= b[j]; + } + hmac_sha.update(sha_a, 0, sha_a.length); + sha_a = hmac_sha.digest(); + hmac_sha.reset(); + } + idx = 0; + } +} diff --git a/gnu/javax/net/ssl/provider/Util.java b/gnu/javax/net/ssl/provider/Util.java new file mode 100644 index 000000000..15790dd26 --- /dev/null +++ b/gnu/javax/net/ssl/provider/Util.java @@ -0,0 +1,422 @@ +/* Util.java -- Miscellaneous utility methods. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Security; + +/** + * A collection of useful class methods. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +final class Util +{ + + // Constants. + // ------------------------------------------------------------------------- + + static final String HEX = "0123456789abcdef"; + + // Static methods only. + private Util() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Convert a hexadecimal string into its byte representation. + * + * @param hex The hexadecimal string. + * @return The converted bytes. + */ + static byte[] toByteArray(String hex) + { + hex = hex.toLowerCase(); + byte[] buf = new byte[hex.length() / 2]; + int j = 0; + for (int i = 0; i < buf.length; i++) + { + buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) | + Character.digit(hex.charAt(j++), 16)); + } + return buf; + } + + /** + * Convert a byte array to a hexadecimal string, as though it were a + * big-endian arbitrarily-sized integer. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @return A hexadecimal representation of the specified bytes. + */ + static String toHexString(byte[] buf, int off, int len) + { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int)}. + */ + static String toHexString(byte[] buf) + { + return Util.toHexString(buf, 0, buf.length); + } + + /** + * Convert a byte array to a hexadecimal string, separating octets + * with the given character. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @param sep The character to insert between octets. + * @return A hexadecimal representation of the specified bytes. + */ + static String toHexString(byte[] buf, int off, int len, char sep) + { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + if (i < len - 1) + str.append(sep); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int,char)}. + */ + static String toHexString(byte[] buf, char sep) + { + return Util.toHexString(buf, 0, buf.length, sep); + } + + /** + * Create a representation of the given byte array similar to the + * output of `hexdump -C', which is + * + *

    OFFSET  SIXTEEN-BYTES-IN-HEX  PRINTABLE-BYTES
    + * + *

    The printable bytes show up as-is if they are printable and + * not a newline character, otherwise showing as '.'. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to encode. + * @param prefix A string to prepend to every line. + * @return The formatted string. + */ + static String hexDump(byte[] buf, int off, int len, String prefix) + { + String nl = getProperty("line.separator"); + StringBuffer str = new StringBuffer(); + int i = 0; + while (i < len) + { + if (prefix != null) + str.append(prefix); + str.append(Util.formatInt(i+off, 16, 8)); + str.append(" "); + String s = Util.toHexString(buf, i+off, Math.min(16, len-i), ' '); + str.append(s); + for (int j = 56 - (56 - s.length()); j < 56; j++) + str.append(" "); + for (int j = 0; j < Math.min(16, len - i); j++) + { + if ((buf[i+off+j] & 0xFF) < 0x20 || (buf[i+off+j] & 0xFF) > 0x7E) + str.append('.'); + else + str.append((char) (buf[i+off+j] & 0xFF)); + } + str.append(nl); + i += 16; + } + return str.toString(); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + static String hexDump(byte[] buf, int off, int len) + { + return hexDump(buf, off, len, ""); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + static String hexDump(byte[] buf, String prefix) + { + return hexDump(buf, 0, buf.length, prefix); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + static String hexDump(byte[] buf) + { + return hexDump(buf, 0, buf.length); + } + + /** + * Format an integer into the specified radix, zero-filled. + * + * @param i The integer to format. + * @param radix The radix to encode to. + * @param len The target length of the string. The string is + * zero-padded to this length, but may be longer. + * @return The formatted integer. + */ + static String formatInt(int i, int radix, int len) + { + String s = Integer.toString(i, radix); + StringBuffer buf = new StringBuffer(); + for (int j = 0; j < len - s.length(); j++) + buf.append("0"); + buf.append(s); + return buf.toString(); + } + + /** + * Concatenate two byte arrays into one. + * + * @param b1 The first byte array. + * @param b2 The second byte array. + * @return The concatenation of b1 and b2. + */ + static byte[] concat(byte[] b1, byte[] b2) + { + byte[] b3 = new byte[b1.length+b2.length]; + System.arraycopy(b1, 0, b3, 0, b1.length); + System.arraycopy(b2, 0, b3, b1.length, b2.length); + return b3; + } + + /** + * See {@link #trim(byte[],int,int)}. + */ + static byte[] trim(byte[] buffer, int len) + { + return trim(buffer, 0, len); + } + + /** + * Returns a portion of a byte array, possibly zero-filled. + * + * @param buffer The byte array to trim. + * @param off The offset to begin reading at. + * @param len The number of bytes to return. This value can be larger + * than buffer.length - off, in which case the rest of the + * returned byte array will be filled with zeros. + * @throws IndexOutOfBoundsException If off or len is + * negative, or if off is larger than the byte array's + * length. + * @return The trimmed byte array. + */ + static byte[] trim(byte[] buffer, int off, int len) + { + if (off < 0 || len < 0 || off > buffer.length) + throw new IndexOutOfBoundsException("max=" + buffer.length + + " off=" + off + " len=" + len); + if (off == 0 && len == buffer.length) + return buffer; + byte[] b = new byte[len]; + System.arraycopy(buffer, off, b, 0, Math.min(len, buffer.length - off)); + return b; + } + + /** + * Returns the byte array representation of the given big integer with + * the leading zero byte (if any) trimmed off. + * + * @param bi The integer to trim. + * @return The byte representation of the big integer, with any leading + * zero removed. + */ + static byte[] trim(BigInteger bi) + { + byte[] buf = bi.toByteArray(); + if (buf[0] == 0x00 && !bi.equals(BigInteger.ZERO)) + { + return trim(buf, 1, buf.length - 1); + } + else + { + return buf; + } + } + + /** + * Returns the integer value of {@link + * java.lang.System#currentTimeMillis()} / 1000. + * + * @return The current time, in seconds. + */ + static int unixTime() + { + return (int) (System.currentTimeMillis() / 1000L); + } + + /** + * Transform an Object array into another by calling the given method + * on each object. The returned object array will have the runtime + * type of returnType. For example, the following will transform + * array of objects into their String representations, returning a String + * array. For example: + * + *

    + * String[] strings = (String[]) Util.transform(array, String.class, + * "toString", null); + *

    + * + *

    If any element of the given array is null, then that + * entry in the returned array will also be null. + * + * @param array The array to transform. It does not need to be of + * uniform type. + * @param returnType The desired return type of the returned array. + * This must by the component type, not the array type. + * @param method The name of the method to invoke from each object. + * @param args The arguments to pass to the method, or null + * if the method takes no arguments. + * @throws InvocationTargetException If an exception occurs while + * calling method of any object. + * @throws NoSuchMethodException If method is not the name of + * a valid method of any component of the array. + * @throws ClassCastException If the returned object from the method + * is not assignable to the return type. + * @throws IllegalArgumentException If args is not appropriate + * for method + * @throws IllegalAccessException If method is not accessible. + * @throws SecurityException If method is not accessible. + * @return An array containing the output of method called on + * each element of array with args. The return type + * of the array will be an array of returnType. + */ + static Object[] transform(Object[] array, Class returnType, + String method, Object[] args) + throws InvocationTargetException, NoSuchMethodException, + IllegalAccessException + { + if (args == null) + args = new Object[0]; + Object[] result = (Object[]) Array.newInstance(returnType, array.length); + Class[] argsClasses = new Class[args.length]; + for (int i = 0; i < args.length; i++) + { + argsClasses[i] = args[i].getClass(); + } + for (int i = 0; i < array.length; i++) + { + if (array[i] == null) + { + result[i] = null; + continue; + } + Class objClass = array[i].getClass(); + Method objMethod = objClass.getMethod(method, argsClasses); + Object o = objMethod.invoke(array[i], args); + if (!returnType.isAssignableFrom(o.getClass())) + throw new ClassCastException(); + result[i] = o; + } + return result; + } + + /** + * Get a system property as a privileged action. + * + * @param name The name of the property to get. + * @return The property named name, or null if the property is + * not set. + * @throws SecurityException If the Jessie code still does not have + * permission to read the property. + */ + static String getProperty(final String name) + { + return (String) AccessController.doPrivileged( + new PrivilegedAction() + { + public Object run() + { + return System.getProperty(name); + } + } + ); + } + + /** + * Get a security property as a privileged action. + * + * @param name The name of the property to get. + * @return The property named name, or null if the property is + * not set. + * @throws SecurityException If the Jessie code still does not have + * permission to read the property. + */ + static String getSecurityProperty(final String name) + { + return (String) AccessController.doPrivileged( + new PrivilegedAction() + { + public Object run() + { + return Security.getProperty(name); + } + } + ); + } +} diff --git a/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java b/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java new file mode 100644 index 000000000..476655c45 --- /dev/null +++ b/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java @@ -0,0 +1,359 @@ +/* X509KeyManagerFactory.java -- X.509 key manager factory. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.Socket; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Enumeration; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.List; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactorySpi; +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.X509KeyManager; + +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.PrivateCredentials; + +/** + * This class implements a {@link javax.net.ssl.KeyManagerFactory} engine + * for the ``JessieX509'' algorithm. + */ +public class X509KeyManagerFactory extends KeyManagerFactorySpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Manager current; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509KeyManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected KeyManager[] engineGetKeyManagers() + { + if (current == null) + { + throw new IllegalStateException(); + } + return new KeyManager[] { current }; + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params instanceof NullManagerParameters) + { + current = new Manager(Collections.EMPTY_MAP, Collections.EMPTY_MAP); + } + else if (params instanceof PrivateCredentials) + { + List chains = ((PrivateCredentials) params).getCertChains(); + List keys = ((PrivateCredentials) params).getPrivateKeys(); + int i = 0; + HashMap certMap = new HashMap(); + HashMap keyMap = new HashMap(); + Iterator c = chains.iterator(); + Iterator k = keys.iterator(); + while (c.hasNext() && k.hasNext()) + { + certMap.put(String.valueOf(i), c.next()); + keyMap.put(String.valueOf(i), k.next()); + i++; + } + current = new Manager(keyMap, certMap); + } + else + { + throw new InvalidAlgorithmParameterException(); + } + } + + protected void engineInit(KeyStore store, char[] passwd) + throws KeyStoreException, NoSuchAlgorithmException, + UnrecoverableKeyException + { + if (store == null) + { + String s = Util.getProperty("javax.net.ssl.keyStoreType"); + if (s == null) + s = KeyStore.getDefaultType(); + store = KeyStore.getInstance(s); + s = Util.getProperty("javax.net.ssl.keyStore"); + if (s == null) + return; + String p = Util.getProperty("javax.net.ssl.keyStorePassword"); + try + { + store.load(new FileInputStream(s), p != null ? p.toCharArray() : null); + } + catch (IOException ioe) + { + throw new KeyStoreException(ioe.toString()); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce.toString()); + } + } + + HashMap p = new HashMap(); + HashMap c = new HashMap(); + Enumeration aliases = store.aliases(); + UnrecoverableKeyException exception = null; + while (aliases.hasMoreElements()) + { + String alias = (String) aliases.nextElement(); + if (!store.isKeyEntry(alias)) + { + continue; + } + X509Certificate[] chain = null; + Certificate[] chain2 = store.getCertificateChain (alias); + if (chain2 != null && chain2.length > 0 && + (chain2[0] instanceof X509Certificate)) + { + chain = toX509Chain(chain2); + } + else + { + continue; + } + PrivateKey key = null; + try + { + key = (PrivateKey) store.getKey(alias, passwd); + } + catch (UnrecoverableKeyException uke) + { + exception = uke; + continue; + } + if (key == null) + { + continue; + } + p.put(alias, key); + c.put(alias, chain); + } + if (p.isEmpty () && c.isEmpty ()) + { + if (exception != null) + { + throw exception; + } + throw new KeyStoreException ("no private credentials found"); + } + current = this.new Manager(p, c); + } + + private static X509Certificate[] toX509Chain(Certificate[] chain) + { + if (chain instanceof X509Certificate[]) + { + return (X509Certificate[]) chain; + } + X509Certificate[] _chain = new X509Certificate[chain.length]; + for (int i = 0; i < chain.length; i++) + _chain[i] = (X509Certificate) chain[i]; + return _chain; + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class Manager implements X509KeyManager + { + // Fields. + // ----------------------------------------------------------------------- + + private final Map privateKeys; + private final Map certChains; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(Map privateKeys, Map certChains) + { + this.privateKeys = privateKeys; + this.certChains = certChains; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public String chooseClientAlias(String[] keyTypes, Principal[] issuers, + Socket socket) + { + for (int i = 0; i < keyTypes.length; i++) + { + String[] s = getClientAliases(keyTypes[i], issuers); + if (s.length > 0) + return s[0]; + } + return null; + } + + public String[] getClientAliases(String keyType, Principal[] issuers) + { + return getAliases(keyType, issuers); + } + + public String chooseServerAlias(String keyType, Principal[] issuers, + Socket socket) + { + String[] s = getServerAliases(keyType, issuers); + if (s.length > 0) + return s[0]; + return null; + } + + public String[] getServerAliases(String keyType, Principal[] issuers) + { + return getAliases(keyType, issuers); + } + + private String[] getAliases(String keyType, Principal[] issuers) + { + LinkedList l = new LinkedList(); + for (Iterator i = privateKeys.keySet().iterator(); i.hasNext(); ) + { + String alias = (String) i.next(); + X509Certificate[] chain = getCertificateChain(alias); + if (chain.length == 0) + continue; + PrivateKey privKey = getPrivateKey(alias); + if (privKey == null) + continue; + PublicKey pubKey = chain[0].getPublicKey(); + if (keyType.equals("RSA") || keyType.equals("DHE_RSA") || + keyType.equals("SRP_RSA") || keyType.equals("rsa_sign")) + { + if (!(privKey instanceof RSAPrivateKey) || + !(pubKey instanceof RSAPublicKey)) + continue; + } + if (keyType.equals("DHE_DSS") || keyType.equals("dss_sign") || + keyType.equals("SRP_DSS")) + { + if (!(privKey instanceof DSAPrivateKey) || + !(pubKey instanceof DSAPublicKey)) + continue; + } + if (keyType.equals("DH_RSA") || keyType.equals("rsa_fixed_dh")) + { + if (!(privKey instanceof DHPrivateKey) || + !(pubKey instanceof DHPublicKey)) + continue; + if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA")) + continue; + } + if (keyType.equals("DH_DSS") || keyType.equals("dss_fixed_dh")) + { + if (!(privKey instanceof DHPrivateKey) || + !(pubKey instanceof DHPublicKey)) + continue; + if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA")) + continue; + } + if (issuers == null || issuers.length == 0) + { + l.add(alias); + continue; + } + for (int j = 0; j < issuers.length; j++) + if (chain[0].getIssuerDN().equals(issuers[j])) + { + l.add(alias); + break; + } + } + return (String[]) l.toArray(new String[l.size()]); + } + + public X509Certificate[] getCertificateChain(String alias) + { + X509Certificate[] c = (X509Certificate[]) certChains.get(alias); + return c != null ? (X509Certificate[]) c.clone() : null; + } + + public PrivateKey getPrivateKey(String alias) + { + return (PrivateKey) privateKeys.get(alias); + } + } +} diff --git a/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java b/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java new file mode 100644 index 000000000..4f049e916 --- /dev/null +++ b/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java @@ -0,0 +1,298 @@ +/* X509TrustManagerFactory.java -- X.509 trust manager factory. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.FileInputStream; +import java.io.IOException; + +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedList; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.SignatureException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactorySpi; +import javax.net.ssl.X509TrustManager; + +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.StaticTrustAnchors; + +/** + * This class implements a {@link javax.net.ssl.TrustManagerFactory} engine + * for the ``JessieX509'' algorithm. + */ +public class X509TrustManagerFactory extends TrustManagerFactorySpi +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + /** + * The location of the JSSE key store. + */ + private static final String JSSE_CERTS = Util.getProperty("java.home") + + Util.getProperty("file.separator") + "lib" + + Util.getProperty("file.separator") + "security" + + Util.getProperty("file.separator") + "jssecerts"; + + /** + * The location of the system key store, containing the CA certs. + */ + private static final String CA_CERTS = Util.getProperty("java.home") + + Util.getProperty("file.separator") + "lib" + + Util.getProperty("file.separator") + "security" + + Util.getProperty("file.separator") + "cacerts"; + + private Manager current; + + // Construtors. + // ------------------------------------------------------------------------- + + public X509TrustManagerFactory() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected TrustManager[] engineGetTrustManagers() + { + if (current == null) + { + throw new IllegalStateException("not initialized"); + } + return new TrustManager[] { current }; + } + + protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (params instanceof StaticTrustAnchors) + { + current = new Manager(((StaticTrustAnchors) params).getCertificates()); + } + else if (params instanceof NullManagerParameters) + { + current = new Manager(new X509Certificate[0]); + } + else + { + throw new InvalidAlgorithmParameterException(); + } + } + + protected void engineInit(KeyStore store) throws KeyStoreException + { + if (store == null) + { + String s = Util.getProperty("javax.net.ssl.trustStoreType"); + if (s == null) + s = KeyStore.getDefaultType(); + store = KeyStore.getInstance(s); + try + { + s = Util.getProperty("javax.net.ssl.trustStore"); + FileInputStream in = null; + if (s == null) + { + try + { + in = new FileInputStream(JSSE_CERTS); + } + catch (IOException e) + { + in = new FileInputStream(CA_CERTS); + } + } + else + { + in = new FileInputStream(s); + } + String p = Util.getProperty("javax.net.ssl.trustStorePassword"); + store.load(in, p != null ? p.toCharArray() : null); + } + catch (IOException ioe) + { + throw new KeyStoreException(ioe.toString()); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce.toString()); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyStoreException(nsae.toString()); + } + } + + LinkedList l = new LinkedList(); + Enumeration aliases = store.aliases(); + while (aliases.hasMoreElements()) + { + String alias = (String) aliases.nextElement(); + if (!store.isCertificateEntry(alias)) + continue; + Certificate c = store.getCertificate(alias); + if (!(c instanceof X509Certificate)) + continue; + l.add(c); + } + current = this.new Manager((X509Certificate[]) + l.toArray(new X509Certificate[l.size()])); + } + + // Inner class. + // ------------------------------------------------------------------------- + + /** + * The actual manager implementation returned. + */ + private class Manager implements X509TrustManager + { + + // Fields. + // ----------------------------------------------------------------------- + + private final X509Certificate[] trusted; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(X509Certificate[] trusted) + { + this.trusted = trusted; + } + + // Instance methodns. + // ----------------------------------------------------------------------- + + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + checkTrusted(chain, authType); + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + checkTrusted(chain, authType); + } + + public X509Certificate[] getAcceptedIssuers() + { + if (trusted == null) + return new X509Certificate[0]; + return (X509Certificate[]) trusted.clone(); + } + + // Own methods. + // ----------------------------------------------------------------------- + + private void checkTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + // NOTE: this is not a full-featured path validation algorithm. + // + // Step 0: check if the target is valid now. + chain[0].checkValidity(); + + // Step 1: verify that the chain is complete and valid. + for (int i = 1; i < chain.length; i++) + { + chain[i].checkValidity(); + try + { + chain[i-1].verify(chain[i].getPublicKey()); + } + catch (NoSuchAlgorithmException nsae) + { + throw new CertificateException(nsae.toString()); + } + catch (NoSuchProviderException nspe) + { + throw new CertificateException(nspe.toString()); + } + catch (InvalidKeyException ike) + { + throw new CertificateException(ike.toString()); + } + catch (SignatureException se) + { + throw new CertificateException(se.toString()); + } + } + + // Step 2: verify that the root of the chain was issued by a trust anchor. + if (trusted == null || trusted.length == 0) + throw new CertificateException("no trust anchors"); + for (int i = 0; i < trusted.length; i++) + { + try + { + trusted[i].checkValidity(); + chain[chain.length-1].verify(trusted[i].getPublicKey()); + return; + } + catch (Exception e) + { + } + //catch (CertificateException ce) { } + //catch (NoSuchAlgorithmException nsae) { } + //catch (NoSuchProviderException nspe) { } + //catch (InvalidKeyException ike) { } + //catch (SignatureException se) { } + } + throw new CertificateException(); + } + } +} diff --git a/gnu/javax/net/ssl/provider/XMLSessionContext.java b/gnu/javax/net/ssl/provider/XMLSessionContext.java new file mode 100644 index 000000000..dcfa9d4ad --- /dev/null +++ b/gnu/javax/net/ssl/provider/XMLSessionContext.java @@ -0,0 +1,619 @@ +/* XMLSessionContext.java -- XML-encoded persistent SSL sessions. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.PrintStream; + +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeSet; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; +import gnu.javax.crypto.prng.IPBE; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.PRNGFactory; + +import gnu.javax.net.ssl.Base64; + +/** + * An implementation of session contexts that stores session data on the + * filesystem in a simple XML-encoded file. + */ +class XMLSessionContext extends SessionContext +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final File file; + private final IRandom pbekdf; + private final boolean compress; + private final SecureRandom random; + private boolean encoding; + + // Constructor. + // ------------------------------------------------------------------------- + + XMLSessionContext() throws IOException, SAXException + { + file = new File(Util.getSecurityProperty("jessie.SessionContext.xml.file")); + String password = Util.getSecurityProperty("jessie.SessionContext.xml.password"); + compress = new Boolean(Util.getSecurityProperty("jessie.SessionContext.xml.compress")).booleanValue(); + if (password == null) + { + password = ""; + } + pbekdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA1"); + HashMap kdfattr = new HashMap(); + kdfattr.put(IPBE.PASSWORD, password.toCharArray()); + // Dummy salt. This is replaced by a real salt when encoding. + kdfattr.put(IPBE.SALT, new byte[8]); + kdfattr.put(IPBE.ITERATION_COUNT, new Integer(1000)); + pbekdf.init(kdfattr); + encoding = false; + if (file.exists()) + { + decode(); + } + encoding = true; + random = new SecureRandom (); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + synchronized boolean addSession(Session.ID sessionId, Session session) + { + boolean ret = super.addSession(sessionId, session); + if (ret && encoding) + { + try + { + encode(); + } + catch (IOException ioe) + { + } + } + return ret; + } + + synchronized void notifyAccess(Session session) + { + try + { + encode(); + } + catch (IOException ioe) + { + } + } + + synchronized boolean removeSession(Session.ID sessionId) + { + if (super.removeSession(sessionId)) + { + try + { + encode(); + } + catch (Exception x) + { + } + return true; + } + return false; + } + + private void decode() throws IOException, SAXException + { + SAXParser parser = null; + try + { + parser = SAXParserFactory.newInstance().newSAXParser(); + } + catch (Exception x) + { + throw new Error(x.toString()); + } + SAXHandler handler = new SAXHandler(this, pbekdf); + InputStream in = null; + if (compress) + in = new GZIPInputStream(new FileInputStream(file)); + else + in = new FileInputStream(file); + parser.parse(in, handler); + } + + private void encode() throws IOException + { + IMode cipher = ModeFactory.getInstance("CBC", "AES", 16); + HashMap cipherAttr = new HashMap(); + IMac mac = MacFactory.getInstance("HMAC-SHA1"); + HashMap macAttr = new HashMap(); + byte[] key = new byte[32]; + byte[] iv = new byte[16]; + byte[] mackey = new byte[20]; + byte[] salt = new byte[8]; + byte[] encryptedSecret = new byte[48]; + cipherAttr.put(IMode.KEY_MATERIAL, key); + cipherAttr.put(IMode.IV, iv); + cipherAttr.put(IMode.STATE, new Integer(IMode.ENCRYPTION)); + macAttr.put(IMac.MAC_KEY_MATERIAL, mackey); + PrintStream out = null; + if (compress) + { + out = new PrintStream(new GZIPOutputStream(new FileOutputStream(file))); + } + else + { + out = new PrintStream(new FileOutputStream(file)); + } + out.println(""); + out.println(""); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println(" "); + out.println("]>"); + out.println(); + out.print(""); + for (Iterator it = sessions.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry entry = (Map.Entry) it.next(); + Session.ID id = (Session.ID) entry.getKey(); + Session session = (Session) entry.getValue(); + if (!session.valid) + { + continue; + } + out.print(""); + out.print(""); + Certificate[] certs = session.getPeerCertificates(); + if (certs != null && certs.length > 0) + { + out.print(""); + for (int i = 0; i < certs.length; i++) + { + out.println("-----BEGIN CERTIFICATE-----"); + try + { + out.print(Base64.encode(certs[i].getEncoded(), 70)); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + out.println("-----END CERTIFICATE-----"); + } + out.println(""); + } + out.println(""); + certs = session.getLocalCertificates(); + if (certs != null && certs.length > 0) + { + out.print(""); + for (int i = 0; i < certs.length; i++) + { + out.println("-----BEGIN CERTIFICATE-----"); + try + { + out.print(Base64.encode(certs[i].getEncoded(), 70)); + } + catch (CertificateEncodingException cee) + { + throw new IOException(cee.toString()); + } + out.println("-----END CERTIFICATE-----"); + } + out.println(""); + } + random.nextBytes (salt); + pbekdf.init(Collections.singletonMap(IPBE.SALT, salt)); + try + { + pbekdf.nextBytes(key, 0, key.length); + pbekdf.nextBytes(iv, 0, iv.length); + pbekdf.nextBytes(mackey, 0, mackey.length); + cipher.reset(); + cipher.init(cipherAttr); + mac.init(macAttr); + } + catch (Exception ex) + { + throw new Error(ex.toString()); + } + for (int i = 0; i < session.masterSecret.length; i += 16) + { + cipher.update(session.masterSecret, i, encryptedSecret, i); + } + mac.update(encryptedSecret, 0, encryptedSecret.length); + byte[] macValue = mac.digest(); + out.print(""); + out.print(Base64.encode(Util.concat(encryptedSecret, macValue), 70)); + out.println(""); + out.println(""); + } + out.println(""); + out.close(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + private class SAXHandler extends DefaultHandler + { + + // Field. + // ----------------------------------------------------------------------- + + private SessionContext context; + private Session current; + private IRandom pbekdf; + private StringBuffer buf; + private String certType; + private int state; + private IMode cipher; + private HashMap cipherAttr; + private IMac mac; + private HashMap macAttr; + private byte[] key; + private byte[] iv; + private byte[] mackey; + + private static final int START = 0; + private static final int SESSIONS = 1; + private static final int SESSION = 2; + private static final int PEER = 3; + private static final int PEER_CERTS = 4; + private static final int CERTS = 5; + private static final int SECRET = 6; + + // Constructor. + // ----------------------------------------------------------------------- + + SAXHandler(SessionContext context, IRandom pbekdf) + { + this.context = context; + this.pbekdf = pbekdf; + buf = new StringBuffer(); + state = START; + cipher = ModeFactory.getInstance("CBC", "AES", 16); + cipherAttr = new HashMap(); + mac = MacFactory.getInstance("HMAC-SHA1"); + macAttr = new HashMap(); + key = new byte[32]; + iv = new byte[16]; + mackey = new byte[20]; + cipherAttr.put(IMode.KEY_MATERIAL, key); + cipherAttr.put(IMode.IV, iv); + cipherAttr.put(IMode.STATE, new Integer(IMode.DECRYPTION)); + macAttr.put(IMac.MAC_KEY_MATERIAL, mackey); + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public void startElement(String u, String n, String qname, Attributes attr) + throws SAXException + { + qname = qname.toLowerCase(); + switch (state) + { + case START: + if (qname.equals("sessions")) + { + try + { + timeout = Integer.parseInt(attr.getValue("timeout")); + cacheSize = Integer.parseInt(attr.getValue("size")); + if (timeout <= 0 || cacheSize < 0) + throw new SAXException("timeout or cache size out of range"); + } + catch (NumberFormatException nfe) + { + throw new SAXException(nfe); + } + state = SESSIONS; + } + else + throw new SAXException("expecting sessions"); + break; + + case SESSIONS: + if (qname.equals("session")) + { + try + { + current = new Session(Long.parseLong(attr.getValue("created"))); + current.enabledSuites = new ArrayList(SSLSocket.supportedSuites); + current.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols); + current.context = context; + current.sessionId = new Session.ID(Base64.decode(attr.getValue("id"))); + current.setLastAccessedTime(Long.parseLong(attr.getValue("timestamp"))); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + String prot = attr.getValue("protocol"); + if (prot.equals("SSLv3")) + current.protocol = ProtocolVersion.SSL_3; + else if (prot.equals("TLSv1")) + current.protocol = ProtocolVersion.TLS_1; + else if (prot.equals("TLSv1.1")) + current.protocol = ProtocolVersion.TLS_1_1; + else + throw new SAXException("bad protocol: " + prot); + current.cipherSuite = CipherSuite.forName(attr.getValue("suite")); + state = SESSION; + } + else + throw new SAXException("expecting session"); + break; + + case SESSION: + if (qname.equals("peer")) + { + current.peerHost = attr.getValue("host"); + state = PEER; + } + else if (qname.equals("certificates")) + { + certType = attr.getValue("type"); + state = CERTS; + } + else if (qname.equals("secret")) + { + byte[] salt = null; + try + { + salt = Base64.decode(attr.getValue("salt")); + } + catch (IOException ioe) + { + throw new SAXException(ioe); + } + pbekdf.init(Collections.singletonMap(IPBE.SALT, salt)); + state = SECRET; + } + else + throw new SAXException("bad element: " + qname); + break; + + case PEER: + if (qname.equals("certificates")) + { + certType = attr.getValue("type"); + state = PEER_CERTS; + } + else + throw new SAXException("bad element: " + qname); + break; + + default: + throw new SAXException("bad element: " + qname); + } + } + + public void endElement(String uri, String name, String qname) + throws SAXException + { + qname = qname.toLowerCase(); + switch (state) + { + case SESSIONS: + if (qname.equals("sessions")) + state = START; + else + throw new SAXException("expecting sessions"); + break; + + case SESSION: + if (qname.equals("session")) + { + current.valid = true; + context.addSession(current.sessionId, current); + state = SESSIONS; + } + else + throw new SAXException("expecting session"); + break; + + case PEER: + if (qname.equals("peer")) + state = SESSION; + else + throw new SAXException("unexpected element: " + qname); + break; + + case PEER_CERTS: + if (qname.equals("certificates")) + { + try + { + CertificateFactory fact = CertificateFactory.getInstance(certType); + current.peerCerts = (Certificate[]) + fact.generateCertificates(new ByteArrayInputStream( + buf.toString().getBytes())).toArray(new Certificate[0]); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + current.peerVerified = true; + state = PEER; + } + else + throw new SAXException("unexpected element: " + qname); + break; + + case CERTS: + if (qname.equals("certificates")) + { + try + { + CertificateFactory fact = CertificateFactory.getInstance(certType); + current.localCerts = (Certificate[]) + fact.generateCertificates(new ByteArrayInputStream( + buf.toString().getBytes())).toArray(new Certificate[0]); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + state = SESSION; + } + else + throw new SAXException("unexpected element: " + qname); + break; + + case SECRET: + if (qname.equals("secret")) + { + byte[] encrypted = null; + try + { + encrypted = Base64.decode(buf.toString()); + if (encrypted.length != 68) + throw new IOException("encrypted secret not 68 bytes long"); + pbekdf.nextBytes(key, 0, key.length); + pbekdf.nextBytes(iv, 0, iv.length); + pbekdf.nextBytes(mackey, 0, mackey.length); + cipher.reset(); + cipher.init(cipherAttr); + mac.init(macAttr); + } + catch (Exception ex) + { + throw new SAXException(ex); + } + mac.update(encrypted, 0, 48); + byte[] macValue = mac.digest(); + for (int i = 0; i < macValue.length; i++) + { + if (macValue[i] != encrypted[48+i]) + throw new SAXException("MAC mismatch"); + } + current.masterSecret = new byte[48]; + for (int i = 0; i < current.masterSecret.length; i += 16) + { + cipher.update(encrypted, i, current.masterSecret, i); + } + state = SESSION; + } + else + throw new SAXException("unexpected element: " + qname); + break; + + default: + throw new SAXException("unexpected element: " + qname); + } + buf.setLength(0); + } + + public void characters(char[] ch, int off, int len) throws SAXException + { + if (state != CERTS && state != PEER_CERTS && state != SECRET) + { + throw new SAXException("illegal character data"); + } + buf.append(ch, off, len); + } + } +} diff --git a/gnu/javax/security/auth/Password.java b/gnu/javax/security/auth/Password.java new file mode 100644 index 000000000..7284b7d68 --- /dev/null +++ b/gnu/javax/security/auth/Password.java @@ -0,0 +1,285 @@ +/* Password.java -- opaque wrapper around a password. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth; + +import gnu.java.security.util.ExpirableObject; + +import javax.security.auth.DestroyFailedException; + +/** + * Immutible, though destroyable, password class. + * + *

    Extends {@link ExpirableObject}, implementing {@link doDestroy()} + * in which encapsulated {@link char[]}, and {@link byte[]} password fields + * are cleared (elements set to zero) in order to thwart memory heap + * snooping. + */ +public final class Password extends ExpirableObject +{ + + // Constants and variables + // ------------------------------------------------------------------------- + + /** + * Password stored in {@link char[]} format. + */ + private final char[] password; + + /** + * Password stored in {@link byte[]} format. + */ + private final byte[] bPassword; + + /** + * Indicates whether this Password object's {@link doDestroy()} method has + * been called. See also, {@link ExpirableObject#Destroy()}. + */ + private boolean mIsDestroyed = false; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Create a new expirable Password object that will expire after the + * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}. + * + * @param password The character array password to associate with this + * Password object. + */ + public Password (char[] password) + { + this (password, 0, password.length, DEFAULT_TIMEOUT); + } + + /** + * Create a new expirable Password object that will expire after the + * timeout denoted by constructor parameter, delay. + * + * @param password The character array password to associate with this + * Password object. + * @param delay The number of miliseconds before this Password object + * will be automatically destroyed. + */ + public Password (char[] password, long delay) + { + this (password, 0, password.length, delay); + } + + /** + * Create a new expirable Password object that will expire after the + * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}. + * + * @param password The character array password to associate with this + * Password object. + * @param offset The password character array parameter element + * marking the beginning of the contained password string. + * @param length The number of characters, beginning at offset, + * to be copied into this object's {@link password} field. + */ + public Password (char[] password, int offset, int length) + { + this (password, offset, length, DEFAULT_TIMEOUT); + } + + /** + * Create a new expirable Password object that will expire after the + * timeout denoted by constructor parameter, delay. + * + * @param password The character array password to associate with this + * Password object. + * @param offset The password character array parameter element + * marking the beginning of the contained password string. + * @param length The number of characters, beginning at offset, + * to be copied into this object's {@link password} field. + * @param delay The number of miliseconds before this Password object + * will be automatically destroyed. + */ + public Password (char[] password, int offset, int length, long delay) + { + super (delay); + + if (offset < 0 || length < 0 || offset + length > password.length) + throw new ArrayIndexOutOfBoundsException ("off=" + offset + " length=" + + length + " array.length=" + + password.length); + + int i, j; + this.password = new char[length]; + bPassword = new byte[length]; + + for(i = 0, j = offset; i < length; i++, j++) + { + this.password[i] = (char) password[j]; + // XXX this should use character encodings, other than ASCII. + bPassword[i] = (byte) (password[j] & 0x7F); + } + } + + /** + * Create a new expirable Password object that will expire after the + * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}. + * + * @param password The byte array password to associate with this + * Password object. + */ + public Password (byte[] password) + { + this (password, 0, password.length, DEFAULT_TIMEOUT); + } + + /** + * Create a new expirable Password object that will expire after the + * timeout denoted by constructor parameter, delay. + * + * @param password The byte array password to associate with this + * Password object. + * @param delay The number of miliseconds before this Password object + * will be automatically destroyed. + */ + public Password (byte[] password, long delay) + { + this (password, 0, password.length, delay); + } + + /** + * Create a new expirable Password object that will expire after the + * default timeout {@link ExpirableObject#DEFAULT_TIMEOUT}. + * + * @param password The byte array password to associate with this + * Password object. + * @param offset The password byte array parameter element + * marking the beginning of the contained password string. + * @param length The number of bytes, beginning at offset, + * to be copied into this object's {@link password} field. + */ + public Password (byte[] password, int offset, int length) + { + this (password, offset, length, DEFAULT_TIMEOUT); + } + + /** + * Create a new expirable Password object that will expire after the + * timeout denoted by constructor parameter, delay. + * + * @param password The byte array password to associate with this + * Password object. + * @param offset The password byte array parameter element + * marking the beginning of the contained password string. + * @param length The number of bytes, beginning at offset, + * to be copied into this object's {@link bPassword} field. + * @param delay The number of miliseconds before this Password object + * will be automatically destroyed. + */ + public Password (byte[] password, int offset, int length, long delay) + { + super (delay); + + if (offset < 0 || length < 0 || offset + length > password.length) + throw new ArrayIndexOutOfBoundsException ("off=" + offset + " length=" + + length + " array.length=" + + password.length); + + int i, j; + this.password = new char[length]; + bPassword = new byte[length]; + + for (i = 0, j = offset; i < length; i++, j++) + { + this.password[i] = (char) password[j]; + bPassword[i] = password[j]; + } + } + + // Instance methods + // ------------------------------------------------------------------------- + + /** + * Returns a reference to the {@link char[]} password storage field, + * {@link password}. + */ + public synchronized char[] getPassword() + { + if (mIsDestroyed) + throw new IllegalStateException ("Attempted destroyed password access."); + + return password; + } + + /** + * Returns a reference to the {@link byte[]} password storage field, + * {@link bPassword}. + */ + public synchronized byte[] getBytes() + { + if (mIsDestroyed) + throw new IllegalStateException ("Attempted destroyed password access."); + + return bPassword; + } + + /** + * Sets password field char[], and byte[] array elements to zero. + * This method implements base class {@link ExpirableObject} abstract + * method, {@link ExpirableObject#doDestroy()}. See also, + * {@link ExpirableObject#destroy()}. + */ + protected synchronized void doDestroy() + { + if (isDestroyed()) + return; + else + { + for (int i = 0; i < password.length; i++) + password[i] = 0; + for (int i = 0; i < bPassword.length; i++) + bPassword[i] = 0; + mIsDestroyed = true; + } + } + + /** + * Returns true, or false relative to whether, or not this object's + * {@link doDestroy()} method has been called. See also, + * {@ExpirableObject#destroy()}. + */ + public synchronized boolean isDestroyed() + { + return (mIsDestroyed); + } +} diff --git a/gnu/javax/security/auth/callback/AWTCallbackHandler.java b/gnu/javax/security/auth/callback/AWTCallbackHandler.java new file mode 100644 index 000000000..539c4a17e --- /dev/null +++ b/gnu/javax/security/auth/callback/AWTCallbackHandler.java @@ -0,0 +1,452 @@ +/* AWTCallbackHandler.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.callback; + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.TextField; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; + +import java.util.Locale; + +import javax.security.auth.callback.ChoiceCallback; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.LanguageCallback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.TextOutputCallback; + +public class AWTCallbackHandler extends AbstractCallbackHandler + implements ActionListener, WindowListener +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected String actionCommand; + + private static final String ACTION_CANCEL = "CANCEL"; + private static final String ACTION_NO = "NO"; + private static final String ACTION_NONE = "NONE"; + private static final String ACTION_OK = "OK"; + private static final String ACTION_YES = "YES"; + + // Constructor. + // ------------------------------------------------------------------------- + + public AWTCallbackHandler() + { + super ("AWT"); + actionCommand = ACTION_NONE; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected synchronized void handleChoice(ChoiceCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + String[] choices = c.getChoices(); + dialog.setTitle(c.getPrompt()); + Label label = new Label(c.getPrompt()); + List list = new List(Math.min(5, choices.length), + c.allowMultipleSelections()); + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + for (int i = 0; i < choices.length; i++) + { + list.add(choices[i]); + } + if (c.getDefaultChoice() >= 0 && c.getDefaultChoice() < choices.length) + { + list.select(c.getDefaultChoice()); + } + dialog.setLayout(new BorderLayout()); + dialog.add(label, BorderLayout.NORTH); + dialog.add(list, BorderLayout.CENTER); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(cancel); + buttons.add(ok); + dialog.add(buttons, BorderLayout.SOUTH); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + if (c.allowMultipleSelections()) + { + c.setSelectedIndexes(list.getSelectedIndexes()); + } + else + { + c.setSelectedIndex(list.getSelectedIndex()); + } + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleConfirmation(ConfirmationCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + switch (c.getMessageType()) + { + case ConfirmationCallback.ERROR: + dialog.setTitle(messages.getString("callback.error")); + break; + case ConfirmationCallback.INFORMATION: + dialog.setTitle(messages.getString("callback.information")); + break; + case ConfirmationCallback.WARNING: + dialog.setTitle(messages.getString("callback.warning")); + break; + default: + dialog.setTitle(""); + } + dialog.setLayout(new GridLayout(2, 1)); + dialog.add(new Label(c.getPrompt())); + Panel buttons = new Panel(); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + dialog.add(buttons); + String[] choices = null; + int[] values = null; + switch (c.getOptionType()) + { + case ConfirmationCallback.OK_CANCEL_OPTION: + choices = new String[] { + messages.getString("callback.cancel"), + messages.getString("callback.ok") + }; + values = new int[] { + ConfirmationCallback.CANCEL, ConfirmationCallback.OK + }; + break; + case ConfirmationCallback.YES_NO_CANCEL_OPTION: + choices = new String[] { + messages.getString("callback.cancel"), + messages.getString("callback.no"), + messages.getString("callback.yes") + }; + values = new int[] { + ConfirmationCallback.CANCEL, ConfirmationCallback.NO, + ConfirmationCallback.YES + }; + break; + case ConfirmationCallback.YES_NO_OPTION: + choices = new String[] { + messages.getString("callback.no"), + messages.getString("callback.yes") + }; + values = new int[] { + ConfirmationCallback.NO, ConfirmationCallback.YES + }; + break; + case ConfirmationCallback.UNSPECIFIED_OPTION: + choices = c.getOptions(); + values = new int[choices.length]; + for (int i = 0; i < values.length; i++) + values[i] = i; + break; + default: + throw new IllegalArgumentException(); + } + for (int i = 0; i < choices.length; i++) + { + Button b = new Button(choices[i]); + b.setActionCommand(choices[i]); + b.addActionListener(this); + buttons.add(b); + } + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + for (int i = 0; i < choices.length; i++) + { + if (actionCommand.equals(choices[i])) + { + c.setSelectedIndex(values[i]); + break; + } + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleLanguage(LanguageCallback c) + { + Locale[] locales = Locale.getAvailableLocales(); + String[] languages = new String[locales.length]; + Locale def = Locale.getDefault(); + int defind = 0; + for (int i = 0; i < locales.length; i++) + { + StringBuffer lang = + new StringBuffer(locales[i].getDisplayLanguage(locales[i])); + String country = locales[i].getDisplayCountry(locales[i]); + String variant = locales[i].getDisplayVariant(locales[i]); + if (country.length() > 0 && variant.length() > 0) + { + lang.append(" ("); + lang.append(country); + lang.append(", "); + lang.append(variant); + lang.append(")"); + } + else if (country.length() > 0) + { + lang.append(" ("); + lang.append(country); + lang.append(")"); + } + else if (variant.length() > 0) + { + lang.append(" ("); + lang.append(variant); + lang.append(")"); + } + languages[i] = lang.toString(); + if (locales[i].equals(def)) + defind = i; + } + ChoiceCallback c2 = + new ChoiceCallback(messages.getString("callback.language"), languages, + defind, false); + handleChoice(c2); + c.setLocale(def); + if (c2.getSelectedIndexes() != null && c2.getSelectedIndexes().length > 0) + { + int index = c2.getSelectedIndexes()[0]; + if (index >= 0 && index < locales.length) + c.setLocale(locales[index]); + } + } + + protected synchronized void handleName(NameCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setTitle(c.getPrompt()); + dialog.setLayout(new GridLayout(3, 1)); + Label label = new Label(c.getPrompt()); + TextField input = new TextField(); + if (c.getDefaultName() != null) + { + input.setText(c.getDefaultName()); + } + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + dialog.add(label); + dialog.add(input); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + buttons.add(cancel); + dialog.add(buttons); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + c.setName(input.getText()); + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handlePassword(PasswordCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setTitle(c.getPrompt()); + dialog.setLayout(new GridLayout(3, 1)); + Label label = new Label(c.getPrompt()); + TextField input = new TextField(); + if (!c.isEchoOn()) + { + input.setEchoChar('*'); + } + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + dialog.add(label); + dialog.add(input); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + buttons.add(cancel); + dialog.add(buttons); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + c.setPassword(input.getText().toCharArray()); + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleTextInput(TextInputCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setTitle(c.getPrompt()); + dialog.setLayout(new BorderLayout()); + Label label = new Label(c.getPrompt()); + TextArea text = new TextArea(10, 40); + if (c.getDefaultText() != null) + { + text.setText(c.getDefaultText()); + } + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + ok.setActionCommand(ACTION_OK); + ok.addActionListener(this); + Button cancel = new Button(messages.getString("callback.cancel")); + cancel.setActionCommand(ACTION_CANCEL); + cancel.addActionListener(this); + dialog.add(label, BorderLayout.NORTH); + dialog.add(text, BorderLayout.CENTER); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + buttons.add(cancel); + dialog.add(buttons, BorderLayout.SOUTH); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + if (actionCommand.equals(ACTION_OK)) + { + c.setText(text.getText()); + } + dialog.dispose(); + ownerFrame.dispose(); + } + + protected synchronized void handleTextOutput(TextOutputCallback c) + { + Frame ownerFrame = new Frame(); + Dialog dialog = new Dialog(ownerFrame); + dialog.setLayout(new GridLayout(2, 1)); + switch (c.getMessageType() /*c.getStyle()*/) + { + case ConfirmationCallback.ERROR: + dialog.setTitle(messages.getString("callback.error")); + break; + case ConfirmationCallback.INFORMATION: + dialog.setTitle(messages.getString("callback.information")); + break; + case ConfirmationCallback.WARNING: + dialog.setTitle(messages.getString("callback.warning")); + break; + default: + dialog.setTitle(""); + } + Label label = new Label(c.getMessage()); + Panel buttons = new Panel(); + Button ok = new Button(messages.getString("callback.ok")); + buttons.setLayout(new FlowLayout(FlowLayout.RIGHT)); + buttons.add(ok); + ok.addActionListener(this); + dialog.add(label); + dialog.add(buttons); + dialog.pack(); + dialog.show(); + try { wait(); } + catch (InterruptedException ie) { } + dialog.dispose(); + ownerFrame.dispose(); + } + + // ActionListener interface implementation. + // ------------------------------------------------------------------------- + + public synchronized void actionPerformed(ActionEvent ae) + { + actionCommand = ae.getActionCommand(); + notifyAll(); + } + + // WindowListener interface implementation. + // ------------------------------------------------------------------------- + + public synchronized void windowClosing(WindowEvent we) + { + actionCommand = ACTION_NONE; + notifyAll(); + } + + public void windowOpened(WindowEvent we) { } + public void windowClosed(WindowEvent we) { } + public void windowIconified(WindowEvent we) { } + public void windowDeiconified(WindowEvent we) { } + public void windowActivated(WindowEvent we) { } + public void windowDeactivated(WindowEvent we) { } +} diff --git a/gnu/javax/security/auth/callback/AbstractCallbackHandler.java b/gnu/javax/security/auth/callback/AbstractCallbackHandler.java new file mode 100644 index 000000000..eeedf2605 --- /dev/null +++ b/gnu/javax/security/auth/callback/AbstractCallbackHandler.java @@ -0,0 +1,258 @@ +/* AbstractCallbackHandler.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.callback; + +import gnu.java.security.Engine; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.ChoiceCallback; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.LanguageCallback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.TextOutputCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +public abstract class AbstractCallbackHandler implements CallbackHandler +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final String SERVICE = "CallbackHandler"; + + protected final ResourceBundle messages; + + private final String name; + + // Constructors. + // ------------------------------------------------------------------------- + + protected AbstractCallbackHandler (final String name) + { + super(); + messages = PropertyResourceBundle.getBundle("gnu/javax/security/auth/callback/MessagesBundle"); + this.name = name; + } + + // Class methods. + // ------------------------------------------------------------------------- + + public static CallbackHandler getInstance(String type) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + for (int i = 0; i < p.length; i++) + { + try + { + return getInstance(type, p[i]); + } + catch (NoSuchAlgorithmException ignored) + { + } + } + throw new NoSuchAlgorithmException(type); + } + + public static CallbackHandler getInstance(String type, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + Provider p = Security.getProvider(provider); + if (p == null) + { + throw new NoSuchProviderException(provider); + } + return getInstance(type, p); + } + + public static CallbackHandler getInstance(String type, Provider provider) + throws NoSuchAlgorithmException + { + try + { + return (CallbackHandler) Engine.getInstance(SERVICE, type, provider); + } + catch (InvocationTargetException ite) + { + Throwable cause = ite.getCause(); + if (cause instanceof NoSuchAlgorithmException) + throw (NoSuchAlgorithmException) cause; + NoSuchAlgorithmException nsae = new NoSuchAlgorithmException(type); + if (cause != null) + nsae.initCause (cause); + throw nsae; + } + catch (ClassCastException cce) + { + NoSuchAlgorithmException nsae = new NoSuchAlgorithmException(type); + nsae.initCause (cce); + throw nsae; + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException + { + if (callbacks == null) + throw new NullPointerException(); + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] == null) + continue; + if (callbacks[i] instanceof ChoiceCallback) + handleChoice((ChoiceCallback) callbacks[i]); + else if (callbacks[i] instanceof ConfirmationCallback) + handleConfirmation((ConfirmationCallback) callbacks[i]); + else if (callbacks[i] instanceof LanguageCallback) + handleLanguage((LanguageCallback) callbacks[i]); + else if (callbacks[i] instanceof NameCallback) + handleName((NameCallback) callbacks[i]); + else if (callbacks[i] instanceof PasswordCallback) + handlePassword((PasswordCallback) callbacks[i]); + else if (callbacks[i] instanceof TextInputCallback) + handleTextInput((TextInputCallback) callbacks[i]); + else if (callbacks[i] instanceof TextOutputCallback) + handleTextOutput((TextOutputCallback) callbacks[i]); + else + handleOther(callbacks[i]); + } + } + + public final String getName () + { + return name; + } + + // Abstract methods. + // ------------------------------------------------------------------------- + + /** + * Handles a {@link ChoiceCallback}. + * + * @param callback The choice callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleChoice(ChoiceCallback callback) + throws IOException; + + /** + * Handles a {@link ConfirmationCallback}. + * + * @param callback The confirmation callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleConfirmation(ConfirmationCallback callback) + throws IOException; + + /** + * Handles a {@link LanguageCallback}. + * + * @param callback The language callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleLanguage(LanguageCallback callback) + throws IOException; + + /** + * Handles a {@link NameCallback}. + * + * @param callback The name callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleName(NameCallback callback) + throws IOException; + + /** + * Handles a {@link PasswordCallback}. + * + * @param callback The password callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handlePassword(PasswordCallback callback) + throws IOException; + + /** + * Handles a {@link TextInputCallback}. + * + * @param callback The text input callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleTextInput(TextInputCallback callback) + throws IOException; + + /** + * Handles a {@link TextOutputCallback}. + * + * @param callback The text output callback. + * @throws IOException If an I/O error occurs. + */ + protected abstract void handleTextOutput(TextOutputCallback callback) + throws IOException; + + /** + * Handles an unknown callback. The default implementation simply throws + * an {@link UnsupportedCallbackException}. + * + * @param callback The callback to handle. + * @throws IOException If an I/O error occurs. + * @throws UnsupportedCallbackException If the specified callback is not + * supported. + */ + protected void handleOther(Callback callback) + throws IOException, UnsupportedCallbackException + { + throw new UnsupportedCallbackException(callback); + } +} diff --git a/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java b/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java new file mode 100644 index 000000000..4ce22cb30 --- /dev/null +++ b/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java @@ -0,0 +1,289 @@ +/* ConsoleCallbackHandler.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.callback; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintStream; + +import java.util.Iterator; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.TreeSet; + +import javax.security.auth.callback.ChoiceCallback; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.LanguageCallback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.TextOutputCallback; + +/** + * An implementation of {@link CallbackHandler} that reads and writes + * information to and from System.in and System.out. + */ +public class ConsoleCallbackHandler extends AbstractCallbackHandler +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final PrintStream out; + + // Constructors. + // ------------------------------------------------------------------------- + + public ConsoleCallbackHandler() + { + this (System.out); + } + + public ConsoleCallbackHandler (final PrintStream out) + { + super ("CONSOLE"); + this.out = out; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected void handleChoice(ChoiceCallback c) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + out.println(c.getPrompt()); + out.print('('); + String[] choices = c.getChoices(); + for (int i = 0; i < choices.length; i++) + { + out.print(choices[i]); + if (i != choices.length - 1) + out.print(", "); + } + out.print(") "); + if (c.getDefaultChoice() >= 0 && c.getDefaultChoice() < choices.length) + { + out.print('['); + out.print(choices[c.getDefaultChoice()]); + out.print("] "); + } + String reply = in.readLine(); + if (reply == null || reply.length() == 0) + { + c.setSelectedIndex(c.getDefaultChoice()); + return; + } + if (!c.allowMultipleSelections()) + { + for (int i = 0; i < choices.length; i++) + { + if (reply.trim().equals(choices[i])) + { + c.setSelectedIndex(i); + return; + } + } + c.setSelectedIndex(c.getDefaultChoice()); + } + else + { + TreeSet indices = new TreeSet(); + StringTokenizer tok = new StringTokenizer(reply, ","); + String[] replies = new String[tok.countTokens()]; + int idx = 0; + while (tok.hasMoreTokens()) + { + replies[idx++] = tok.nextToken().trim(); + } + for (int i = 0; i < choices.length; i++) + for (int j = 0; j < replies.length; i++) + { + if (choices[i].equals(replies[j])) + { + indices.add(new Integer(i)); + } + } + if (indices.size() == 0) + c.setSelectedIndex(c.getDefaultChoice()); + else + { + int[] ii = new int[indices.size()]; + int i = 0; + for (Iterator it = indices.iterator(); it.hasNext(); ) + ii[i++] = ((Integer) it.next()).intValue(); + c.setSelectedIndexes(ii); + } + } + } + + protected void handleConfirmation(ConfirmationCallback c) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + if (c.getPrompt() != null) + out.println(c.getPrompt()); + String[] choices = null; + int[] values = null; + switch (c.getOptionType()) + { + case ConfirmationCallback.OK_CANCEL_OPTION: + out.print(messages.getString("callback.okCancel")); + choices = new String[] { + messages.getString("callback.ok"), + messages.getString("callback.cancel"), + messages.getString("callback.shortOk"), + messages.getString("callback.shortCancel") + }; + values = new int[] { + ConfirmationCallback.OK, ConfirmationCallback.CANCEL, + ConfirmationCallback.OK, ConfirmationCallback.CANCEL + }; + break; + case ConfirmationCallback.YES_NO_CANCEL_OPTION: + out.print(messages.getString("callback.yesNoCancel")); + choices = new String[] { + messages.getString("callback.yes"), + messages.getString("callback.no"), + messages.getString("callback.cancel"), + messages.getString("callback.shortYes"), + messages.getString("callback.shortNo"), + messages.getString("callback.shortCancel") + }; + values = new int[] { + ConfirmationCallback.YES, ConfirmationCallback.NO, + ConfirmationCallback.CANCEL, ConfirmationCallback.YES, + ConfirmationCallback.NO, ConfirmationCallback.CANCEL + }; + break; + case ConfirmationCallback.YES_NO_OPTION: + out.print(messages.getString("callback.yesNo")); + choices = new String[] { + messages.getString("callback.yes"), + messages.getString("callback.no"), + messages.getString("callback.shortYes"), + messages.getString("callback.shortNo") + }; + values = new int[] { + ConfirmationCallback.YES, ConfirmationCallback.NO, + ConfirmationCallback.YES, ConfirmationCallback.NO + }; + break; + case ConfirmationCallback.UNSPECIFIED_OPTION: + choices = c.getOptions(); + values = new int[choices.length]; + for (int i = 0; i < values.length; i++) + values[i] = i; + out.print('('); + for (int i = 0; i < choices.length; i++) + { + out.print(choices[i]); + if (i != choices.length - 1) + out.print(", "); + } + out.print(") ["); + out.print(choices[c.getDefaultOption()]); + out.print("] "); + break; + default: + throw new IllegalArgumentException(); + } + String reply = in.readLine(); + if (reply == null) + { + c.setSelectedIndex(c.getDefaultOption()); + return; + } + reply = reply.trim(); + for (int i = 0; i < choices.length; i++) + if (reply.equalsIgnoreCase(choices[i])) + { + c.setSelectedIndex(values[i]); + return; + } + c.setSelectedIndex(c.getDefaultOption()); + } + + protected void handleLanguage(LanguageCallback c) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + out.println(messages.getString("callback.language")); + String reply = null; + reply = in.readLine(); + if (reply == null) + { + c.setLocale(Locale.getDefault()); + } + else + { + c.setLocale(new Locale(reply.trim())); + } + } + + protected void handleName(NameCallback c) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + out.print(c.getPrompt()); + String name = in.readLine(); + if (name != null) + c.setName(name.trim()); + } + + protected void handlePassword(PasswordCallback c) throws IOException + { + out.print(c.getPrompt()); + BufferedReader in = + new BufferedReader(new InputStreamReader(System.in)); + String pass = in.readLine(); + c.setPassword(pass.toCharArray()); + } + + protected void handleTextInput(TextInputCallback c) throws IOException + { + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + out.print(c.getPrompt()); + String text = in.readLine(); + if (text != null) + c.setText(text); + } + + protected void handleTextOutput(TextOutputCallback c) + { + out.print(c.getMessage()); + } +} diff --git a/gnu/javax/security/auth/callback/DefaultCallbackHandler.java b/gnu/javax/security/auth/callback/DefaultCallbackHandler.java new file mode 100644 index 000000000..fc48782fe --- /dev/null +++ b/gnu/javax/security/auth/callback/DefaultCallbackHandler.java @@ -0,0 +1,109 @@ +/* DefaultCallbackHandler.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.callback; + +import java.util.Locale; + +import javax.security.auth.callback.ChoiceCallback; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.LanguageCallback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.TextOutputCallback; + +/** + * This trivial implementation of {@link CallbackHandler} sets its + * {@link Callback} arguments to default values, with no user interaction. + */ +public class DefaultCallbackHandler extends AbstractCallbackHandler +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public DefaultCallbackHandler() + { + super("DEFAULT"); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + protected void handleChoice(ChoiceCallback c) + { + c.setSelectedIndex(c.getDefaultChoice()); + } + + protected void handleConfirmation(ConfirmationCallback c) + { + if (c.getOptionType() == ConfirmationCallback.YES_NO_OPTION) + c.setSelectedIndex(ConfirmationCallback.NO); + else if (c.getOptionType() == ConfirmationCallback.YES_NO_CANCEL_OPTION) + c.setSelectedIndex(ConfirmationCallback.NO); + else if (c.getOptionType() == ConfirmationCallback.OK_CANCEL_OPTION) + c.setSelectedIndex(ConfirmationCallback.OK); + else + c.setSelectedIndex(c.getDefaultOption()); + } + + protected void handleLanguage(LanguageCallback c) + { + c.setLocale(Locale.getDefault()); + } + + protected void handleName(NameCallback c) + { + c.setName(System.getProperty("user.name")); + } + + protected void handlePassword(PasswordCallback c) + { + c.setPassword(new char[0]); + } + + protected void handleTextInput(TextInputCallback c) + { + c.setText(""); + } + + protected void handleTextOutput(TextOutputCallback c) + { + } +} diff --git a/gnu/javax/security/auth/callback/GnuCallbacks.java b/gnu/javax/security/auth/callback/GnuCallbacks.java new file mode 100644 index 000000000..9fd72f926 --- /dev/null +++ b/gnu/javax/security/auth/callback/GnuCallbacks.java @@ -0,0 +1,64 @@ +/* GnuCallbacks.java -- Provider for callback implementations. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.callback; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; + +public final class GnuCallbacks extends Provider +{ + public GnuCallbacks() + { + super("GNU-CALLBACKS", 2.1, "Implementations of various callback handlers."); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + put("CallbackHandler.Default", DefaultCallbackHandler.class.getName()); + put("CallbackHandler.Console", ConsoleCallbackHandler.class.getName()); + put("CallbackHandler.AWT", AWTCallbackHandler.class.getName()); + put("CallbackHandler.Swing", SwingCallbackHandler.class.getName()); + + return null; + } + }); + } +} diff --git a/gnu/javax/security/auth/callback/SwingCallbackHandler.java b/gnu/javax/security/auth/callback/SwingCallbackHandler.java new file mode 100644 index 000000000..8e3e46eff --- /dev/null +++ b/gnu/javax/security/auth/callback/SwingCallbackHandler.java @@ -0,0 +1,587 @@ + /* SwingCallbackHandler.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.callback; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import java.io.IOException; + +import java.util.Locale; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.ChoiceCallback; +import javax.security.auth.callback.ConfirmationCallback; +import javax.security.auth.callback.LanguageCallback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.TextInputCallback; +import javax.security.auth.callback.TextOutputCallback; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; + +public class SwingCallbackHandler extends AbstractCallbackHandler +{ + public SwingCallbackHandler () + { + super ("SWING"); + } + + protected void handleChoice (final ChoiceCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + dialog.setResizable (false); + Container content = dialog.getContentPane (); + GridBagLayout layout = new GridBagLayout (); + content.setLayout (layout); + JLabel prompt = new JLabel (callback.getPrompt (), JLabel.LEFT); + content.add (prompt, new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.WEST, + GridBagConstraints.NONE, + new Insets (5, 5, 5, 5), 5, 5)); + + String[] choices = callback.getChoices (); + final JList choicesList = new JList (choices); + JScrollPane choicesPane = new JScrollPane (choicesList, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + final int defaultChoice = callback.getDefaultChoice (); + choicesList.setSelectedIndex (defaultChoice); + choicesList.setSelectionMode (callback.allowMultipleSelections () + ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION + : ListSelectionModel.SINGLE_SELECTION); + content.add (choicesPane, new GridBagConstraints (0, 1, 1, 1, 1.0, 1.0, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets (0, 10, 0, 10), 5, 5)); + + JPanel confirmButtons = new JPanel (); + confirmButtons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton ok = new JButton (messages.getString ("callback.ok")); + confirmButtons.add (cancel); + confirmButtons.add (ok); + content.add (confirmButtons, new GridBagConstraints (0, 2, 1, 1, 0, 0, + GridBagConstraints.EAST, + GridBagConstraints.NONE, + new Insets (5, 5, 5, 5), + 0, 0)); + dialog.getRootPane ().setDefaultButton (ok); + + cancel.addActionListener (new ActionListener () + { + public void actionPerformed (final ActionEvent ae) + { + callback.setSelectedIndex (defaultChoice); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }); + ok.addActionListener (new ActionListener () + { + public void actionPerformed (final ActionEvent ae) + { + if (callback.allowMultipleSelections ()) + { + int[] indices = choicesList.getSelectedIndices (); + if (indices != null && indices.length > 0) + callback.setSelectedIndexes (indices); + else + callback.setSelectedIndex (defaultChoice); + } + else + { + int selected = choicesList.getSelectedIndex (); + if (selected != -1) + callback.setSelectedIndex (selected); + else + callback.setSelectedIndex (defaultChoice); + } + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }); + + dialog.pack (); + dialog.setSize (new Dimension (400, 400)); + dialog.setVisible (true); + waitForInput (dialog, callback); + } + + protected void handleConfirmation (final ConfirmationCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + switch (callback.getMessageType ()) + { + case ConfirmationCallback.ERROR: + dialog.setTitle (messages.getString ("callback.error")); + break; + case ConfirmationCallback.WARNING: + dialog.setTitle (messages.getString ("callback.warning")); + break; + case ConfirmationCallback.INFORMATION: + dialog.setTitle (messages.getString ("callback.information")); + break; + } + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + String prompt = callback.getPrompt (); + if (prompt != null) + { + content.add (new JLabel (prompt), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.WEST, + GridBagConstraints.NONE, + new Insets (5, 5, 5, 25), 0, 0)); + } + + final String[] options = callback.getOptions (); + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (options != null) + { + for (int i = 0; i < options.length; i++) + { + if (cmd.equals (options[i])) + { + callback.setSelectedIndex (i); + break; + } + } + } + else + { + if (cmd.equals ("cancel")) + callback.setSelectedIndex (ConfirmationCallback.CANCEL); + else if (cmd.equals ("okay")) + callback.setSelectedIndex (ConfirmationCallback.OK); + else if (cmd.equals ("yes")) + callback.setSelectedIndex (ConfirmationCallback.YES); + else if (cmd.equals ("no")) + callback.setSelectedIndex (ConfirmationCallback.NO); + } + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + switch (callback.getOptionType ()) + { + case ConfirmationCallback.YES_NO_CANCEL_OPTION: + { + JButton cancel = new JButton (messages.getString ("callback.cancel")); + buttons.add (cancel); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + } + /* Fall-through. */ + case ConfirmationCallback.YES_NO_OPTION: + { + JButton yes = new JButton (messages.getString ("callback.yes")); + JButton no = new JButton (messages.getString ("callback.no")); + buttons.add (no); + buttons.add (yes); + yes.setActionCommand ("yes"); + yes.addActionListener (listener); + no.setActionCommand ("no"); + no.addActionListener (listener); + dialog.getRootPane ().setDefaultButton (yes); + } + break; + case ConfirmationCallback.OK_CANCEL_OPTION: + { + JButton okay = new JButton (messages.getString ("callback.ok")); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + buttons.add (cancel); + buttons.add (okay); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + dialog.getRootPane ().setDefaultButton (okay); + } + break; + case ConfirmationCallback.UNSPECIFIED_OPTION: + for (int i = 0; i < options.length; i++) + { + JButton button = new JButton (options[i]); + buttons.add (button); + button.setActionCommand (options[i]); + button.addActionListener (listener); + if (i == options.length - 1) + dialog.getRootPane ().setDefaultButton (button); + } + } + content.add (buttons, + new GridBagConstraints (0, GridBagConstraints.RELATIVE, + 1, 1, 1, 1, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.BOTH, + new Insets (5, 5, 5, 5), 0, 0)); + dialog.setResizable (false); + dialog.pack (); + dialog.setVisible (true); + waitForInput (dialog, callback); + } + + protected void handleLanguage (final LanguageCallback callback) + throws IOException + { + Locale locale = Locale.getDefault (); + Locale[] locales = Locale.getAvailableLocales (); + String[] localeNames = new String[locales.length+1]; + int defaultIndex = 0; + for (int i = 0; i < locales.length; i++) + { + localeNames[i+1] = locales[i].getDisplayLanguage (locales[i]); + String country = locales[i].getDisplayCountry (locales[i]); + if (country.length () > 0) + localeNames[i+1] += " (" + country + ")"; + if (locales[i].equals (locale)) + defaultIndex = i; + } + locales[0] = locale; + localeNames[0] = locale.getDisplayLanguage (locale); + String country = locale.getDisplayCountry (locale); + if (country.length () > 0) + localeNames[0] += " (" + country + ")"; + ChoiceCallback cb = new ChoiceCallback (messages.getString ("callback.language"), + localeNames, 0, + false); + handleChoice (cb); + int selected = cb.getSelectedIndexes ()[0]; + if (selected > 0) + callback.setLocale (locales[selected - 1]); + else + callback.setLocale (locale); + } + + protected void handleName (final NameCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + content.add (new JLabel (callback.getPrompt ()), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.NORTHEAST, + GridBagConstraints.VERTICAL, + new Insets (10, 10, 15, 5), 0, 0)); + + final JTextField name = new JTextField (); + name.setColumns (20); + String _name; + if ((_name = callback.getDefaultName ()) != null) + name.setText (_name); + content.add (name, new GridBagConstraints (1, 0, 1, 1, 1, 1, + GridBagConstraints.NORTHWEST, + GridBagConstraints.BOTH, + new Insets (10, 5, 15, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (cmd.equals ("okay")) + callback.setName (name.getText ()); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton okay = new JButton (messages.getString ("callback.ok")); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + buttons.add (cancel); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + buttons.add (okay); + content.add (buttons, new GridBagConstraints (0, 1, 2, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (false); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + protected void handlePassword (final PasswordCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + content.add (new JLabel (callback.getPrompt ()), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.NORTHEAST, + GridBagConstraints.VERTICAL, + new Insets (10, 10, 15, 5), 0, 0)); + + final JPasswordField password = new JPasswordField (); + password.setColumns (20); + password.setEchoChar (callback.isEchoOn () ? '\u0000' : '\u2022'); + content.add (password, new GridBagConstraints (1, 0, 1, 1, 1, 1, + GridBagConstraints.NORTHWEST, + GridBagConstraints.BOTH, + new Insets (10, 5, 15, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (cmd.equals ("okay")) + callback.setPassword (password.getPassword ()); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton okay = new JButton (messages.getString ("callback.ok")); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + buttons.add (cancel); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + buttons.add (okay); + content.add (buttons, new GridBagConstraints (0, 1, 2, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (false); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + protected void handleTextInput (final TextInputCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + content.add (new JLabel (callback.getPrompt ()), + new GridBagConstraints (0, 0, 1, 1, 0, 0, + GridBagConstraints.NORTHWEST, + GridBagConstraints.NONE, + new Insets (10, 10, 15, 5), 0, 0)); + + final JTextArea text = new JTextArea (24, 80); + text.setEditable (true); + String _text; + if ((_text = callback.getDefaultText ()) != null) + text.setText (_text); + text.setFont (new Font ("Monospaced", Font.PLAIN, 12)); + JScrollPane textPane = new JScrollPane (text, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + content.add (textPane, + new GridBagConstraints (0, 1, 1, 1, 1, 1, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets (5, 10, 5, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + String cmd = ae.getActionCommand (); + if (cmd.equals ("okay")) + callback.setText (text.getText ()); + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JPanel buttons = new JPanel (); + buttons.setLayout (new FlowLayout (FlowLayout.RIGHT)); + JButton cancel = new JButton (messages.getString ("callback.cancel")); + JButton okay = new JButton (messages.getString ("callback.ok")); + cancel.setActionCommand ("cancel"); + cancel.addActionListener (listener); + buttons.add (cancel); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + buttons.add (okay); + content.add (buttons, new GridBagConstraints (0, 2, 1, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (true); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + protected void handleTextOutput (final TextOutputCallback callback) + throws IOException + { + final JDialog dialog = new JDialog (); + switch (callback.getMessageType ()) + { + case TextOutputCallback.ERROR: + dialog.setTitle (messages.getString ("callback.error")); + break; + case TextOutputCallback.WARNING: + dialog.setTitle (messages.getString ("callback.warning")); + break; + case TextOutputCallback.INFORMATION: + dialog.setTitle (messages.getString ("callback.information")); + break; + } + Container content = dialog.getContentPane (); + content.setLayout (new GridBagLayout ()); + + final JTextArea text = new JTextArea (24, 80); + text.setEditable (false); + text.setText (callback.getMessage ()); + text.setFont (new Font ("Monospaced", Font.PLAIN, 12)); + JScrollPane textPane = new JScrollPane (text, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + content.add (textPane, + new GridBagConstraints (0, 0, 1, 1, 1, 1, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets (10, 10, 5, 10), 0, 0)); + + ActionListener listener = new ActionListener () + { + public void actionPerformed (ActionEvent ae) + { + dialog.setVisible (false); + synchronized (callback) + { + callback.notify (); + } + } + }; + + JButton okay = new JButton (messages.getString ("callback.ok")); + okay.setActionCommand ("okay"); + okay.addActionListener (listener); + content.add (okay, new GridBagConstraints (0, 1, 1, 1, 0, 0, + GridBagConstraints.SOUTHEAST, + GridBagConstraints.NONE, + new Insets (0, 10, 10, 10), 0, 0)); + + dialog.setResizable (true); + dialog.pack (); + dialog.setVisible (true); + dialog.getRootPane ().setDefaultButton (okay); + waitForInput (dialog, callback); + } + + private void waitForInput (JDialog dialog, Callback callback) + { + synchronized (callback) + { + while (dialog.isVisible ()) + { + try + { + callback.wait (1000); + } + catch (InterruptedException ignored) + { + } + } + } + dialog.dispose (); + } +} \ No newline at end of file diff --git a/gnu/javax/security/auth/login/ConfigFileParser.java b/gnu/javax/security/auth/login/ConfigFileParser.java new file mode 100644 index 000000000..f6c39bb3d --- /dev/null +++ b/gnu/javax/security/auth/login/ConfigFileParser.java @@ -0,0 +1,338 @@ +/* ConfigFileParser.java -- JAAS Login Configuration default syntax parser + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.login; + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.security.auth.login.AppConfigurationEntry; + +/** + * A parser that knows how to interpret JAAS Login Module Configuration files + * written in the default syntax which is interpreted as adhering to + * the following grammar: + * + *

    + *   CONFIG              ::= APP_OR_OTHER_ENTRY+
    + *   APP_OR_OTHER_ENTRY  ::= APP_NAME_OR_OTHER JAAS_CONFIG_BLOCK
    + *   APP_NAME_OR_OTHER   ::= APP_NAME
    + *                         | 'other'
    + *   JAAS_CONFIG_BLOCK   ::= '{' (LOGIN_MODULE_ENTRY ';')+ '}' ';'
    + *   LOGIN_MODULE_ENTRY  ::= MODULE_CLASS FLAG MODULE_OPTION* ';'
    + *   FLAG                ::= 'required'
    + *                         | 'requisite'
    + *                         | 'sufficient'
    + *                         | 'optional'
    + *   MODULE_OPTION       ::= PARAM_NAME '=' PARAM_VALUE
    + *
    + *   APP_NAME     ::= JAVA_IDENTIFIER
    + *   MODULE_CLASS ::= JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)*
    + *   PARAM_NAME   ::= STRING
    + *   PARAM_VALUE  ::= '"' STRING '"' | ''' STRING ''' | STRING
    + * 
    + * + *

    This parser handles UTF-8 entities when used as APP_NAME and PARAM_VALUE. + * It also checks for the use of Java identifiers used in MODULE_CLASS, thus + * minimizing the risks of having {@link java.lang.ClassCastException}s thrown + * at runtime due to syntactically invalid names.

    + * + *

    In the above context, a JAVA_IDENTIFIER is a sequence of tokens, + * separated by the character '.'. Each of these tokens obeys the following:

    + * + *
      + *
    1. its first character yields true when used as an input to + * the {@link java.lang.Character#isJavaIdentifierStart(char)}, and
    2. + *
    3. all remaining characters, yield true when used as an + * input to {@link java.lang.Character#isJavaIdentifierPart(char)}.
    4. + *
    + */ +public final class ConfigFileParser +{ + // Constants and fields + // -------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + private static final void debug(String m) {if (DEBUG) System.err.println(m);}; + + private ConfigFileTokenizer cft; + private Map map = new HashMap(); + + // Constructor(s) + // -------------------------------------------------------------------------- + + // default 0-arguments constructor + + // Class methods + // -------------------------------------------------------------------------- + + // Instance methods + // -------------------------------------------------------------------------- + + /** + * Returns the parse result as a {@link Map} where the keys are application + * names, and the entries are {@link List}s of {@link AppConfigurationEntry} + * entries, one for each login module entry, in the order they were + * encountered, for that application name in the just parsed configuration + * file. + */ + public Map getLoginModulesMap() + { + return map; + } + + /** + * Parses the {@link Reader}'s contents assuming it is in the default + * syntax. + * + * @param r the {@link Reader} whose contents are assumed to be a JAAS Login + * Configuration Module file written in the default syntax. + * @throws IOException if an exception occurs while parsing the input. + */ + public void parse(Reader r) throws IOException + { + initParser(r); + + while (parseAppOrOtherEntry()) + ; // do nothing + } + + private void initParser(Reader r) throws IOException + { + map.clear(); + + cft = new ConfigFileTokenizer(r); + } + + /** + * @return true if an APP_OR_OTHER_ENTRY was correctly parsed. + * Returns false otherwise. + * @throws IOException if an exception occurs while parsing the input. + */ + private boolean parseAppOrOtherEntry() throws IOException + { + int c = cft.nextToken(); + if (c == ConfigFileTokenizer.TT_EOF) + return false; + + if (c != ConfigFileTokenizer.TT_WORD) + { + cft.pushBack(); + return false; + } + + String appName = cft.sval; + debug("DEBUG: APP_NAME_OR_OTHER = " + appName); + if (cft.nextToken() != '{') + abort("Missing '{' after APP_NAME_OR_OTHER"); + + List lmis = new ArrayList(); + while (parseACE(lmis)) + ; // do nothing + + c = cft.nextToken(); + if (c != '}') + abort("Was expecting '}' but found " + (char) c); + + c = cft.nextToken(); + if (c != ';') + abort("Was expecting ';' but found " + (char) c); + + List listOfACEs = (List) map.get(appName); + if (listOfACEs == null) + { + listOfACEs = new ArrayList(); + map.put(appName, listOfACEs); + } + listOfACEs.addAll(lmis); + return !appName.equalsIgnoreCase("other"); + } + + /** + * @return true if a LOGIN_MODULE_ENTRY was correctly parsed. + * Returns false otherwise. + * @throws IOException if an exception occurs while parsing the input. + */ + private boolean parseACE(List listOfACEs) throws IOException + { + int c = cft.nextToken(); + if (c != ConfigFileTokenizer.TT_WORD) + { + cft.pushBack(); + return false; + } + + String clazz = validateClassName(cft.sval); + debug("DEBUG: MODULE_CLASS = " + clazz); + + if (cft.nextToken() != ConfigFileTokenizer.TT_WORD) + abort("Was expecting FLAG but found none"); + + String flag = cft.sval; + debug("DEBUG: FLAG = " + flag); + AppConfigurationEntry.LoginModuleControlFlag f = null; + if (flag.equalsIgnoreCase("required")) + f = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED; + else if (flag.equalsIgnoreCase("requisite")) + f = AppConfigurationEntry.LoginModuleControlFlag.REQUISITE; + else if (flag.equalsIgnoreCase("sufficient")) + f = AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT; + else if (flag.equalsIgnoreCase("optional")) + f = AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL; + else + abort("Unknown Flag: " + flag); + + Map options = new HashMap(); + String paramName, paramValue; + c = cft.nextToken(); + while (c != ';') + { + if (c != ConfigFileTokenizer.TT_WORD) + abort("Was expecting PARAM_NAME but got '" + ((char) c) + "'"); + + paramName = cft.sval; + debug("DEBUG: PARAM_NAME = " + paramName); + if (cft.nextToken() != '=') + abort("Missing '=' after PARAM_NAME"); + + c = cft.nextToken(); + if (c != '"' && c != '\'') + debug(" WARN: Was expecting a quoted string but got no quote " + + "character. Assume unquoted string"); + + paramValue = expandParamValue(cft.sval); + debug("DEBUG: PARAM_VALUE = " + paramValue); + options.put(paramName, paramValue); + + c = cft.nextToken(); + } + + AppConfigurationEntry ace = new AppConfigurationEntry(clazz, f, options); + debug("DEBUG: LOGIN_MODULE_ENTRY = " + ace); + listOfACEs.add(ace); + return true; + } + + private void abort(String m) throws IOException + { + debug("ERROR: " + m); + debug("DEBUG: Map (so far) = " + String.valueOf(map)); + throw new IOException(m); + } + + private String validateClassName(String cn) throws IOException + { + if (cn.startsWith(".") || cn.endsWith(".")) + abort("MODULE_CLASS MUST NOT start or end with a '.'"); + + String[] tokens = cn.split("."); + for (int i = 0; i < tokens.length; i++) + { + String t = tokens[i]; + if (Character.isJavaIdentifierStart(cn.toCharArray()[0])) + abort(""); + + // we dont check the rest of the characters for isJavaIdentifierPart() + // because that's what the tokenizer does. + } + + return cn; + } + + /** + * The documentation of the {@link javax.security.auth.login.Configuration} + * states that: "...If a String in the form, ${system.property}, occurs in + * the value, it will be expanded to the value of the system property.". + * This method ensures this is the case. If such a string can not be expanded + * then it is left AS IS, assuming the LoginModule knows what to do with it. + * + *

    IMPORTANT: This implementation DOES NOT handle embedded ${} + * constructs. + * + * @param s the raw parameter value, incl. eventually strings of the form + * ${system.property}. + * @return the input string with every occurence of + * ${system.property} replaced with the value of the + * corresponding System property at the time of this method invocation. If + * the string is not a known System property name, then the complete sequence + * (incl. the ${} characters are passed AS IS. + */ + private String expandParamValue(String s) + { + String result = s; + try + { + int searchNdx = 0; + while (searchNdx < result.length()) + { + int i = s.indexOf("${", searchNdx); + if (i == -1) + break; + + int j = s.indexOf("}", i + 2); + if (j == -1) + { + debug(" WARN: Found a ${ prefix with no } suffix. Ignore"); + break; + } + + String sysPropName = s.substring(i + 2, j); + debug("DEBUG: Found a reference to System property " + sysPropName); + String sysPropValue = System.getProperty(sysPropName); + debug("DEBUG: Resolved " + sysPropName + " to '" + sysPropValue + "'"); + if (sysPropValue != null) + { + result = s.substring(0, i) + sysPropValue + s.substring(j + 1); + searchNdx = i + sysPropValue.length(); + } + else + searchNdx = j + 1; + } + } + catch (Exception x) + { + debug(" WARN: Exception while expanding " + s + ". Ignore: " + x); + } + + return result; + } +} diff --git a/gnu/javax/security/auth/login/ConfigFileTokenizer.java b/gnu/javax/security/auth/login/ConfigFileTokenizer.java new file mode 100644 index 000000000..2cfe916e4 --- /dev/null +++ b/gnu/javax/security/auth/login/ConfigFileTokenizer.java @@ -0,0 +1,243 @@ +/* ConfigFileTokenizer.java -- JAAS Login Configuration default syntax tokenizer + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.login; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; + +/** + * A UTF-8 friendly, JAAS Login Module Configuration file tokenizer written in + * the deault syntax. This class emulates, to a certain extent, the behavior of + * a {@link java.io.SrteamTokenizer} instance st, when set as + * follows: + * + *

    + *  st.resetSyntax();
    + *  st.lowerCaseMode(false);
    + *  st.slashSlashComments(true);
    + *  st.slashStarComments(true);
    + *  st.eolIsSignificant(false);
    + *  st.wordChars('_', '_');
    + *  st.wordChars('$', '$');
    + *  st.wordChars('A', 'Z');
    + *  st.wordChars('a', 'z');
    + *  st.wordChars('0', '9');
    + *  st.wordChars('.', '.');
    + *  st.whitespaceChars(' ', ' ');
    + *  st.whitespaceChars('\t', '\t');
    + *  st.whitespaceChars('\f', '\f');
    + *  st.whitespaceChars('\r', '\r');
    + *  st.whitespaceChars('\n', '\n');
    + *  st.quoteChar('"');
    + *  st.quoteChar('\'');
    + *  
    + * + *

    The most important (negative) difference with a + * {@link java.io.StreamTokenizer} is that this tokenizer does not properly + * handle C++ and Java // style comments in the middle of the line. It only + * ignores them if/when found at the start of the line.

    + */ +public class ConfigFileTokenizer +{ + // Constants and fields + // -------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + private static final void debug(String m) {if (DEBUG) System.err.println(m);}; + + /** A constant indicating that the end of the stream has been read. */ + public static final int TT_EOF = -1; + /** A constant indicating that a word token has been read. */ + public static final int TT_WORD = -3; + /** A constant indicating that no tokens have been read yet. */ + private static final int TT_NONE = -4; + + public String sval; + public int ttype; + + private BufferedReader br; + boolean initialised; + private StringBuffer sb; + private int sbNdx; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** Trivial constructor. */ + ConfigFileTokenizer(Reader r) + { + super(); + + br = r instanceof BufferedReader ? (BufferedReader) r : new BufferedReader(r); + initialised = false; + } + + // Class methods + // -------------------------------------------------------------------------- + + // Instance methods + // -------------------------------------------------------------------------- + + public int nextToken() throws IOException + { + if (!initialised) + init(); + + if (sbNdx >= sb.length()) + return TT_EOF; + + skipWhitespace(); + + if (sbNdx >= sb.length()) + return TT_EOF; + + int endNdx; + if (Character.isJavaIdentifierPart(sb.charAt(sbNdx))) + { + endNdx = sbNdx + 1; + while (Character.isJavaIdentifierPart(sb.charAt(endNdx)) + || sb.charAt(endNdx) == '.') + endNdx++; + + ttype = TT_WORD; + sval = sb.substring(sbNdx, endNdx); + sbNdx = endNdx; + return ttype; + } + + int c = sb.charAt(sbNdx); + if (c == '{' || c == '}' || c == ';' || c == '=') + { + ttype = c; + sbNdx++; + return ttype; + } + + if (c == '"' || c == '\'') + { + ttype = c; + String quote = sb.substring(sbNdx, sbNdx + 1); + int i = sbNdx + 1; + while (true) + { + // find a candidate + endNdx = sb.indexOf(quote, i); + if (endNdx == -1) + abort("Missing closing quote: " + quote); + + // found one; is it escaped? + if (sb.charAt(endNdx - 1) != '\\') + break; + + i++; + continue; + } + + endNdx++; + sval = sb.substring(sbNdx, endNdx); + sbNdx = endNdx; + return ttype; + } + + abort("Unknown character: " + sb.charAt(sbNdx)); + return Integer.MIN_VALUE; + } + + public void pushBack() + { + sbNdx -= ttype != TT_WORD ? 1 : sval.length(); + } + + private void init() throws IOException + { + sb = new StringBuffer(); + String line; + while ((line = br.readLine()) != null) + { + line = line.trim(); + if (line.length() == 0) + continue; + + if (line.startsWith("#") || line.startsWith("//")) + continue; + + sb.append(line).append(" "); + } + + sbNdx = 0; + sval = null; + ttype = TT_NONE; + + initialised = true; + } + + private void skipWhitespace() throws IOException + { + int endNdx; + while (sbNdx < sb.length()) + if (Character.isWhitespace(sb.charAt(sbNdx))) + { + sbNdx++; + while (sbNdx < sb.length() && Character.isWhitespace(sb.charAt(sbNdx))) + sbNdx++; + + continue; + } + else if (sb.charAt(sbNdx) == '/' && sb.charAt(sbNdx + 1) == '*') + { + endNdx = sb.indexOf("*/", sbNdx + 2); + if (endNdx == -1) + abort("Missing closing */ sequence"); + + sbNdx = endNdx + 2; + continue; + } + else + break; + } + + private void abort(String m) throws IOException + { + debug("DEBUG: " + m); + debug("DEBUG: sb = " + sb); + debug("DEBUG: sbNdx = " + sbNdx); + throw new IOException(m); + } +} diff --git a/gnu/javax/security/auth/login/GnuConfiguration.java b/gnu/javax/security/auth/login/GnuConfiguration.java new file mode 100644 index 000000000..f0b8594a0 --- /dev/null +++ b/gnu/javax/security/auth/login/GnuConfiguration.java @@ -0,0 +1,450 @@ +/* GnuConfiguration.java -- GNU Classpath implementation of JAAS Configuration + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.security.auth.login; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.Security; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.security.auth.AuthPermission; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + +/** + * An implementation of the {@link Configuration} class which interprets JAAS + * Login Configuration files written in the default syntax described in + * the publicly available documentation of that class. A more formal definition + * of this syntax is as follows: + * + *
    + *   CONFIG              ::= APP_OR_OTHER_ENTRY+
    + *   APP_OR_OTHER_ENTRY  ::= APP_NAME_OR_OTHER JAAS_CONFIG_BLOCK
    + *   APP_NAME_OR_OTHER   ::= APP_NAME
    + *                         | 'other'
    + *   JAAS_CONFIG_BLOCK   ::= '{' (LOGIN_MODULE_ENTRY ';')+ '}' ';'
    + *   LOGIN_MODULE_ENTRY  ::= MODULE_CLASS FLAG MODULE_OPTION* ';'
    + *   FLAG                ::= 'required'
    + *                         | 'requisite'
    + *                         | 'sufficient'
    + *                         | 'optional'
    + *   MODULE_OPTION       ::= PARAM_NAME '=' PARAM_VALUE
    + *
    + *   APP_NAME     ::= JAVA_IDENTIFIER
    + *   MODULE_CLASS ::= JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)*
    + *   PARAM_NAME   ::= STRING
    + *   PARAM_VALUE  ::= '"' STRING '"' | ''' STRING ''' | STRING
    + * 
    + * + *

    This implementation will specifically attempt to process one or more + * Login Configuration files in the following locations, and when found parse + * them and merge their contents. The locations, and the order in which they are + * investigated, follows:

    + * + *
      + *
    1. If the following Security properties: + * java.security.auth.login.config.url.N, where N + * is a digit, from 1 to an arbitrary number, are defined, then + * the value of each of those properties will be considered as a JAAS Login + * Configuration file written in the default syntax. This implementation will + * attempt parsing all such files. + * + *

      It is worth noting the following: + *

        + *
      • The GNU Classpath security file, named classpath.security, + * where all Security properties are encoded, is usually located in + * /usr/local/classpath/lib/security folder.
      • + * + *
      • The numbers used in the properties + * java.security.auth.login.config.url.N MUST be sequential, + * with no breaks in-between.
      • + *
      + *

      + * + *

      If at least one of the designated Configuration files was found, and + * was parsed correctly, then no other location will be inspected.

    2. + * + *
    3. If the System property named java.security.auth.login.config + * is not null or empty, its contents are then interpreted as a URL to a + * JAAS Login Configuration file written in the default syntax. + * + *

      If this System property is defined, and the file it refers to was + * parsed correctly, then no other location will be inspected.

    4. + * + *
    5. If a file named .java.login.config or java.login.config + * (in that order) is found in the location referenced by the value of the + * System property user.home, then that file is parsed as a JAAS Login + * Configuration written in the default syntax.
    6. + * + *
    7. If none of the above resulted in a correctly parsed JAAS Login + * Configuration file, then this implementation will install a Null + * Configuration which basically does not recognize any Application.
    8. + *
    + */ +public final class GnuConfiguration extends Configuration +{ + // Constants and fields + // -------------------------------------------------------------------------- + + private static final boolean DEBUG = true; + private static final void debug(String m) {if (DEBUG) System.err.println(m);}; + + /** + * The internal map of login modules keyed by application name. Each entry in + * this map is a {@link List} of {@link AppConfigurationEntry}s for that + * application name. + */ + private Map loginModulesMap; + /** Our reference to our default syntax parser. */ + private ConfigFileParser cp; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** Trivial 0-arguments Constructor. */ + public GnuConfiguration() + { + super(); + + loginModulesMap = new HashMap(); + cp = new ConfigFileParser(); + init(); + } + + // Class methods + // -------------------------------------------------------------------------- + + // Instance methods + // -------------------------------------------------------------------------- + + // Configuration abstract methods implementation ---------------------------- + + /* (non-Javadoc) + * @see javax.security.auth.login.Configuration#getAppConfigurationEntry(java.lang.String) + */ + public AppConfigurationEntry[] getAppConfigurationEntry(String appName) + { + if (appName == null) + return null; + + appName = appName.trim(); + if (appName.length() == 0) + return null; + + List loginModules = (List) loginModulesMap.get(appName); + if (loginModules == null || loginModules.size() == 0) + return null; + + debug("DEBUG: " + appName + " -> " + loginModules.size() + " entry(ies)"); + return (AppConfigurationEntry[]) loginModules.toArray(new AppConfigurationEntry[0]); + } + + /** + * Refreshes and reloads this Configuration. + * + *

    This method causes this Configuration object to refresh / + * reload its contents following the locations and logic described above in + * the class documentation section.

    + * + * @throws SecurityException if the caller does not have an + * {@link AuthPermission} for the action named + * refreshLoginConfiguration. + * @see {@link AuthPermission} + */ + public void refresh() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new AuthPermission("refreshLoginConfiguration")); + + loginModulesMap.clear(); + init(); + } + + // helper methods ----------------------------------------------------------- + + /** + * Attempts to find and parse JAAS Login Configuration file(s) written in + * the default syntax. The locations searched are as descibed in the class + * documentation. + */ + private void init() + { + if (processSecurityProperties()) + debug(" INFO: Using login configuration defined by Security property(ies)"); + else if (processSystemProperty()) + debug(" INFO: Using login configuration defined by System property"); + else if (processUserHome()) + debug(" INFO: Using login configuration defined in ${user.home}"); + else + debug(" WARN: No login configuration file found"); + } + + /** + * Attempts to locate and parse one or more JAAS Login Configuration files + * defined as the values of the Security properties + * java.security.auth.login.config.url.N. + * + * @return true if it succeeds, and false + * otherwsie. + */ + private boolean processSecurityProperties() + { + boolean result = false; + int counter = 0; + String s; + while (true) + try + { + counter++; + s = Security.getProperty("java.security.auth.login.config.url." + + counter); + if (s == null) + break; + + s = s.trim(); + if (s.length() != 0) + { + debug("DEBUG: java.security.auth.login.config.url." + counter + + " = " + s); + parseConfig(getInputStreamFromURL(s)); + result = true; + } + } + catch (Throwable t) + { + debug(" WARN: Exception while handling Security property at #" + + counter + ". Continue: " + t); + } + return result; + } + + /** + * Attempts to open a designated string as a well-formed {@link URL}. If a + * {@link MalformedURLException} occurs, this method then tries to open that + * string as a {@link File} (with the same name). If it succeeds, an + * {@link InputStream} is constructed and returned. + * + * @param s + * the designated name of either a {@link URL} or a {@link File} + * assumed to contain a JAAS Login Configuration in the default + * syntax. + * @return an {@link InputStream} around the data source. + * @throws IOException + * if an exception occurs during the operation. + */ + private InputStream getInputStreamFromURL(String s) throws IOException + { + InputStream result = null; + try + { + URL url = new URL(s); + result = url.openStream(); + } + catch (MalformedURLException x) + { + debug(" WARN: Failed opening as URL: " + s + ". Will try as File"); + result = new FileInputStream(s); + } + return result; + } + + /** + * Attempts to locate and parse a JAAS Login Configuration file defined as the + * value of the System property java.security.auth.login.config. + * + * @return true if it succeeds, and false + * otherwsie. + */ + private boolean processSystemProperty() + { + boolean result = false; + try + { + String s = System.getProperty("java.security.auth.login.config"); + if (s != null) + { + s = s.trim(); + if (s.length() != 0) + { + debug("DEBUG: java.security.auth.login.config = " + s); + parseConfig(getInputStreamFromURL(s)); + result = true; + } + } + } + catch (Throwable t) + { + debug(" WARN: Exception while handling System property. Continue: " + t); + } + return result; + } + + /** + * Attempts to locate and parse a JAAS Login Configuration file named either + * as .java.login.config or java.login.config (without the + * leading dot) in the folder referenced by the System property + * user.home. + * + * @return true if it succeeds, and false + * otherwsie. + */ + private boolean processUserHome() + { + boolean result = false; + try + { + File userHome = getUserHome(); + if (userHome == null) + return result; + + File jaasFile; + jaasFile = getConfigFromUserHome(userHome, ".java.login.config"); + if (jaasFile == null) + jaasFile = getConfigFromUserHome(userHome, "java.login.config"); + + if (jaasFile == null) + { + debug(" WARN: Login Configuration file, in " + userHome + + ", does not exist or is inaccessible"); + return result; + } + + FileInputStream fis = new FileInputStream(jaasFile); + parseConfig(fis); + result = true; + } + catch (Throwable t) + { + debug(" WARN: Exception while handling ${user.home}: " + t); + } + return result; + } + + private void parseConfig(InputStream configStream) throws IOException + { + cp.parse(new InputStreamReader(configStream, "UTF-8")); + Map loginModulesMap = cp.getLoginModulesMap(); + mergeLoginModules(loginModulesMap); + } + + private void mergeLoginModules(Map otherLoginModules) + { + if (otherLoginModules == null || otherLoginModules.size() < 1) + return; + + for (Iterator it = otherLoginModules.keySet().iterator(); it.hasNext();) + { + String appName = (String) it.next(); + List thatListOfACEs = (List) otherLoginModules.get(appName); + if (thatListOfACEs == null || thatListOfACEs.size() < 1) + continue; + + List thisListsOfACEs = (List) loginModulesMap.get(appName); + if (thisListsOfACEs == null) + loginModulesMap.put(appName, thatListOfACEs); + else + thisListsOfACEs.addAll(thatListOfACEs); + } + } + + private File getUserHome() + { + String uh = System.getProperty("user.home"); + if (uh == null || uh.trim().length() == 0) + { + debug(" WARN: User home path is not set or is empty"); + return null; + } + + uh = uh.trim(); + File result = new File(uh); + if (!result.exists()) + { + debug(" WARN: User home '" + uh + "' does not exist"); + return null; + } + + if (!result.isDirectory()) + { + debug(" WARN: User home '" + uh + "' is not a directory"); + return null; + } + + if (!result.canRead()) + { + debug(" WARN: User home '" + uh + "' is not readable"); + return null; + } + + return result; + } + + private File getConfigFromUserHome(File userHome, String fileName) + { + File result = new File(userHome, fileName); + if (!result.exists()) + { + debug(" WARN: File '" + fileName + "' does not exist in user's home"); + return null; + } + + if (!result.isFile()) + { + debug(" WARN: File '" + fileName + "' in user's home is not a file"); + return null; + } + + if (!result.canRead()) + { + debug(" WARN: File '" + fileName + "' in user's home is not readable"); + return null; + } + + return result; + } +} diff --git a/gnu/regexp/CharIndexed.java b/gnu/regexp/CharIndexed.java index a0d7106ae..df1d8930c 100644 --- a/gnu/regexp/CharIndexed.java +++ b/gnu/regexp/CharIndexed.java @@ -1,5 +1,5 @@ /* gnu/regexp/CharIndexed.java - Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + Copyright (C) 1998-2001, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -81,4 +81,16 @@ public interface CharIndexed { * position at a valid position in the input. */ boolean isValid(); + + /** + * Returns another CharIndexed containing length characters to the left + * of the given index. The given length is an expected maximum and + * the returned CharIndexed may not necessarily contain so many characters. + */ + CharIndexed lookBehind(int index, int length); + + /** + * Returns the effective length of this CharIndexed + */ + int length(); } diff --git a/gnu/regexp/CharIndexedCharArray.java b/gnu/regexp/CharIndexedCharArray.java index 63d858c87..1388d4729 100644 --- a/gnu/regexp/CharIndexedCharArray.java +++ b/gnu/regexp/CharIndexedCharArray.java @@ -1,5 +1,5 @@ /* gnu/regexp/CharIndexedCharArray.java - Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + Copyright (C) 1998-2001, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -59,4 +59,13 @@ class CharIndexedCharArray implements CharIndexed, Serializable { public boolean move(int index) { return ((anchor += index) < s.length); } + + public CharIndexed lookBehind(int index, int length) { + if (length > (anchor + index)) length = anchor + index; + return new CharIndexedCharArray(s, anchor + index - length); + } + + public int length() { + return s.length - anchor; + } } diff --git a/gnu/regexp/CharIndexedInputStream.java b/gnu/regexp/CharIndexedInputStream.java index 145fe11b1..d5225a793 100644 --- a/gnu/regexp/CharIndexedInputStream.java +++ b/gnu/regexp/CharIndexedInputStream.java @@ -1,5 +1,5 @@ /* gnu/regexp/CharIndexedInputStream.java - Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + Copyright (C) 1998-2001, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -145,5 +145,15 @@ class CharIndexedInputStream implements CharIndexed { public boolean isValid() { return (cached != OUT_OF_BOUNDS); } + + public CharIndexed lookBehind(int index, int length) { + throw new UnsupportedOperationException( + "difficult to look behind for an input stream"); + } + + public int length() { + throw new UnsupportedOperationException( + "difficult to tell the length for an input stream"); + } } diff --git a/gnu/regexp/CharIndexedString.java b/gnu/regexp/CharIndexedString.java index 05be07ac6..fe4fa8f76 100644 --- a/gnu/regexp/CharIndexedString.java +++ b/gnu/regexp/CharIndexedString.java @@ -1,5 +1,5 @@ /* gnu/regexp/CharIndexedString.java - Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + Copyright (C) 1998-2001, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -61,4 +61,13 @@ class CharIndexedString implements CharIndexed, Serializable { public boolean move(int index) { return ((anchor += index) < len); } + + public CharIndexed lookBehind(int index, int length) { + if (length > (anchor + index)) length = anchor + index; + return new CharIndexedString(s, anchor + index - length); + } + + public int length() { + return len - anchor; + } } diff --git a/gnu/regexp/CharIndexedStringBuffer.java b/gnu/regexp/CharIndexedStringBuffer.java index 1b88e3985..9c9118dfe 100644 --- a/gnu/regexp/CharIndexedStringBuffer.java +++ b/gnu/regexp/CharIndexedStringBuffer.java @@ -1,5 +1,5 @@ /* gnu/regexp/CharIndexedStringBuffer.java - Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + Copyright (C) 1998-2001, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -59,4 +59,13 @@ class CharIndexedStringBuffer implements CharIndexed, Serializable { public boolean move(int index) { return ((anchor += index) < s.length()); } + + public CharIndexed lookBehind(int index, int length) { + if (length > (anchor + index)) length = anchor + index; + return new CharIndexedStringBuffer(s, anchor + index - length); + } + + public int length() { + return s.length() - anchor; + } } diff --git a/gnu/regexp/RE.java b/gnu/regexp/RE.java index 9ac9b53d1..ef606a6d8 100644 --- a/gnu/regexp/RE.java +++ b/gnu/regexp/RE.java @@ -1,5 +1,5 @@ /* gnu/regexp/RE.java - Copyright (C) 1998-2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -136,12 +136,13 @@ public class RE extends REToken { /** Minimum length, in characters, of any possible match. */ private int minimumLength; + private int maximumLength; /** * Compilation flag. Do not differentiate case. Subsequent * searches using this RE will be case insensitive. */ - public static final int REG_ICASE = 2; + public static final int REG_ICASE = 0x02; /** * Compilation flag. The match-any-character operator (dot) @@ -149,14 +150,14 @@ public class RE extends REToken { * bit RE_DOT_NEWLINE (see RESyntax for details). This is equivalent to * the "/s" operator in Perl. */ - public static final int REG_DOT_NEWLINE = 4; + public static final int REG_DOT_NEWLINE = 0x04; /** * Compilation flag. Use multiline mode. In this mode, the ^ and $ * anchors will match based on newlines within the input. This is * equivalent to the "/m" operator in Perl. */ - public static final int REG_MULTILINE = 8; + public static final int REG_MULTILINE = 0x08; /** * Execution flag. @@ -185,14 +186,14 @@ public class RE extends REToken { * // m4.toString(): "fool"
    *
    */ - public static final int REG_NOTBOL = 16; + public static final int REG_NOTBOL = 0x10; /** * Execution flag. * The match-end operator ($) does not match at the end * of the input string. Useful for matching on substrings. */ - public static final int REG_NOTEOL = 32; + public static final int REG_NOTEOL = 0x20; /** * Execution flag. @@ -206,7 +207,7 @@ public class RE extends REToken { * the example under REG_NOTBOL. It also affects the use of the \< * and \b operators. */ - public static final int REG_ANCHORINDEX = 64; + public static final int REG_ANCHORINDEX = 0x40; /** * Execution flag. @@ -215,7 +216,24 @@ public class RE extends REToken { * the corresponding subexpressions. For example, you may want to * replace all matches of "one dollar" with "$1". */ - public static final int REG_NO_INTERPOLATE = 128; + public static final int REG_NO_INTERPOLATE = 0x80; + + /** + * Execution flag. + * Try to match the whole input string. An implicit match-end operator + * is added to this regexp. + */ + public static final int REG_TRY_ENTIRE_MATCH = 0x0100; + + /** + * Execution flag. + * The substitute and substituteAll methods will treat the + * character '\' in the replacement as an escape to a literal + * character. In this case "\n", "\$", "\\", "\x40" and "\012" + * will become "n", "$", "\", "x40" and "012" respectively. + * This flag has no effect if REG_NO_INTERPOLATE is set on. + */ + public static final int REG_REPLACE_USE_BACKSLASHESCAPE = 0x0200; /** Returns a string representing the version of the gnu.regexp package. */ public static final String version() { @@ -273,12 +291,13 @@ public class RE extends REToken { } // internal constructor used for alternation - private RE(REToken first, REToken last,int subs, int subIndex, int minLength) { + private RE(REToken first, REToken last,int subs, int subIndex, int minLength, int maxLength) { super(subIndex); firstToken = first; lastToken = last; numSubs = subs; minimumLength = minLength; + maximumLength = maxLength; addToken(new RETokenEndSub(subIndex)); } @@ -333,6 +352,11 @@ public class RE extends REToken { char ch; boolean quot = false; + // Saved syntax and flags. + RESyntax savedSyntax = null; + int savedCflags = 0; + boolean flagsSaved = false; + while (index < pLength) { // read the next character unit (including backslash escapes) index = getCharUnit(pattern,index,unit,quot); @@ -359,8 +383,9 @@ public class RE extends REToken { && !syntax.get(RESyntax.RE_LIMITED_OPS)) { // make everything up to here be a branch. create vector if nec. addToken(currentToken); - RE theBranch = new RE(firstToken, lastToken, numSubs, subIndex, minimumLength); + RE theBranch = new RE(firstToken, lastToken, numSubs, subIndex, minimumLength, maximumLength); minimumLength = 0; + maximumLength = 0; if (branches == null) { branches = new Vector(); } @@ -402,102 +427,12 @@ public class RE extends REToken { // [...] | [^...] else if ((unit.ch == '[') && !(unit.bk || quot)) { - Vector options = new Vector(); - boolean negative = false; - char lastChar = 0; - if (index == pLength) throw new REException(getLocalizedMessage("unmatched.bracket"),REException.REG_EBRACK,index); - - // Check for initial caret, negation - if ((ch = pattern[index]) == '^') { - negative = true; - if (++index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); - ch = pattern[index]; - } - - // Check for leading right bracket literal - if (ch == ']') { - lastChar = ch; - if (++index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); - } - - while ((ch = pattern[index++]) != ']') { - if ((ch == '-') && (lastChar != 0)) { - if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); - if ((ch = pattern[index]) == ']') { - options.addElement(new RETokenChar(subIndex,lastChar,insens)); - lastChar = '-'; - } else { - options.addElement(new RETokenRange(subIndex,lastChar,ch,insens)); - lastChar = 0; - index++; - } - } else if ((ch == '\\') && syntax.get(RESyntax.RE_BACKSLASH_ESCAPE_IN_LISTS)) { - if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); - int posixID = -1; - boolean negate = false; - char asciiEsc = 0; - if (("dswDSW".indexOf(pattern[index]) != -1) && syntax.get(RESyntax.RE_CHAR_CLASS_ESC_IN_LISTS)) { - switch (pattern[index]) { - case 'D': - negate = true; - case 'd': - posixID = RETokenPOSIX.DIGIT; - break; - case 'S': - negate = true; - case 's': - posixID = RETokenPOSIX.SPACE; - break; - case 'W': - negate = true; - case 'w': - posixID = RETokenPOSIX.ALNUM; - break; - } - } - else if ("nrt".indexOf(pattern[index]) != -1) { - switch (pattern[index]) { - case 'n': - asciiEsc = '\n'; - break; - case 't': - asciiEsc = '\t'; - break; - case 'r': - asciiEsc = '\r'; - break; - } - } - if (lastChar != 0) options.addElement(new RETokenChar(subIndex,lastChar,insens)); - - if (posixID != -1) { - options.addElement(new RETokenPOSIX(subIndex,posixID,insens,negate)); - } else if (asciiEsc != 0) { - lastChar = asciiEsc; - } else { - lastChar = pattern[index]; - } - ++index; - } else if ((ch == '[') && (syntax.get(RESyntax.RE_CHAR_CLASSES)) && (index < pLength) && (pattern[index] == ':')) { - StringBuffer posixSet = new StringBuffer(); - index = getPosixSet(pattern,index+1,posixSet); - int posixId = RETokenPOSIX.intValue(posixSet.toString()); - if (posixId != -1) - options.addElement(new RETokenPOSIX(subIndex,posixId,insens,false)); - } else { - if (lastChar != 0) options.addElement(new RETokenChar(subIndex,lastChar,insens)); - lastChar = ch; - } - if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); - } // while in list - // Out of list, index is one past ']' - - if (lastChar != 0) options.addElement(new RETokenChar(subIndex,lastChar,insens)); - // Create a new RETokenOneOf + ParseCharClassResult result = parseCharClass( + subIndex, pattern, index, pLength, cflags, syntax, 0); addToken(currentToken); - options.trimToSize(); - currentToken = new RETokenOneOf(subIndex,options,negative); + currentToken = result.token; + index = result.index; } // SUBEXPRESSIONS @@ -507,7 +442,10 @@ public class RE extends REToken { boolean pure = false; boolean comment = false; boolean lookAhead = false; + boolean lookBehind = false; + boolean independent = false; boolean negativelh = false; + boolean negativelb = false; if ((index+1 < pLength) && (pattern[index] == '?')) { switch (pattern[index+1]) { case '!': @@ -525,6 +463,114 @@ public class RE extends REToken { index += 2; } break; + case '<': + // We assume that if the syntax supports look-ahead, + // it also supports look-behind. + if (syntax.get(RESyntax.RE_LOOKAHEAD)) { + index++; + switch (pattern[index +1]) { + case '!': + pure = true; + negativelb = true; + lookBehind = true; + index += 2; + break; + case '=': + pure = true; + lookBehind = true; + index += 2; + } + } + break; + case '>': + // We assume that if the syntax supports look-ahead, + // it also supports independent group. + if (syntax.get(RESyntax.RE_LOOKAHEAD)) { + pure = true; + independent = true; + index += 2; + } + break; + case 'i': + case 'd': + case 'm': + case 's': + // case 'u': not supported + // case 'x': not supported + case '-': + if (!syntax.get(RESyntax.RE_EMBEDDED_FLAGS)) break; + // Set or reset syntax flags. + int flagIndex = index + 1; + int endFlag = -1; + RESyntax newSyntax = new RESyntax(syntax); + int newCflags = cflags; + boolean negate = false; + while (flagIndex < pLength && endFlag < 0) { + switch(pattern[flagIndex]) { + case 'i': + if (negate) + newCflags &= ~REG_ICASE; + else + newCflags |= REG_ICASE; + flagIndex++; + break; + case 'd': + if (negate) + newSyntax.setLineSeparator(RESyntax.DEFAULT_LINE_SEPARATOR); + else + newSyntax.setLineSeparator("\n"); + flagIndex++; + break; + case 'm': + if (negate) + newCflags &= ~REG_MULTILINE; + else + newCflags |= REG_MULTILINE; + flagIndex++; + break; + case 's': + if (negate) + newCflags &= ~REG_DOT_NEWLINE; + else + newCflags |= REG_DOT_NEWLINE; + flagIndex++; + break; + // case 'u': not supported + // case 'x': not supported + case '-': + negate = true; + flagIndex++; + break; + case ':': + case ')': + endFlag = pattern[flagIndex]; + break; + default: + throw new REException(getLocalizedMessage("repeat.no.token"), REException.REG_BADRPT, index); + } + } + if (endFlag == ')') { + syntax = newSyntax; + cflags = newCflags; + insens = ((cflags & REG_ICASE) > 0); + // This can be treated as though it were a comment. + comment = true; + index = flagIndex - 1; + break; + } + if (endFlag == ':') { + savedSyntax = syntax; + savedCflags = cflags; + flagsSaved = true; + syntax = newSyntax; + cflags = newCflags; + insens = ((cflags & REG_ICASE) > 0); + index = flagIndex -1; + // Fall through to the next case. + } + else { + throw new REException(getLocalizedMessage("unmatched.paren"), REException.REG_ESUBREG,index); + } case ':': if (syntax.get(RESyntax.RE_PURE_GROUPING)) { pure = true; @@ -607,15 +653,28 @@ public class RE extends REToken { numSubs++; } - int useIndex = (pure || lookAhead) ? 0 : nextSub + numSubs; + int useIndex = (pure || lookAhead || lookBehind || independent) ? + 0 : nextSub + numSubs; currentToken = new RE(String.valueOf(pattern,index,endIndex-index).toCharArray(),cflags,syntax,useIndex,nextSub + numSubs); numSubs += ((RE) currentToken).getNumSubs(); if (lookAhead) { currentToken = new RETokenLookAhead(currentToken,negativelh); } + else if (lookBehind) { + currentToken = new RETokenLookBehind(currentToken,negativelb); + } + else if (independent) { + currentToken = new RETokenIndependent(currentToken); + } index = nextIndex; + if (flagsSaved) { + syntax = savedSyntax; + cflags = savedCflags; + insens = ((cflags & REG_ICASE) > 0); + flagsSaved = false; + } } // not a comment } // subexpression @@ -715,14 +774,45 @@ public class RE extends REToken { else currentToken = setRepeated(currentToken,0,1,index); } + + // OCTAL CHARACTER + // \0377 + else if (unit.bk && (unit.ch == '0') && syntax.get(RESyntax.RE_OCTAL_CHAR)) { + CharExpression ce = getCharExpression(pattern, index - 2, pLength, syntax); + if (ce == null) + throw new REException("invalid octal character", REException.REG_ESCAPE, index); + index = index - 2 + ce.len; + addToken(currentToken); + currentToken = new RETokenChar(subIndex,ce.ch,insens); + } + // BACKREFERENCE OPERATOR - // \1 \2 ... \9 + // \1 \2 ... \9 and \10 \11 \12 ... // not available if RE_NO_BK_REFS is set + // Perl recognizes \10, \11, and so on only if enough number of + // parentheses have opened before it, otherwise they are treated + // as aliases of \010, \011, ... (octal characters). In case of + // Sun's JDK, octal character expression must always begin with \0. + // We will do as JDK does. But FIXME, take a look at "(a)(b)\29". + // JDK treats \2 as a back reference to the 2nd group because + // there are only two groups. But in our poor implementation, + // we cannot help but treat \29 as a back reference to the 29th group. else if (unit.bk && Character.isDigit(unit.ch) && !syntax.get(RESyntax.RE_NO_BK_REFS)) { addToken(currentToken); - currentToken = new RETokenBackRef(subIndex,Character.digit(unit.ch,10),insens); + int numBegin = index - 1; + int numEnd = pLength; + for (int i = index; i < pLength; i++) { + if (! Character.isDigit(pattern[i])) { + numEnd = i; + break; + } + } + int num = parseInt(pattern, numBegin, numEnd-numBegin, 10); + + currentToken = new RETokenBackRef(subIndex,num,insens); + index = numEnd; } // START OF STRING OPERATOR @@ -844,6 +934,32 @@ public class RE extends REToken { currentToken = new RETokenEnd(subIndex,null); } + // HEX CHARACTER, UNICODE CHARACTER + // \x1B, \u1234 + + else if ((unit.bk && (unit.ch == 'x') && syntax.get(RESyntax.RE_HEX_CHAR)) || + (unit.bk && (unit.ch == 'u') && syntax.get(RESyntax.RE_UNICODE_CHAR))) { + CharExpression ce = getCharExpression(pattern, index - 2, pLength, syntax); + if (ce == null) + throw new REException("invalid hex character", REException.REG_ESCAPE, index); + index = index - 2 + ce.len; + addToken(currentToken); + currentToken = new RETokenChar(subIndex,ce.ch,insens); + } + + // NAMED PROPERTY + // \p{prop}, \P{prop} + + else if ((unit.bk && (unit.ch == 'p') && syntax.get(RESyntax.RE_NAMED_PROPERTY)) || + (unit.bk && (unit.ch == 'P') && syntax.get(RESyntax.RE_NAMED_PROPERTY))) { + NamedProperty np = getNamedProperty(pattern, index - 2, pLength); + if (np == null) + throw new REException("invalid escape sequence", REException.REG_ESCAPE, index); + index = index - 2 + np.len; + addToken(currentToken); + currentToken = getRETokenNamedProperty(subIndex,np,insens,index); + } + // NON-SPECIAL CHARACTER (or escape to make literal) // c | \* for example @@ -857,9 +973,10 @@ public class RE extends REToken { addToken(currentToken); if (branches != null) { - branches.addElement(new RE(firstToken,lastToken,numSubs,subIndex,minimumLength)); + branches.addElement(new RE(firstToken,lastToken,numSubs,subIndex,minimumLength, maximumLength)); branches.trimToSize(); // compact the Vector minimumLength = 0; + maximumLength = 0; firstToken = lastToken = null; addToken(new RETokenOneOf(subIndex,branches,false)); } @@ -867,6 +984,199 @@ public class RE extends REToken { } + private static class ParseCharClassResult { + RETokenOneOf token; + int index; + boolean returnAtAndOperator = false; + } + + /** + * Parse [...] or [^...] and make an RETokenOneOf instance. + * @param subIndex subIndex to be given to the created RETokenOneOf instance. + * @param pattern Input array of characters to be parsed. + * @param index Index pointing to the character next to the beginning '['. + * @param pLength Limit of the input array. + * @param cflags Compilation flags used to parse the pattern. + * @param pflags Flags that affect the behavior of this method. + * @param syntax Syntax used to parse the pattern. + */ + private static ParseCharClassResult parseCharClass(int subIndex, + char[] pattern, int index, + int pLength, int cflags, RESyntax syntax, int pflags) + throws REException { + + boolean insens = ((cflags & REG_ICASE) > 0); + Vector options = new Vector(); + Vector addition = new Vector(); + boolean additionAndAppeared = false; + final int RETURN_AT_AND = 0x01; + boolean returnAtAndOperator = ((pflags & RETURN_AT_AND) != 0); + boolean negative = false; + char ch; + + char lastChar = 0; + boolean lastCharIsSet = false; + if (index == pLength) throw new REException(getLocalizedMessage("unmatched.bracket"),REException.REG_EBRACK,index); + + // Check for initial caret, negation + if ((ch = pattern[index]) == '^') { + negative = true; + if (++index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); + ch = pattern[index]; + } + + // Check for leading right bracket literal + if (ch == ']') { + lastChar = ch; lastCharIsSet = true; + if (++index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); + } + + while ((ch = pattern[index++]) != ']') { + if ((ch == '-') && (lastCharIsSet)) { + if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); + if ((ch = pattern[index]) == ']') { + options.addElement(new RETokenChar(subIndex,lastChar,insens)); + lastChar = '-'; + } else { + if ((ch == '\\') && syntax.get(RESyntax.RE_BACKSLASH_ESCAPE_IN_LISTS)) { + CharExpression ce = getCharExpression(pattern, index, pLength, syntax); + if (ce == null) + throw new REException("invalid escape sequence", REException.REG_ESCAPE, index); + ch = ce.ch; + index = index + ce.len - 1; + } + options.addElement(new RETokenRange(subIndex,lastChar,ch,insens)); + lastChar = 0; lastCharIsSet = false; + index++; + } + } else if ((ch == '\\') && syntax.get(RESyntax.RE_BACKSLASH_ESCAPE_IN_LISTS)) { + if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); + int posixID = -1; + boolean negate = false; + char asciiEsc = 0; + boolean asciiEscIsSet = false; + NamedProperty np = null; + if (("dswDSW".indexOf(pattern[index]) != -1) && syntax.get(RESyntax.RE_CHAR_CLASS_ESC_IN_LISTS)) { + switch (pattern[index]) { + case 'D': + negate = true; + case 'd': + posixID = RETokenPOSIX.DIGIT; + break; + case 'S': + negate = true; + case 's': + posixID = RETokenPOSIX.SPACE; + break; + case 'W': + negate = true; + case 'w': + posixID = RETokenPOSIX.ALNUM; + break; + } + } + if (("pP".indexOf(pattern[index]) != -1) && syntax.get(RESyntax.RE_NAMED_PROPERTY)) { + np = getNamedProperty(pattern, index - 1, pLength); + if (np == null) + throw new REException("invalid escape sequence", REException.REG_ESCAPE, index); + index = index - 1 + np.len - 1; + } + else { + CharExpression ce = getCharExpression(pattern, index - 1, pLength, syntax); + if (ce == null) + throw new REException("invalid escape sequence", REException.REG_ESCAPE, index); + asciiEsc = ce.ch; asciiEscIsSet = true; + index = index - 1 + ce.len - 1; + } + if (lastCharIsSet) options.addElement(new RETokenChar(subIndex,lastChar,insens)); + + if (posixID != -1) { + options.addElement(new RETokenPOSIX(subIndex,posixID,insens,negate)); + } else if (np != null) { + options.addElement(getRETokenNamedProperty(subIndex,np,insens,index)); + } else if (asciiEscIsSet) { + lastChar = asciiEsc; lastCharIsSet = true; + } else { + lastChar = pattern[index]; lastCharIsSet = true; + } + ++index; + } else if ((ch == '[') && (syntax.get(RESyntax.RE_CHAR_CLASSES)) && (index < pLength) && (pattern[index] == ':')) { + StringBuffer posixSet = new StringBuffer(); + index = getPosixSet(pattern,index+1,posixSet); + int posixId = RETokenPOSIX.intValue(posixSet.toString()); + if (posixId != -1) + options.addElement(new RETokenPOSIX(subIndex,posixId,insens,false)); + } else if ((ch == '[') && (syntax.get(RESyntax.RE_NESTED_CHARCLASS))) { + ParseCharClassResult result = parseCharClass( + subIndex, pattern, index, pLength, cflags, syntax, 0); + addition.addElement(result.token); + addition.addElement("|"); + index = result.index; + } else if ((ch == '&') && + (syntax.get(RESyntax.RE_NESTED_CHARCLASS)) && + (index < pLength) && (pattern[index] == '&')) { + if (returnAtAndOperator) { + ParseCharClassResult result = new ParseCharClassResult(); + options.trimToSize(); + if (additionAndAppeared) addition.addElement("&"); + if (addition.size() == 0) addition = null; + result.token = new RETokenOneOf(subIndex, + options, addition, negative); + result.index = index - 1; + result.returnAtAndOperator = true; + return result; + } + // The precedence of the operator "&&" is the lowest. + // So we postpone adding "&" until other elements + // are added. And we insert Boolean.FALSE at the + // beginning of the list of tokens following "&&". + // So, "&&[a-b][k-m]" will be stored in the Vecter + // addition in this order: + // Boolean.FALSE, [a-b], "|", [k-m], "|", "&" + if (additionAndAppeared) addition.addElement("&"); + addition.addElement(Boolean.FALSE); + additionAndAppeared = true; + + // The part on which "&&" operates may be either + // (1) explicitly enclosed by [] + // or + // (2) not enclosed by [] and terminated by the + // next "&&" or the end of the character list. + // Let the preceding else if block do the case (1). + // We must do something in case of (2). + if ((index + 1 < pLength) && (pattern[index + 1] != '[')) { + ParseCharClassResult result = parseCharClass( + subIndex, pattern, index+1, pLength, cflags, syntax, + RETURN_AT_AND); + addition.addElement(result.token); + addition.addElement("|"); + // If the method returned at the next "&&", it is OK. + // Otherwise we have eaten the mark of the end of this + // character list "]". In this case we must give back + // the end mark. + index = (result.returnAtAndOperator ? + result.index: result.index - 1); + } + } else { + if (lastCharIsSet) options.addElement(new RETokenChar(subIndex,lastChar,insens)); + lastChar = ch; lastCharIsSet = true; + } + if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index); + } // while in list + // Out of list, index is one past ']' + + if (lastCharIsSet) options.addElement(new RETokenChar(subIndex,lastChar,insens)); + + ParseCharClassResult result = new ParseCharClassResult(); + // Create a new RETokenOneOf + options.trimToSize(); + if (additionAndAppeared) addition.addElement("&"); + if (addition.size() == 0) addition = null; + result.token = new RETokenOneOf(subIndex,options, addition, negative); + result.index = index; + return result; + } + private static int getCharUnit(char[] input, int index, CharUnit unit, boolean quot) throws REException { unit.ch = input[index++]; unit.bk = (unit.ch == '\\' @@ -878,6 +1188,176 @@ public class RE extends REToken { return index; } + private static int parseInt(char[] input, int pos, int len, int radix) { + int ret = 0; + for (int i = pos; i < pos + len; i++) { + ret = ret * radix + Character.digit(input[i], radix); + } + return ret; + } + + /** + * This class represents various expressions for a character. + * "a" : 'a' itself. + * "\0123" : Octal char 0123 + * "\x1b" : Hex char 0x1b + * "\u1234" : Unicode char \u1234 + */ + private static class CharExpression { + /** character represented by this expression */ + char ch; + /** String expression */ + String expr; + /** length of this expression */ + int len; + public String toString() { return expr; } + } + + private static CharExpression getCharExpression(char[] input, int pos, int lim, + RESyntax syntax) { + CharExpression ce = new CharExpression(); + char c = input[pos]; + if (c == '\\') { + if (pos + 1 >= lim) return null; + c = input[pos + 1]; + switch(c) { + case 't': + ce.ch = '\t'; + ce.len = 2; + break; + case 'n': + ce.ch = '\n'; + ce.len = 2; + break; + case 'r': + ce.ch = '\r'; + ce.len = 2; + break; + case 'x': + case 'u': + if ((c == 'x' && syntax.get(RESyntax.RE_HEX_CHAR)) || + (c == 'u' && syntax.get(RESyntax.RE_UNICODE_CHAR))) { + int l = 0; + int expectedLength = (c == 'x' ? 2 : 4); + for (int i = pos + 2; i < pos + 2 + expectedLength; i++) { + if (i >= lim) break; + if (!((input[i] >= '0' && input[i] <= '9') || + (input[i] >= 'A' && input[i] <= 'F') || + (input[i] >= 'a' && input[i] <= 'f'))) + break; + l++; + } + if (l != expectedLength) return null; + ce.ch = (char)(parseInt(input, pos + 2, l, 16)); + ce.len = l + 2; + } + else { + ce.ch = c; + ce.len = 2; + } + break; + case '0': + if (syntax.get(RESyntax.RE_OCTAL_CHAR)) { + int l = 0; + for (int i = pos + 2; i < pos + 2 + 3; i++) { + if (i >= lim) break; + if (input[i] < '0' || input[i] > '7') break; + l++; + } + if (l == 3 && input[pos + 2] > '3') l--; + if (l <= 0) return null; + ce.ch = (char)(parseInt(input, pos + 2, l, 8)); + ce.len = l + 2; + } + else { + ce.ch = c; + ce.len = 2; + } + break; + default: + ce.ch = c; + ce.len = 2; + break; + } + } + else { + ce.ch = input[pos]; + ce.len = 1; + } + ce.expr = new String(input, pos, ce.len); + return ce; + } + + /** + * This class represents a substring in a pattern string expressing + * a named property. + * "\pA" : Property named "A" + * "\p{prop}" : Property named "prop" + * "\PA" : Property named "A" (Negated) + * "\P{prop}" : Property named "prop" (Negated) + */ + private static class NamedProperty { + /** Property name */ + String name; + /** Negated or not */ + boolean negate; + /** length of this expression */ + int len; + } + + private static NamedProperty getNamedProperty(char[] input, int pos, int lim) { + NamedProperty np = new NamedProperty(); + char c = input[pos]; + if (c == '\\') { + if (++pos >= lim) return null; + c = input[pos++]; + switch(c) { + case 'p': + np.negate = false; + break; + case 'P': + np.negate = true; + break; + default: + return null; + } + c = input[pos++]; + if (c == '{') { + int p = -1; + for (int i = pos; i < lim; i++) { + if (input[i] == '}') { + p = i; + break; + } + } + if (p < 0) return null; + int len = p - pos; + np.name = new String(input, pos, len); + np.len = len + 4; + } + else { + np.name = new String(input, pos - 1, 1); + np.len = 3; + } + return np; + } + else return null; + } + + private static RETokenNamedProperty getRETokenNamedProperty( + int subIndex, NamedProperty np, boolean insens, int index) + throws REException { + try { + return new RETokenNamedProperty(subIndex, np.name, insens, np.negate); + } + catch (REException e) { + REException ree; + ree = new REException(e.getMessage(), REException.REG_ESCAPE, index); + ree.initCause(e); + throw ree; + } + } + /** * Checks if the regular expression matches the input in its entirety. * @@ -958,6 +1438,10 @@ public class RE extends REToken { return minimumLength; } + public int getMaximumLength() { + return maximumLength; + } + /** * Returns an array of all matches found in the input. * @@ -1025,7 +1509,9 @@ public class RE extends REToken { /* Implements abstract method REToken.match() */ boolean match(CharIndexed input, REMatch mymatch) { - if (firstToken == null) return next(input, mymatch); + if (firstToken == null) { + return next(input, mymatch); + } // Note the start of this subexpression mymatch.start[subIndex] = mymatch.index; @@ -1089,23 +1575,34 @@ public class RE extends REToken { } REMatch getMatchImpl(CharIndexed input, int anchor, int eflags, StringBuffer buffer) { + boolean tryEntireMatch = ((eflags & REG_TRY_ENTIRE_MATCH) != 0); + RE re = (tryEntireMatch ? (RE) this.clone() : this); + if (tryEntireMatch) { + re.chain(new RETokenEnd(0, null)); + } // Create a new REMatch to hold results REMatch mymatch = new REMatch(numSubs, anchor, eflags); do { // Optimization: check if anchor + minimumLength > length if (minimumLength == 0 || input.charAt(minimumLength-1) != CharIndexed.OUT_OF_BOUNDS) { - if (match(input, mymatch)) { - // Find longest match of them all to observe leftmost longest - REMatch longest = mymatch; + if (re.match(input, mymatch)) { + REMatch best = mymatch; + // We assume that the match that coms first is the best. + // And the following "The longer, the better" rule has + // been commented out. The longest is not neccesarily + // the best. For example, "a" out of "aaa" is the best + // match for /a+?/. + /* + // Find best match of them all to observe leftmost longest while ((mymatch = mymatch.next) != null) { - if (mymatch.index > longest.index) { - longest = mymatch; + if (mymatch.index > best.index) { + best = mymatch; } } - - longest.end[0] = longest.index; - longest.finish(input); - return longest; + */ + best.end[0] = best.index; + best.finish(input); + return best; } } mymatch.clear(++anchor); @@ -1216,8 +1713,7 @@ public class RE extends REToken { StringBuffer buffer = new StringBuffer(); REMatch m = getMatchImpl(input,index,eflags,buffer); if (m==null) return buffer.toString(); - buffer.append( ((eflags & REG_NO_INTERPOLATE) > 0) ? - replace : m.substituteInto(replace) ); + buffer.append(getReplacement(replace, m, eflags)); if (input.move(m.end[0])) { do { buffer.append(input.charAt(0)); @@ -1278,8 +1774,7 @@ public class RE extends REToken { StringBuffer buffer = new StringBuffer(); REMatch m; while ((m = getMatchImpl(input,index,eflags,buffer)) != null) { - buffer.append( ((eflags & REG_NO_INTERPOLATE) > 0) ? - replace : m.substituteInto(replace) ); + buffer.append(getReplacement(replace, m, eflags)); index = m.getEndIndex(); if (m.end[0] == 0) { char ch = input.charAt(0); @@ -1294,11 +1789,50 @@ public class RE extends REToken { } return buffer.toString(); } + + public static String getReplacement(String replace, REMatch m, int eflags) { + if ((eflags & REG_NO_INTERPOLATE) > 0) + return replace; + else { + if ((eflags & REG_REPLACE_USE_BACKSLASHESCAPE) > 0) { + StringBuffer sb = new StringBuffer(); + int l = replace.length(); + for (int i = 0; i < l; i++) { + char c = replace.charAt(i); + switch(c) { + case '\\': + i++; + // Let StringIndexOutOfBoundsException be thrown. + sb.append(replace.charAt(i)); + break; + case '$': + int i1 = i + 1; + while (i1 < replace.length() && + Character.isDigit(replace.charAt(i1))) i1++; + sb.append(m.substituteInto(replace.substring(i, i1))); + i = i1 - 1; + break; + default: + sb.append(c); + } + } + return sb.toString(); + } + else + return m.substituteInto(replace); + } + } /* Helper function for constructor */ private void addToken(REToken next) { if (next == null) return; minimumLength += next.getMinimumLength(); + int nmax = next.getMaximumLength(); + if (nmax < Integer.MAX_VALUE && maximumLength < Integer.MAX_VALUE) + maximumLength += nmax; + else + maximumLength = Integer.MAX_VALUE; + if (firstToken == null) { lastToken = firstToken = next; } else { diff --git a/gnu/regexp/REMatch.java b/gnu/regexp/REMatch.java index cf25bb331..91a3c0249 100644 --- a/gnu/regexp/REMatch.java +++ b/gnu/regexp/REMatch.java @@ -1,5 +1,5 @@ /* gnu/regexp/REMatch.java - Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -67,6 +67,10 @@ public final class REMatch implements Serializable, Cloneable { int[] start; // start positions (relative to offset) for each (sub)exp. int[] end; // end positions for the same REMatch next; // other possibility (to avoid having to use arrays) + boolean empty; // empty string matched. This flag is used only within + // RETokenRepeated. + int matchFlags; // flags passed to match methods + static final int MF_FIND_ALL = 0x01; public Object clone() { try { @@ -177,7 +181,9 @@ public final class REMatch implements Serializable, Cloneable { * @param sub Index of the subexpression. */ public String toString(int sub) { - if ((sub >= start.length) || (start[sub] == -1)) return ""; + if ((sub >= start.length) || sub < 0) + throw new IndexOutOfBoundsException("No group " + sub); + if (start[sub] == -1) return null; return (matchedText.substring(start[sub],end[sub])); } @@ -242,6 +248,8 @@ public final class REMatch implements Serializable, Cloneable { * $0 through $9. $0 matches * the full substring matched; $n matches * subexpression number n. + * $10, $11, ... may match the 10th, 11th, ... subexpressions + * if such subexpressions exist. * * @param input A string consisting of literals and $n tokens. */ @@ -252,6 +260,16 @@ public final class REMatch implements Serializable, Cloneable { for (pos = 0; pos < input.length()-1; pos++) { if ((input.charAt(pos) == '$') && (Character.isDigit(input.charAt(pos+1)))) { int val = Character.digit(input.charAt(++pos),10); + int pos1 = pos + 1; + while (pos1 < input.length() && + Character.isDigit(input.charAt(pos1))) { + int val1 = val*10 + Character.digit(input.charAt(pos1),10); + if (val1 >= start.length) break; + pos1++; + val = val1; + } + pos = pos1 - 1; + if (val < start.length) { output.append(toString(val)); } @@ -260,4 +278,42 @@ public final class REMatch implements Serializable, Cloneable { if (pos < input.length()) output.append(input.charAt(pos)); return output.toString(); } + + static class REMatchList { + REMatch head; + REMatch tail; + REMatchList() { + head = tail = null; + } + /* Not used now. But we may need this some day? + void addHead(REMatch newone) { + if (head == null) { + head = newone; + tail = newone; + while (tail.next != null) { + tail = tail.next; + } + } + else { + REMatch tmp = newone; + while (tmp.next != null) tmp = tmp.next; + tmp.next = head; + head = newone; + } + } + */ + void addTail(REMatch newone) { + if (head == null) { + head = newone; + tail = newone; + } + else { + tail.next = newone; + } + while (tail.next != null) { + tail = tail.next; + } + } + } + } diff --git a/gnu/regexp/RESyntax.java b/gnu/regexp/RESyntax.java index 7272b0348..81fd999bf 100644 --- a/gnu/regexp/RESyntax.java +++ b/gnu/regexp/RESyntax.java @@ -1,5 +1,5 @@ /* gnu/regexp/RESyntax.java - Copyright (C) 1998-2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -202,7 +202,37 @@ public final class RESyntax implements Serializable { */ public static final int RE_POSSESSIVE_OPS = 25; - private static final int BIT_TOTAL = 26; + /** + * Syntax bit. Allow embedded flags, (?is-x), as in Perl5. + */ + public static final int RE_EMBEDDED_FLAGS = 26; + + /** + * Syntax bit. Allow octal char (\0377), as in Perl5. + */ + public static final int RE_OCTAL_CHAR = 27; + + /** + * Syntax bit. Allow hex char (\x1b), as in Perl5. + */ + public static final int RE_HEX_CHAR = 28; + + /** + * Syntax bit. Allow Unicode char (\u1234), as in Java 1.4. + */ + public static final int RE_UNICODE_CHAR = 29; + + /** + * Syntax bit. Allow named property (\p{P}, \P{p}), as in Perl5. + */ + public static final int RE_NAMED_PROPERTY = 30; + + /** + * Syntax bit. Allow nested characterclass ([a-z&&[^p-r]]), as in Java 1.4. + */ + public static final int RE_NESTED_CHARCLASS = 31; + + private static final int BIT_TOTAL = 32; /** * Predefined syntax. @@ -422,6 +452,10 @@ public final class RESyntax implements Serializable { .set(RE_STRING_ANCHORS) // \A,\Z .set(RE_CHAR_CLASS_ESC_IN_LISTS)// \d,\D,\w,\W,\s,\S within [] .set(RE_COMMENTS) // (?#) + .set(RE_EMBEDDED_FLAGS) // (?imsx-imsx) + .set(RE_OCTAL_CHAR) // \0377 + .set(RE_HEX_CHAR) // \x1b + .set(RE_NAMED_PROPERTY) // \p{prop}, \P{prop} .makeFinal(); RE_SYNTAX_PERL5_S = new RESyntax(RE_SYNTAX_PERL5) @@ -431,6 +465,8 @@ public final class RESyntax implements Serializable { RE_SYNTAX_JAVA_1_4 = new RESyntax(RE_SYNTAX_PERL5) // XXX .set(RE_POSSESSIVE_OPS) // *+,?+,++,{}+ + .set(RE_UNICODE_CHAR) // \u1234 + .set(RE_NESTED_CHARCLASS) // [a-z&&[^p-r]] .makeFinal(); } diff --git a/gnu/regexp/REToken.java b/gnu/regexp/REToken.java index 4eae9ec47..5f4659b21 100644 --- a/gnu/regexp/REToken.java +++ b/gnu/regexp/REToken.java @@ -38,12 +38,21 @@ exception statement from your version. */ package gnu.regexp; import java.io.Serializable; -abstract class REToken implements Serializable { +abstract class REToken implements Serializable, Cloneable { protected REToken next = null; protected REToken uncle = null; protected int subIndex; + public Object clone() { + try { + REToken copy = (REToken) super.clone(); + return copy; + } catch (CloneNotSupportedException e) { + throw new Error(); // doesn't happen + } + } + protected REToken(int subIndex) { this.subIndex = subIndex; } @@ -52,6 +61,10 @@ abstract class REToken implements Serializable { return 0; } + int getMaximumLength() { + return Integer.MAX_VALUE; + } + void setUncle(REToken anUncle) { uncle = anUncle; } diff --git a/gnu/regexp/RETokenAny.java b/gnu/regexp/RETokenAny.java index ac032dcb3..2b0967a79 100644 --- a/gnu/regexp/RETokenAny.java +++ b/gnu/regexp/RETokenAny.java @@ -55,6 +55,10 @@ final class RETokenAny extends REToken { return 1; } + int getMaximumLength() { + return 1; + } + boolean match(CharIndexed input, REMatch mymatch) { char ch = input.charAt(mymatch.index); if ((ch == CharIndexed.OUT_OF_BOUNDS) diff --git a/gnu/regexp/RETokenBackRef.java b/gnu/regexp/RETokenBackRef.java index 674822abd..060a6cf7d 100644 --- a/gnu/regexp/RETokenBackRef.java +++ b/gnu/regexp/RETokenBackRef.java @@ -51,13 +51,25 @@ final class RETokenBackRef extends REToken { // should implement getMinimumLength() -- any ideas? boolean match(CharIndexed input, REMatch mymatch) { + if (num >= mymatch.start.length) return false; + if (num >= mymatch.end.length) return false; int b,e; b = mymatch.start[num]; e = mymatch.end[num]; if ((b==-1)||(e==-1)) return false; // this shouldn't happen, but... for (int i=b; i"); + re.dumpAll(os); + os.append(')'); + } +} + diff --git a/gnu/regexp/RETokenLookAhead.java b/gnu/regexp/RETokenLookAhead.java index 33eaec9fa..b44dfa50c 100644 --- a/gnu/regexp/RETokenLookAhead.java +++ b/gnu/regexp/RETokenLookAhead.java @@ -52,6 +52,10 @@ final class RETokenLookAhead extends REToken this.negative = negative; } + int getMaximumLength() { + return 0; + } + boolean match(CharIndexed input, REMatch mymatch) { REMatch trymatch = (REMatch)mymatch.clone(); diff --git a/gnu/regexp/RETokenLookBehind.java b/gnu/regexp/RETokenLookBehind.java new file mode 100644 index 000000000..a6c1b34cb --- /dev/null +++ b/gnu/regexp/RETokenLookBehind.java @@ -0,0 +1,116 @@ +/* gnu/regexp/RETokenLookBehind.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.regexp; + +/** + * @author Ito Kazumitsu + */ +final class RETokenLookBehind extends REToken +{ + REToken re; + boolean negative; + + RETokenLookBehind(REToken re, boolean negative) throws REException { + super(0); + this.re = re; + this.negative = negative; + } + + int getMaximumLength() { + return 0; + } + + boolean match(CharIndexed input, REMatch mymatch) + { + int max = re.getMaximumLength(); + CharIndexed behind = input.lookBehind(mymatch.index, max); + REMatch trymatch = (REMatch)mymatch.clone(); + REMatch trymatch1 = (REMatch)mymatch.clone(); + REMatch newMatch = null; + int curIndex = trymatch.index + behind.length() - input.length(); + trymatch.index = 0; + RETokenMatchHereOnly stopper = new RETokenMatchHereOnly(curIndex); + REToken re1 = (REToken) re.clone(); + re1.chain(stopper); + if (re1.match(behind, trymatch)) { + if (negative) return false; + if (next(input, trymatch1)) + newMatch = trymatch1; + } + + if (newMatch != null) { + if (negative) return false; + //else + mymatch.assignFrom(newMatch); + return true; + } + else { // no match + if (negative) + return next(input, mymatch); + //else + return false; + } + } + + void dump(StringBuffer os) { + os.append("(?<"); + os.append(negative ? '!' : '='); + re.dumpAll(os); + os.append(')'); + } + + private static class RETokenMatchHereOnly extends REToken { + + int getMaximumLength() { return 0; } + + private int index; + + RETokenMatchHereOnly(int index) { + super(0); + this.index = index; + } + + boolean match(CharIndexed input, REMatch mymatch) { + return index == mymatch.index; + } + + void dump(StringBuffer os) {} + + } +} + diff --git a/gnu/regexp/RETokenNamedProperty.java b/gnu/regexp/RETokenNamedProperty.java new file mode 100644 index 000000000..13c1e418a --- /dev/null +++ b/gnu/regexp/RETokenNamedProperty.java @@ -0,0 +1,301 @@ +/* gnu/regexp/RETokenNamedProperty.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.regexp; + +final class RETokenNamedProperty extends REToken { + String name; + boolean insens; + boolean negate; + Handler handler; + + // Grouped properties + static final byte[] LETTER = new byte[] + { Character.LOWERCASE_LETTER, + Character.UPPERCASE_LETTER, + Character.TITLECASE_LETTER, + Character.MODIFIER_LETTER, + Character.OTHER_LETTER }; + + static final byte[] MARK = new byte[] + { Character.NON_SPACING_MARK, + Character.COMBINING_SPACING_MARK, + Character.ENCLOSING_MARK }; + + static final byte[] SEPARATOR = new byte[] + { Character.SPACE_SEPARATOR, + Character.LINE_SEPARATOR, + Character.PARAGRAPH_SEPARATOR }; + + static final byte[] SYMBOL = new byte[] + { Character.MATH_SYMBOL, + Character.CURRENCY_SYMBOL, + Character.MODIFIER_SYMBOL, + Character.OTHER_SYMBOL }; + + static final byte[] NUMBER = new byte[] + { Character.DECIMAL_DIGIT_NUMBER, + Character.LETTER_NUMBER, + Character.OTHER_NUMBER }; + + static final byte[] PUNCTUATION = new byte[] + { Character.DASH_PUNCTUATION, + Character.START_PUNCTUATION, + Character.END_PUNCTUATION, + Character.CONNECTOR_PUNCTUATION, + Character.OTHER_PUNCTUATION, + Character.INITIAL_QUOTE_PUNCTUATION, + Character.FINAL_QUOTE_PUNCTUATION}; + + static final byte[] OTHER = new byte[] + { Character.CONTROL, + Character.FORMAT, + Character.PRIVATE_USE, + Character.SURROGATE, + Character.UNASSIGNED }; + + RETokenNamedProperty(int subIndex, String name, boolean insens, boolean negate) throws REException { + super(subIndex); + this.name = name; + this.insens = insens; + this.negate = negate; + handler = getHandler(name); + } + + int getMinimumLength() { + return 1; + } + + int getMaximumLength() { + return 1; + } + + boolean match(CharIndexed input, REMatch mymatch) { + char ch = input.charAt(mymatch.index); + if (ch == CharIndexed.OUT_OF_BOUNDS) + return false; + + boolean retval = handler.includes(ch); + if (insens) { + retval = retval || + handler.includes(Character.toUpperCase(ch)) || + handler.includes(Character.toLowerCase(ch)); + } + + if (negate) retval = !retval; + if (retval) { + ++mymatch.index; + return next(input, mymatch); + } + else return false; + } + + void dump(StringBuffer os) { + os.append("\\") + .append(negate ? "P" : "p") + .append("{" + name + "}"); + } + + private abstract static class Handler { + public abstract boolean includes(char c); + } + + private Handler getHandler(String name) throws REException { + if (name.equals("Lower") || + name.equals("Upper") || + // name.equals("ASCII") || + name.equals("Alpha") || + name.equals("Digit") || + name.equals("Alnum") || + name.equals("Punct") || + name.equals("Graph") || + name.equals("Print") || + name.equals("Blank") || + name.equals("Cntrl") || + name.equals("XDigit") || + name.equals("Space") ) { + return new POSIXHandler(name); + } + if (name.startsWith("In")) { + try { + name = name.substring(2); + Character.UnicodeBlock block = Character.UnicodeBlock.forName(name); + return new UnicodeBlockHandler(block); + } + catch (IllegalArgumentException e) { + throw new REException("Invalid Unicode block name: " + name, REException.REG_ESCAPE, 0); + } + } + if (name.startsWith("Is")) { + name = name.substring(2); + } + + // "grouped properties" + if (name.equals("L")) + return new UnicodeCategoriesHandler(LETTER); + if (name.equals("M")) + return new UnicodeCategoriesHandler(MARK); + if (name.equals("Z")) + return new UnicodeCategoriesHandler(SEPARATOR); + if (name.equals("S")) + return new UnicodeCategoriesHandler(SYMBOL); + if (name.equals("N")) + return new UnicodeCategoriesHandler(NUMBER); + if (name.equals("P")) + return new UnicodeCategoriesHandler(PUNCTUATION); + if (name.equals("C")) + return new UnicodeCategoriesHandler(OTHER); + + if (name.equals("Mc")) + return new UnicodeCategoryHandler(Character.COMBINING_SPACING_MARK); + if (name.equals("Pc")) + return new UnicodeCategoryHandler(Character.CONNECTOR_PUNCTUATION); + if (name.equals("Cc")) + return new UnicodeCategoryHandler(Character.CONTROL); + if (name.equals("Sc")) + return new UnicodeCategoryHandler(Character.CURRENCY_SYMBOL); + if (name.equals("Pd")) + return new UnicodeCategoryHandler(Character.DASH_PUNCTUATION); + if (name.equals("Nd")) + return new UnicodeCategoryHandler(Character.DECIMAL_DIGIT_NUMBER); + if (name.equals("Me")) + return new UnicodeCategoryHandler(Character.ENCLOSING_MARK); + if (name.equals("Pe")) + return new UnicodeCategoryHandler(Character.END_PUNCTUATION); + if (name.equals("Pf")) + return new UnicodeCategoryHandler(Character.FINAL_QUOTE_PUNCTUATION); + if (name.equals("Cf")) + return new UnicodeCategoryHandler(Character.FORMAT); + if (name.equals("Pi")) + return new UnicodeCategoryHandler(Character.INITIAL_QUOTE_PUNCTUATION); + if (name.equals("Nl")) + return new UnicodeCategoryHandler(Character.LETTER_NUMBER); + if (name.equals("Zl")) + return new UnicodeCategoryHandler(Character.LINE_SEPARATOR); + if (name.equals("Ll")) + return new UnicodeCategoryHandler(Character.LOWERCASE_LETTER); + if (name.equals("Sm")) + return new UnicodeCategoryHandler(Character.MATH_SYMBOL); + if (name.equals("Lm")) + return new UnicodeCategoryHandler(Character.MODIFIER_LETTER); + if (name.equals("Sk")) + return new UnicodeCategoryHandler(Character.MODIFIER_SYMBOL); + if (name.equals("Mn")) + return new UnicodeCategoryHandler(Character.NON_SPACING_MARK); + if (name.equals("Lo")) + return new UnicodeCategoryHandler(Character.OTHER_LETTER); + if (name.equals("No")) + return new UnicodeCategoryHandler(Character.OTHER_NUMBER); + if (name.equals("Po")) + return new UnicodeCategoryHandler(Character.OTHER_PUNCTUATION); + if (name.equals("So")) + return new UnicodeCategoryHandler(Character.OTHER_SYMBOL); + if (name.equals("Zp")) + return new UnicodeCategoryHandler(Character.PARAGRAPH_SEPARATOR); + if (name.equals("Co")) + return new UnicodeCategoryHandler(Character.PRIVATE_USE); + if (name.equals("Zs")) + return new UnicodeCategoryHandler(Character.SPACE_SEPARATOR); + if (name.equals("Ps")) + return new UnicodeCategoryHandler(Character.START_PUNCTUATION); + if (name.equals("Cs")) + return new UnicodeCategoryHandler(Character.SURROGATE); + if (name.equals("Lt")) + return new UnicodeCategoryHandler(Character.TITLECASE_LETTER); + if (name.equals("Cn")) + return new UnicodeCategoryHandler(Character.UNASSIGNED); + if (name.equals("Lu")) + return new UnicodeCategoryHandler(Character.UPPERCASE_LETTER); + throw new REException("unsupported name " + name, REException.REG_ESCAPE, 0); + } + + private static class POSIXHandler extends Handler { + private RETokenPOSIX retoken; + private REMatch mymatch = new REMatch(0,0,0); + private char[] chars = new char[1]; + private CharIndexedCharArray ca = new CharIndexedCharArray(chars, 0); + public POSIXHandler(String name) { + int posixId = RETokenPOSIX.intValue(name.toLowerCase()); + if (posixId != -1) + retoken = new RETokenPOSIX(0,posixId,false,false); + else + throw new RuntimeException("Unknown posix ID: " + name); + } + public boolean includes(char c) { + chars[0] = c; + mymatch.index = 0; + return retoken.match(ca, mymatch); + } + } + + private static class UnicodeCategoryHandler extends Handler { + public UnicodeCategoryHandler(byte category) { + this.category = (int)category; + } + private int category; + public boolean includes(char c) { + return Character.getType(c) == category; + } + } + + private static class UnicodeCategoriesHandler extends Handler { + public UnicodeCategoriesHandler(byte[] categories) { + this.categories = categories; + } + private byte[] categories; + public boolean includes(char c) { + int category = Character.getType(c); + for (int i = 0; i < categories.length; i++) + if (category == categories[i]) + return true; + return false; + } + } + + private static class UnicodeBlockHandler extends Handler { + public UnicodeBlockHandler(Character.UnicodeBlock block) { + this.block = block; + } + private Character.UnicodeBlock block; + public boolean includes(char c) { + Character.UnicodeBlock cblock = Character.UnicodeBlock.of(c); + return (cblock != null && cblock.equals(block)); + } + } + +} diff --git a/gnu/regexp/RETokenOneOf.java b/gnu/regexp/RETokenOneOf.java index 3f6e89e21..260bc4b8f 100644 --- a/gnu/regexp/RETokenOneOf.java +++ b/gnu/regexp/RETokenOneOf.java @@ -1,5 +1,5 @@ /* gnu/regexp/RETokenOneOf.java - Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,11 +37,35 @@ exception statement from your version. */ package gnu.regexp; import java.util.Vector; +import java.util.Stack; final class RETokenOneOf extends REToken { private Vector options; private boolean negative; + private Vector addition; + // This Vector addition is used to store nested character classes. + // For example, if the original expression is + // [2-7a-c[f-k][m-z]&&[^p-v][st]] + // the basic part /2-7a-c/ is stored in the Vector options, and + // the additional part /[f-k][m-z]&&[^p-v][st]/ is stored in the + // Vector addition in the following order (Reverse Polish Notation): + // -- The matching result of the basic part is assumed here. + // [f-k] -- REToken + // "|" -- or + // [m-z] -- REToken + // "|" -- or + // false + // [^p-v] -- REToken + // "|" -- or + // [st] -- REToken + // "|" -- or + // "&" -- and + // + // As it is clear from the explanation above, the Vector addition is + // effective only when this REToken originates from a character class + // expression. + // This constructor is used for convenience when we know the set beforehand, // e.g. \d --> new RETokenOneOf("0123456789",false, ..) // \D --> new RETokenOneOf("0123456789",true, ..) @@ -60,7 +84,17 @@ final class RETokenOneOf extends REToken { this.negative = negative; } + RETokenOneOf(int subIndex, Vector options, Vector addition, boolean negative) { + super(subIndex); + this.options = options; + this.addition = addition; + this.negative = negative; + } + int getMinimumLength() { + // (negative || addition != null) occurs when this token originates from + // character class expression. + if (negative || addition != null) return 1; int min = Integer.MAX_VALUE; int x; for (int i=0; i < options.size(); i++) { @@ -70,54 +104,123 @@ final class RETokenOneOf extends REToken { return min; } + int getMaximumLength() { + // (negative || addition != null) occurs when this token originates from + // character class expression. + if (negative || addition != null) return 1; + int max = 0; + int x; + for (int i=0; i < options.size(); i++) { + if ((x = ((REToken) options.elementAt(i)).getMaximumLength()) > max) + max = x; + } + return max; + } + boolean match(CharIndexed input, REMatch mymatch) { - if (negative && (input.charAt(mymatch.index) == CharIndexed.OUT_OF_BOUNDS)) + REMatch tryMatch; + boolean tryOnly; + if (addition == null) { + tryMatch = mymatch; + tryOnly = false; + } + else { + tryMatch = (REMatch) mymatch.clone(); + tryOnly = true; + } + boolean b = negative ? + matchN(input, tryMatch, tryOnly) : + matchP(input, tryMatch, tryOnly); + if (addition == null) return b; + + Stack stack = new Stack(); + stack.push(new Boolean(b)); + for (int i=0; i < addition.size(); i++) { + Object obj = addition.elementAt(i); + if (obj instanceof REToken) { + b = ((REToken)obj).match(input, (REMatch)mymatch.clone()); + stack.push(new Boolean(b)); + } + else if (obj instanceof Boolean) { + stack.push(obj); + } + else if (obj.equals("|")) { + b = ((Boolean)stack.pop()).booleanValue(); + b = ((Boolean)stack.pop()).booleanValue() || b; + stack.push(new Boolean(b)); + } + else if (obj.equals("&")) { + b = ((Boolean)stack.pop()).booleanValue(); + b = ((Boolean)stack.pop()).booleanValue() && b; + stack.push(new Boolean(b)); + } + else { + throw new RuntimeException("Invalid object found"); + } + } + b = ((Boolean)stack.pop()).booleanValue(); + if (b) { + ++mymatch.index; + return next(input, mymatch); + } return false; + } - REMatch newMatch = null; - REMatch last = null; - REToken tk; - boolean isMatch; - for (int i=0; i < options.size(); i++) { + private boolean matchN(CharIndexed input, REMatch mymatch, boolean tryOnly) { + if (input.charAt(mymatch.index) == CharIndexed.OUT_OF_BOUNDS) + return false; + + REMatch newMatch = null; + REMatch last = null; + REToken tk; + for (int i=0; i < options.size(); i++) { tk = (REToken) options.elementAt(i); REMatch tryMatch = (REMatch) mymatch.clone(); if (tk.match(input, tryMatch)) { // match was successful - if (negative) return false; - - if (next(input, tryMatch)) { - // Add tryMatch to list of possibilities. - if (last == null) { - newMatch = tryMatch; - last = tryMatch; - } else { - last.next = tryMatch; - last = tryMatch; - } - } // next succeeds - } // is a match - } // try next option - - if (newMatch != null) { - if (negative) { return false; - } else { - // set contents of mymatch equal to newMatch + } // is a match + } // try next option - // try each one that matched - mymatch.assignFrom(newMatch); - return true; - } - } else { - if (negative) { - ++mymatch.index; - return next(input, mymatch); - } else { - return false; - } + if (tryOnly) return true; + ++mymatch.index; + return next(input, mymatch); } - // index+1 works for [^abc] lists, not for generic lookahead (--> index) - } + private boolean matchP(CharIndexed input, REMatch mymatch, boolean tryOnly) { + boolean stopMatchingIfSatisfied = + (mymatch.matchFlags & REMatch.MF_FIND_ALL) == 0; + REMatch.REMatchList newMatch = new REMatch.REMatchList(); + REToken tk; + for (int i=0; i < options.size(); i++) { + // In order that the backtracking can work, + // each option must be chained to the next token. + // But the chain method has some side effect, so + // we use clones. + tk = (REToken)((REToken) options.elementAt(i)).clone(); + if (! tryOnly) { + tk.chain(this.next); + tk.setUncle(this.uncle); + tk.subIndex = this.subIndex; + } + REMatch tryMatch = (REMatch) mymatch.clone(); + if (tk.match(input, tryMatch)) { // match was successful + if (tryOnly) return true; + newMatch.addTail(tryMatch); + if (stopMatchingIfSatisfied) break; + } // is a match + } // try next option + if (tryOnly) return false; + + if (newMatch.head != null) { + // set contents of mymatch equal to newMatch + + // try each one that matched + mymatch.assignFrom(newMatch.head); + return true; + } else { + return false; + } + } void dump(StringBuffer os) { os.append(negative ? "[^" : "(?:"); diff --git a/gnu/regexp/RETokenPOSIX.java b/gnu/regexp/RETokenPOSIX.java index bbb8066bc..4182c6fab 100644 --- a/gnu/regexp/RETokenPOSIX.java +++ b/gnu/regexp/RETokenPOSIX.java @@ -81,6 +81,10 @@ final class RETokenPOSIX extends REToken { return 1; } + int getMaximumLength() { + return 1; + } + boolean match(CharIndexed input, REMatch mymatch) { char ch = input.charAt(mymatch.index); if (ch == CharIndexed.OUT_OF_BOUNDS) diff --git a/gnu/regexp/RETokenRange.java b/gnu/regexp/RETokenRange.java index dadaf2d80..8a1ac86b2 100644 --- a/gnu/regexp/RETokenRange.java +++ b/gnu/regexp/RETokenRange.java @@ -43,19 +43,32 @@ final class RETokenRange extends REToken { RETokenRange(int subIndex, char lo, char hi, boolean ins) { super(subIndex); - this.lo = (insens = ins) ? Character.toLowerCase(lo) : lo; - this.hi = ins ? Character.toLowerCase(hi) : hi; + insens = ins; + this.lo = lo; + this.hi = hi; } int getMinimumLength() { return 1; } + int getMaximumLength() { + return 1; + } + boolean match(CharIndexed input, REMatch mymatch) { char c = input.charAt(mymatch.index); if (c == CharIndexed.OUT_OF_BOUNDS) return false; - if (insens) c = Character.toLowerCase(c); - if ((c >= lo) && (c <= hi)) { + boolean matches = (c >= lo) && (c <= hi); + if (! matches && insens) { + char c1 = Character.toLowerCase(c); + matches = (c1 >= lo) && (c1 <= hi); + if (!matches) { + c1 = Character.toUpperCase(c); + matches = (c1 >= lo) && (c1 <= hi); + } + } + if (matches) { ++mymatch.index; return next(input, mymatch); } diff --git a/gnu/regexp/RETokenRepeated.java b/gnu/regexp/RETokenRepeated.java index 6291a3c39..2d019c53c 100644 --- a/gnu/regexp/RETokenRepeated.java +++ b/gnu/regexp/RETokenRepeated.java @@ -1,5 +1,5 @@ /* gnu/regexp/RETokenRepeated.java - Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.regexp; import java.util.Vector; +import java.util.Arrays; final class RETokenRepeated extends REToken { private REToken token; @@ -82,6 +83,38 @@ final class RETokenRepeated extends REToken { return (min * token.getMinimumLength()); } + int getMaximumLength() { + if (max == Integer.MAX_VALUE) return Integer.MAX_VALUE; + int tmax = token.getMaximumLength(); + if (tmax == Integer.MAX_VALUE) return tmax; + return (max * tmax); + } + + private static REMatch findDoables(REToken tk, + CharIndexed input, REMatch mymatch) { + + REMatch.REMatchList doables = new REMatch.REMatchList(); + + // try next repeat at all possible positions + for (REMatch current = mymatch; + current != null; current = current.next) { + REMatch recurrent = (REMatch) current.clone(); + int origin = recurrent.index; + tk = (REToken) tk.clone(); + tk.next = tk.uncle = null; + recurrent.matchFlags |= REMatch.MF_FIND_ALL; + if (tk.match(input, recurrent)) { + for (REMatch m = recurrent; m != null; m = m.next) { + m.matchFlags &= ~REMatch.MF_FIND_ALL; + } + if (recurrent.index == origin) recurrent.empty = true; + // add all items in current to doables array + doables.addTail(recurrent); + } + } + return doables.head; + } + // We do need to save every possible point, but the number of clone() // invocations here is really a killer for performance on non-stingy // repeat operators. I'm open to suggestions... @@ -91,59 +124,167 @@ final class RETokenRepeated extends REToken { // the subexpression back-reference operator allow that? boolean match(CharIndexed input, REMatch mymatch) { - // number of times we've matched so far - int numRepeats = 0; - - // Possible positions for the next repeat to match at - REMatch newMatch = mymatch; - REMatch last = null; - REMatch current; - // Add the '0-repeats' index - // positions.elementAt(z) == position [] in input after <> matches - Vector positions = new Vector(); - positions.addElement(newMatch); - - // Declare variables used in loop - REMatch doables; - REMatch doablesLast; - REMatch recurrent; - int lastIndex = mymatch.index; - - do { - // Check for stingy match for each possibility. - if (stingy && (numRepeats >= min)) { - REMatch result = matchRest(input, newMatch); - if (result != null) { - mymatch.assignFrom(result); - return true; - } + boolean stopMatchingIfSatisfied = + (mymatch.matchFlags & REMatch.MF_FIND_ALL) == 0; + + REMatch newMatch = matchMinimum(input, mymatch); + if (newMatch == null) return false; + + // Array of positions we have already visited + int[] visited = initVisited(); + for (REMatch m = newMatch; m != null; m = m.next) { + visited = addVisited(m.index, visited); + } + + int max1 = decreaseMax(max, min); + + newMatch = _match(input, newMatch, max1, + stopMatchingIfSatisfied, visited); + if (newMatch != null) { + mymatch.assignFrom(newMatch); + return true; + } + return false; + } + + private static int decreaseMax(int m, int n) { + if (m == Integer.MAX_VALUE) return m; + return m - n; + } + + // Array visited is an array of character positions we have already + // visited. visited[0] is used to store the effective length of the + // array. + private static int[] initVisited() { + int[] visited = new int[32]; + visited[0] = 0; + return visited; + } + + private static boolean visitedContains(int n, int[] visited) { + // Experience tells that for a small array like this, + // simple linear search is faster than binary search. + for (int i = 1; i < visited[0]; i++) { + if (n == visited[i]) return true; + } + return false; + } + + private static int[] addVisited(int n, int[] visited) { + if (visitedContains(n, visited)) return visited; + if (visited[0] >= visited.length - 1) { + int[] newvisited = new int[visited.length + 32]; + System.arraycopy(visited, 0, newvisited, 0, visited.length); + visited = newvisited; + } + visited[0]++; + visited[visited[0]] = n; + return visited; + } + + private REMatch _match(CharIndexed input, REMatch mymatch, + int max1, boolean stopMatchingIfSatisfied, + int[] visited) { + + if (max1 == 0) { + return matchRest(input, mymatch); + } + max1 = decreaseMax(max1, 1); + + REMatch.REMatchList allResults = new REMatch.REMatchList(); + + // Depth-first search + + for (REMatch cur = mymatch; cur != null; cur = cur.next) { + + REMatch cur1 = (REMatch) cur.clone(); + + if (stingy) { + REMatch results = matchRest(input, cur1); + if (results != null) { + if (stopMatchingIfSatisfied) { + return results; + } + allResults.addTail(results); + } } - doables = null; - doablesLast = null; + DO_THIS: + do { - // try next repeat at all possible positions - for (current = newMatch; current != null; current = current.next) { - recurrent = (REMatch) current.clone(); - if (token.match(input, recurrent)) { - // add all items in current to doables array - if (doables == null) { - doables = recurrent; - doablesLast = recurrent; - } else { - // Order these from longest to shortest - // Start by assuming longest (more repeats) - doablesLast.next = recurrent; + boolean emptyMatchFound = false; + REMatch doables = findDoables(token, input, cur1); + if (doables == null) break DO_THIS; + if (doables.empty) emptyMatchFound = true; + + if (!emptyMatchFound) { + REMatch.REMatchList list = new REMatch.REMatchList(); + for (REMatch m = doables; m != null; m = m.next) { + REMatch m1 = (REMatch) m.clone(); + int n = m1.index; + if (! visitedContains(n, visited)) { + visited = addVisited(n, visited); + list.addTail(m1); } - // Find new doablesLast - while (doablesLast.next != null) { - doablesLast = doablesLast.next; + } + if (list.head == null) break DO_THIS; + doables = list.head; + } + + for (REMatch m = doables; m != null; m = m.next) { + if (! emptyMatchFound) { + REMatch m1 = _match(input, m, max1, + stopMatchingIfSatisfied, visited); + if (possessive) return m1; + if (m1 != null) { + if (stopMatchingIfSatisfied) { + return m1; + } + allResults.addTail(m1); + } + } + else { + REMatch m1 = matchRest(input, m); + if (m1 != null) { + if (stopMatchingIfSatisfied) { + return m1; + } + allResults.addTail(m1); } } } - // if none of the possibilities worked out, break out of do/while - if (doables == null) break; + + } while (false); // DO_THIS only once; + + // This point itself is a candidate. + if (!stingy) { + REMatch m2 = matchRest(input, cur1); + if (m2 != null) { + if (stopMatchingIfSatisfied) { + return m2; + } + allResults.addTail(m2); + } + } + } + + return allResults.head; + } + + private REMatch matchMinimum(CharIndexed input, final REMatch mymatch) { + // Possible positions for the next repeat to match at + REMatch newMatch = mymatch; + + // number of times we've matched so far + int numRepeats = 0; + + while (numRepeats < min) { + REMatch doables = findDoables(token, input, newMatch); + + // if none of the possibilities worked out, + // it means that minimum number of repeats could not be found. + if (doables == null) return null; // reassign where the next repeat can match newMatch = doables; @@ -151,91 +292,24 @@ final class RETokenRepeated extends REToken { // increment how many repeats we've successfully found ++numRepeats; - positions.addElement(newMatch); - - // doables.index == lastIndex means an empty string - // was the longest that matched this token. - // We break here, otherwise we will fall into an endless loop. - if (doables.index == lastIndex) { - if (numRepeats < min) numRepeats = min; - break; - } - lastIndex = doables.index; - } while (numRepeats < max); - - // If there aren't enough repeats, then fail - if (numRepeats < min) return false; - - // We're greedy, but ease off until a true match is found - int posIndex = positions.size(); - - // At this point we've either got too many or just the right amount. - // See if this numRepeats works with the rest of the regexp. - REMatch allResults = null; - REMatch allResultsLast = null; - - REMatch results = null; - int indexCount = posIndex - min; - if (indexCount <= 0) { - // This case occurs when we exited the previous do loop before - // numRepeats >= min because an empty string matched the token. - // In this case, an empty string can match as many times as - // desired. - indexCount = 1; - } - while (indexCount-- > 0) { - --posIndex; - newMatch = (REMatch) positions.elementAt(posIndex); - results = matchRest(input, newMatch); - if (results != null) { - if (allResults == null) { - allResults = results; - allResultsLast = results; - } else { - // Order these from longest to shortest - // Start by assuming longest (more repeats) - allResultsLast.next = results; - } - // Find new doablesLast - while (allResultsLast.next != null) { - allResultsLast = allResultsLast.next; - } - } - // else did not match rest of the tokens, try again on smaller sample - // or break out when performing possessive matching - if (possessive) break; + if (newMatch.empty) break; } - if (allResults != null) { - mymatch.assignFrom(allResults); // does this get all? - return true; - } - // If we fall out, no matches. - return false; + return newMatch; } private REMatch matchRest(CharIndexed input, final REMatch newMatch) { REMatch current, single; - REMatch doneIndex = null; - REMatch doneIndexLast = null; + REMatch.REMatchList doneIndex = new REMatch.REMatchList(); // Test all possible matches for this number of repeats for (current = newMatch; current != null; current = current.next) { // clone() separates a single match from the chain single = (REMatch) current.clone(); if (next(input, single)) { // chain results to doneIndex - if (doneIndex == null) { - doneIndex = single; - doneIndexLast = single; - } else { - doneIndexLast.next = single; - } - // Find new doneIndexLast - while (doneIndexLast.next != null) { - doneIndexLast = doneIndexLast.next; - } + doneIndex.addTail(single); } } - return doneIndex; + return doneIndex.head; } void dump(StringBuffer os) { diff --git a/gnu/regexp/RETokenStart.java b/gnu/regexp/RETokenStart.java index 8f7198237..42e3c0b2d 100644 --- a/gnu/regexp/RETokenStart.java +++ b/gnu/regexp/RETokenStart.java @@ -44,6 +44,10 @@ class RETokenStart extends REToken { super(subIndex); this.newline = newline; } + + int getMaximumLength() { + return 0; + } boolean match(CharIndexed input, REMatch mymatch) { // charAt(index-n) may be unknown on a Reader/InputStream. FIXME diff --git a/gnu/regexp/RETokenWordBoundary.java b/gnu/regexp/RETokenWordBoundary.java index 6804151e2..f86214bbf 100644 --- a/gnu/regexp/RETokenWordBoundary.java +++ b/gnu/regexp/RETokenWordBoundary.java @@ -52,6 +52,11 @@ final class RETokenWordBoundary extends REToken { this.where = where; this.negated = negated; } + + int getMaximumLength() { + return 0; + } + boolean match(CharIndexed input, REMatch mymatch) { // Word boundary means input[index-1] was a word character diff --git a/gnu/xml/aelfred2/XmlParser.java b/gnu/xml/aelfred2/XmlParser.java index ab2ed16f9..37466ca1c 100644 --- a/gnu/xml/aelfred2/XmlParser.java +++ b/gnu/xml/aelfred2/XmlParser.java @@ -2182,6 +2182,7 @@ loop: { nest++; } + break; case ']': if (tryRead("]>")) { diff --git a/gnu/xml/dom/DomCharacterData.java b/gnu/xml/dom/DomCharacterData.java index e94dcc4ec..1eec5bea7 100644 --- a/gnu/xml/dom/DomCharacterData.java +++ b/gnu/xml/dom/DomCharacterData.java @@ -1,5 +1,5 @@ /* DomCharacterData.java -- - Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. + Copyright (C) 1999,2000,2001,2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,6 +39,8 @@ package gnu.xml.dom; import org.w3c.dom.CharacterData; import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.w3c.dom.events.MutationEvent; @@ -55,6 +57,30 @@ public abstract class DomCharacterData implements CharacterData { + /** + * Empty node list representing the children of character data nodes. + */ + static class EmptyNodeList + implements NodeList + { + + public int getLength() + { + return 0; + } + + public Node item(int index) + { + return null; + } + + } + + /** + * Singleton empty node list for character data nodes. + */ + static final NodeList CHILD_NODES = new EmptyNodeList(); + private String text; // package private @@ -279,6 +305,15 @@ public abstract class DomCharacterData } } + /** + * Returns an empty node list. + * Character data nodes do not have children. + */ + public NodeList getChildNodes() + { + return CHILD_NODES; + } + /** * The base URI for character data is null. * @since DOM Level 3 Core diff --git a/gnu/xml/dom/DomDocumentBuilder.java b/gnu/xml/dom/DomDocumentBuilder.java index 42444e865..343f48c13 100644 --- a/gnu/xml/dom/DomDocumentBuilder.java +++ b/gnu/xml/dom/DomDocumentBuilder.java @@ -1,5 +1,5 @@ /* DomDocumentBuilder.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,9 +37,11 @@ exception statement from your version. */ package gnu.xml.dom; +import java.io.File; import java.io.InputStream; import java.io.IOException; import java.io.Reader; +import java.net.MalformedURLException; import java.net.URL; import javax.xml.parsers.DocumentBuilder; import org.w3c.dom.Document; @@ -157,8 +159,18 @@ class DomDocumentBuilder } else { - URL url = new URL(systemId); - input.setByteStream(url.openStream()); + try + { + URL url = new URL(systemId); + input.setByteStream(url.openStream()); + } + catch (MalformedURLException e) + { + // Maybe this is a relative file URL + File cwd = new File(System.getProperty("user.dir")); + URL url = new URL(cwd.toURL(), systemId); + input.setByteStream(url.openStream()); + } } } input.setPublicId(is.getPublicId()); diff --git a/gnu/xml/dom/DomDocumentBuilderFactory.java b/gnu/xml/dom/DomDocumentBuilderFactory.java index 814141c94..023478580 100644 --- a/gnu/xml/dom/DomDocumentBuilderFactory.java +++ b/gnu/xml/dom/DomDocumentBuilderFactory.java @@ -37,6 +37,7 @@ exception statement from your version. */ package gnu.xml.dom; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; @@ -59,6 +60,7 @@ public class DomDocumentBuilderFactory final DOMImplementation impl; final DOMImplementationLS ls; + private boolean secureProcessing; public DomDocumentBuilderFactory() { @@ -124,5 +126,26 @@ public class DomDocumentBuilderFactory // TODO } + public void setFeature(String name, boolean value) + throws ParserConfigurationException + { + if (name == null) + throw new NullPointerException(); + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + { + secureProcessing = true; + return; + } + throw new ParserConfigurationException(name); + } + + public boolean getFeature(String name) + throws ParserConfigurationException + { + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + return secureProcessing; + throw new ParserConfigurationException(name); + } + } diff --git a/gnu/xml/dom/JAXPFactory.java b/gnu/xml/dom/JAXPFactory.java index 8f481fad6..ca14a8e9d 100644 --- a/gnu/xml/dom/JAXPFactory.java +++ b/gnu/xml/dom/JAXPFactory.java @@ -49,6 +49,7 @@ import org.xml.sax.XMLReader; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -70,6 +71,7 @@ public final class JAXPFactory private static final String FEATURE = "http://xml.org/sax/features/"; private SAXParserFactory pf; + private boolean secureProcessing; /** * Default constructor. @@ -138,6 +140,27 @@ public final class JAXPFactory throw new IllegalArgumentException(name); } + public void setFeature(String name, boolean value) + throws ParserConfigurationException + { + if (name == null) + throw new NullPointerException(); + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + { + secureProcessing = true; + return; + } + throw new ParserConfigurationException(name); + } + + public boolean getFeature(String name) + throws ParserConfigurationException + { + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + return secureProcessing; + throw new ParserConfigurationException(name); + } + static final class JAXPBuilder extends DocumentBuilder implements ErrorHandler diff --git a/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java b/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java index c4f0ce201..c8918aa72 100644 --- a/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java +++ b/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java @@ -37,6 +37,7 @@ exception statement from your version. */ package gnu.xml.libxmlj.dom; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -47,9 +48,11 @@ import javax.xml.parsers.ParserConfigurationException; * @author Chris Burdess */ public class GnomeDocumentBuilderFactory -extends DocumentBuilderFactory + extends DocumentBuilderFactory { + private boolean secureProcessing; + public GnomeDocumentBuilderFactory () { setNamespaceAware (true); @@ -91,4 +94,25 @@ extends DocumentBuilderFactory // TODO } + public void setFeature(String name, boolean value) + throws ParserConfigurationException + { + if (name == null) + throw new NullPointerException(); + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + { + secureProcessing = true; + return; + } + throw new ParserConfigurationException(name); + } + + public boolean getFeature(String name) + throws ParserConfigurationException + { + if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(name)) + return secureProcessing; + throw new ParserConfigurationException(name); + } + } diff --git a/gnu/xml/stream/CRLFReader.java b/gnu/xml/stream/CRLFReader.java index 1d214ce52..dad02b94a 100644 --- a/gnu/xml/stream/CRLFReader.java +++ b/gnu/xml/stream/CRLFReader.java @@ -1,5 +1,5 @@ /* CRLFReader.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -153,13 +153,14 @@ class CRLFReader throws IOException { doReset = false; - int lm1 = len - 1; - for (int i = off; i < len; i++) + int end = off + len; + int em1 = end - 1; + for (int i = off; i < end; i++) { if (b[i] == '\r') // CR { int d; - if (i == lm1) + if (i == em1) { d = in.read(); doReset = true; diff --git a/gnu/xml/stream/SAXParser.java b/gnu/xml/stream/SAXParser.java index 54c8b3624..ee20851f9 100644 --- a/gnu/xml/stream/SAXParser.java +++ b/gnu/xml/stream/SAXParser.java @@ -649,8 +649,11 @@ public class SAXParser lexicalHandler.endDTD(); } } + reset(); + if (opened) + in.close(); } - catch (XMLStreamException e) + catch (Exception e) { if (!startDocumentDone && contentHandler != null) contentHandler.startDocument(); @@ -660,13 +663,13 @@ public class SAXParser errorHandler.fatalError(e2); if (contentHandler != null) contentHandler.endDocument(); - throw e2; - } - finally - { + reset(); if (opened) in.close(); - reset(); + if (e instanceof IOException) + throw (IOException) e; + else + throw e2; } } @@ -901,7 +904,16 @@ public class SAXParser InputSource input = entityResolver.resolveEntity(publicId, systemId); if (input != null) - return input.getByteStream(); + { + InputStream in = input.getByteStream(); + if (in == null) + { + String newSystemId = input.getSystemId(); + if (newSystemId != null && !newSystemId.equals(systemId)) + in = XMLParser.resolve(newSystemId); + } + return in; + } } catch (SAXException e) { diff --git a/gnu/xml/stream/UnicodeReader.java b/gnu/xml/stream/UnicodeReader.java index c38516c30..9350cb2e0 100644 --- a/gnu/xml/stream/UnicodeReader.java +++ b/gnu/xml/stream/UnicodeReader.java @@ -45,7 +45,7 @@ import java.io.Reader; * * @author Chris Burdess */ -class UnicodeReader +public class UnicodeReader { final Reader in; @@ -152,6 +152,10 @@ class UnicodeReader in.close(); } + /** + * Returns the specified UTF-16 char array as an array of Unicode code + * points. + */ public static int[] toCodePointArray(String text) throws IOException { diff --git a/gnu/xml/stream/XIncludeFilter.java b/gnu/xml/stream/XIncludeFilter.java index e151ac69d..6d12bb3b2 100644 --- a/gnu/xml/stream/XIncludeFilter.java +++ b/gnu/xml/stream/XIncludeFilter.java @@ -42,6 +42,7 @@ import java.io.InputStreamReader; import java.io.IOException; import java.io.Reader; import java.net.HttpURLConnection; +import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.HashSet; @@ -121,7 +122,17 @@ class XIncludeFilter boolean expandERefs) { super(reader); - this.systemId = XMLParser.absolutize(null, systemId); + try + { + this.systemId = XMLParser.absolutize(null, systemId); + } + catch (MalformedURLException e) + { + RuntimeException e2 = new RuntimeException("unsupported URL: " + + systemId); + e2.initCause(e); + throw e2; + } this.namespaceAware = namespaceAware; this.validating = validating; this.expandERefs = expandERefs; diff --git a/gnu/xml/stream/XMLParser.java b/gnu/xml/stream/XMLParser.java index 6f10b9303..147fff720 100644 --- a/gnu/xml/stream/XMLParser.java +++ b/gnu/xml/stream/XMLParser.java @@ -710,7 +710,7 @@ public class XMLParser public int getNamespaceCount() { - if (!namespaceAware) + if (!namespaceAware || namespaces.isEmpty()) return 0; switch (event) { @@ -984,10 +984,10 @@ public class XMLParser if (event == XMLStreamConstants.END_ELEMENT) { // Pop namespace context - if (namespaceAware) + if (namespaceAware && !namespaces.isEmpty()) namespaces.removeFirst(); // Pop base context - if (baseAware) + if (baseAware && !bases.isEmpty()) bases.removeFirst(); } if (!startEntityStack.isEmpty()) @@ -1484,7 +1484,6 @@ public class XMLParser { if (!externalEntities) return; - InputStream in = null; String url = absolutize(input.systemId, ids.systemId); // Check for recursion for (Iterator i = inputStack.iterator(); i.hasNext(); ) @@ -1497,7 +1496,8 @@ public class XMLParser } if (name == null || "".equals(name)) report = false; - if (in == null && url != null && resolver != null) + InputStream in = null; + if (resolver != null) { if (resolver instanceof XMLResolver2) in = ((XMLResolver2) resolver).resolve(ids.publicId, url); @@ -1535,12 +1535,13 @@ public class XMLParser * @param base the current base URL * @param href the (absolute or relative) URL to resolve */ - static String absolutize(String base, String href) + public static String absolutize(String base, String href) + throws MalformedURLException { if (href == null) return null; int ci = href.indexOf(':'); - if (ci > 1 && isLowercaseAscii(href.substring(0, ci))) + if (ci > 1 && isURLScheme(href.substring(0, ci))) { // href is absolute already return href; @@ -1565,40 +1566,23 @@ public class XMLParser if (!base.endsWith("/")) base += "/"; } - if (href.startsWith("/")) - { - if (base.startsWith("file:")) - return "file://" + href; - int i = base.indexOf("://"); - if (i != -1) - { - i = base.indexOf('/', i + 3); - if (i != -1) - base = base.substring(0, i); - } - } - else - { - while (href.startsWith("..")) - { - int i = base.lastIndexOf('/', base.length() - 2); - if (i != -1) - base = base.substring(0, i + 1); - href = href.substring(2); - if (href.startsWith("/")) - href = href.substring(1); - } - } - return base + href; + return new URL(new URL(base), href).toString(); } - private static boolean isLowercaseAscii(String text) + /** + * Indicates whether the specified characters match the scheme portion of + * a URL. + * @see RFC 1738 section 2.1 + */ + private static boolean isURLScheme(String text) { int len = text.length(); for (int i = 0; i < len; i++) { char c = text.charAt(i); - if (c < 97 || c > 122) + if (c == '+' || c == '.' || c == '-') + continue; + if (c < 65 || (c > 90 && c < 97) || c > 122) return false; } return true; @@ -1607,7 +1591,7 @@ public class XMLParser /** * Returns an input stream for the given URL. */ - private InputStream resolve(String url) + static InputStream resolve(String url) throws IOException { try @@ -1618,6 +1602,12 @@ public class XMLParser { return null; } + catch (IOException e) + { + IOException e2 = new IOException("error resolving " + url); + e2.initCause(e); + throw e2; + } } /** @@ -1891,7 +1881,10 @@ public class XMLParser throws IOException, XMLStreamException { requireWhitespace(); + boolean saved = expandPE; + expandPE = (inputStack.size() > 1); String name = readNmtoken(true); + expandPE = saved; requireWhitespace(); readContentspec(name); skipWhitespace(); @@ -2106,7 +2099,10 @@ public class XMLParser throws IOException, XMLStreamException { requireWhitespace(); + boolean saved = expandPE; + expandPE = (inputStack.size() > 1); String elementName = readNmtoken(true); + expandPE = saved; boolean white = tryWhitespace(); while (!tryRead('>')) { @@ -2419,11 +2415,11 @@ public class XMLParser } else { - if (!isNameStartCharacter(cp[0])) + if (!isNameStartCharacter(cp[0], input.xml11)) error("malformed reference in entity value", value); for (int i = 1; i < cp.length; i++) { - if (!isNameCharacter(cp[i])) + if (!isNameCharacter(cp[i], input.xml11)) error("malformed reference in entity value", value); } } @@ -2838,8 +2834,6 @@ public class XMLParser error("Duplicate default namespace declaration"); if (XMLConstants.XML_NS_URI.equals(attr.value)) error("can't bind XML namespace"); - if ("".equals(attr.value) && !input.xml11) - error("illegal use of 1.1-style prefix unbinding in 1.0 document"); ctx.put(XMLConstants.DEFAULT_NS_PREFIX, attr.value); return true; } @@ -3087,7 +3081,15 @@ public class XMLParser break; case 0x3c: // '<' reset(); - read(tmpBuf, 0, i); + // read i characters + int count = 0, remaining = i; + do + { + int r = read(tmpBuf, 0, remaining); + count += r; + remaining -= r; + } + while (count < i); i = len; if (coalescing && tryRead(TEST_CDATA)) readUntil(TEST_END_CDATA); // read CDATA section into buf @@ -3258,15 +3260,7 @@ public class XMLParser reset(); char[] ref = readCharacterRef(hex ? 16 : 10); for (int i = 0; i < ref.length; i++) - { - char x = ref[i]; - if ((flags & (LIT_ATTRIBUTE | LIT_PUBID)) != 0 && - (x == 0x0a || x == 0x0d)) - x = 0x20; // normalize - else if ((flags & LIT_ATTRIBUTE) != 0 && x == 0x09) - x = 0x20; // normalize - literalBuf.append(x); - } + literalBuf.append(ref[i]); entities = true; continue; } @@ -3469,13 +3463,13 @@ public class XMLParser int c = readCh(); if (isName) { - if (!isNameStartCharacter(c)) + if (!isNameStartCharacter(c, input.xml11)) error("not a name start character", "U+" + Integer.toHexString(c)); } else { - if (!isNameCharacter(c)) + if (!isNameCharacter(c, input.xml11)) error("not a name character", "U+" + Integer.toHexString(c)); } @@ -3510,7 +3504,7 @@ public class XMLParser reset(); return intern(buf.toString()); default: - if (!isNameCharacter(c)) + if (!isNameCharacter(c, input.xml11)) error("not a name character", "U+" + Integer.toHexString(c)); else @@ -3523,7 +3517,7 @@ public class XMLParser /** * Indicates whether the specified Unicode character is an XML 1.1 Char. */ - private boolean isXML11Char(int c) + public static boolean isXML11Char(int c) { return ((c >= 0x0001 && c <= 0xD7FF) || (c >= 0xE000 && c < 0xFFFD) || // NB exclude 0xfffd @@ -3534,7 +3528,7 @@ public class XMLParser * Indicates whether the specified Unicode character is an XML 1.1 * RestrictedChar. */ - private boolean isXML11RestrictedChar(int c) + public static boolean isXML11RestrictedChar(int c) { return ((c >= 0x0001 && c <= 0x0008) || (c >= 0x000B && c <= 0x000C) || @@ -3556,17 +3550,17 @@ public class XMLParser return false; if (isName) { - if (!isNameStartCharacter(cp[0])) + if (!isNameStartCharacter(cp[0], input.xml11)) return false; } else { - if (!isNameCharacter(cp[0])) + if (!isNameCharacter(cp[0], input.xml11)) return false; } for (int i = 1; i < cp.length; i++) { - if (!isNameCharacter(cp[i])) + if (!isNameCharacter(cp[i], input.xml11)) return false; } return true; @@ -3581,9 +3575,9 @@ public class XMLParser * Indicates whether the specified Unicode character is a Name start * character. */ - private boolean isNameStartCharacter(int c) + public static boolean isNameStartCharacter(int c, boolean xml11) { - if (input.xml11) + if (xml11) return ((c >= 0x0041 && c <= 0x005a) || (c >= 0x0061 && c <= 0x007a) || c == 0x3a | @@ -3608,9 +3602,9 @@ public class XMLParser * Indicates whether the specified Unicode character is a Name non-initial * character. */ - private boolean isNameCharacter(int c) + public static boolean isNameCharacter(int c, boolean xml11) { - if (input.xml11) + if (xml11) return ((c >= 0x0041 && c <= 0x005a) || (c >= 0x0061 && c <= 0x007a) || (c >= 0x0030 && c <= 0x0039) || diff --git a/gnu/xml/stream/XMLStreamWriterImpl.java b/gnu/xml/stream/XMLStreamWriterImpl.java index 6157296c6..291016e67 100644 --- a/gnu/xml/stream/XMLStreamWriterImpl.java +++ b/gnu/xml/stream/XMLStreamWriterImpl.java @@ -104,6 +104,9 @@ public class XMLStreamWriterImpl private NamespaceSupport namespaces; private int count = 0; + private boolean xml11; + private boolean hasXML11RestrictedChars; + /** * Constructor. * @see #writer @@ -145,6 +148,9 @@ public class XMLStreamWriterImpl { try { + if (!isName(localName)) + throw new IllegalArgumentException("illegal Name: " + localName); + endStartElement(); namespaces.pushContext(); @@ -167,6 +173,11 @@ public class XMLStreamWriterImpl { try { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (!isName(localName)) + throw new IllegalArgumentException("illegal Name: " + localName); + endStartElement(); namespaces.pushContext(); @@ -190,7 +201,7 @@ public class XMLStreamWriterImpl inStartElement = true; if (!isDeclared) { - writeNamespace(prefix, namespaceURI); + writeNamespaceImpl(prefix, namespaceURI); } elements.addLast(new String[] { prefix, localName }); @@ -229,6 +240,13 @@ public class XMLStreamWriterImpl { try { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (prefix != null && !isNCName(prefix)) + throw new IllegalArgumentException("illegal NCName: " + prefix); + if (!isNCName(localName)) + throw new IllegalArgumentException("illegal NCName: " + localName); + endStartElement(); namespaces.pushContext(); @@ -243,7 +261,7 @@ public class XMLStreamWriterImpl writer.write(localName); if (prefixDefaulting && !isCurrent) { - writeNamespace(prefix, namespaceURI); + writeNamespaceImpl(prefix, namespaceURI); } elements.addLast(new String[] { prefix, localName }); @@ -343,11 +361,19 @@ public class XMLStreamWriterImpl throw new IllegalStateException(); try { + if (!isName(localName)) + throw new IllegalArgumentException("illegal Name: " + localName); + if (!isChars(value)) + throw new IllegalArgumentException("illegal character: " + value); + writer.write(' '); writer.write(localName); writer.write('='); writer.write('"'); - writeEncoded(value, true); + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(value, true); + else + writeEncoded(value, true); writer.write('"'); } catch (IOException e) @@ -366,11 +392,20 @@ public class XMLStreamWriterImpl throw new IllegalStateException(); try { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (prefix != null && !isNCName(prefix)) + throw new IllegalArgumentException("illegal NCName: " + prefix); + if (!isNCName(localName)) + throw new IllegalArgumentException("illegal NCName: " + localName); + if (!isChars(value)) + throw new IllegalArgumentException("illegal character: " + value); + String currentPrefix = getPrefix(namespaceURI); if (currentPrefix == null) { if (prefixDefaulting) - writeNamespace(prefix, namespaceURI); + writeNamespaceImpl(prefix, namespaceURI); else throw new XMLStreamException("namespace " + namespaceURI + " is not bound"); @@ -388,7 +423,10 @@ public class XMLStreamWriterImpl writer.write(localName); writer.write('='); writer.write('"'); - writeEncoded(value, true); + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(value, true); + else + writeEncoded(value, true); writer.write('"'); } catch (IOException e) @@ -407,13 +445,20 @@ public class XMLStreamWriterImpl throw new IllegalStateException(); try { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (!isName(localName)) + throw new IllegalArgumentException("illegal Name: " + localName); + if (!isChars(value)) + throw new IllegalArgumentException("illegal character: " + value); + String prefix = getPrefix(namespaceURI); if (prefix == null) { if (prefixDefaulting) { prefix = XMLConstants.DEFAULT_NS_PREFIX; - writeNamespace(prefix, namespaceURI); + writeNamespaceImpl(prefix, namespaceURI); } else throw new XMLStreamException("namespace " + namespaceURI + @@ -428,7 +473,10 @@ public class XMLStreamWriterImpl writer.write(localName); writer.write('='); writer.write('"'); - writeEncoded(value, true); + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(value, true); + else + writeEncoded(value, true); writer.write('"'); } catch (IOException e) @@ -444,6 +492,25 @@ public class XMLStreamWriterImpl { if (!inStartElement) throw new IllegalStateException(); + try + { + if (!isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (!isNCName(prefix)) + throw new IllegalArgumentException("illegal NCName: " + prefix); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + writeNamespaceImpl(prefix, namespaceURI); + } + + private void writeNamespaceImpl(String prefix, String namespaceURI) + throws XMLStreamException + { try { if (prefix == null) @@ -474,21 +541,41 @@ public class XMLStreamWriterImpl public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException { - writeNamespace(XMLConstants.DEFAULT_NS_PREFIX, namespaceURI); + if (!inStartElement) + throw new IllegalStateException(); + if (!isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + writeNamespaceImpl(XMLConstants.DEFAULT_NS_PREFIX, namespaceURI); } public void writeComment(String data) throws XMLStreamException { + if (data == null) + return; try { + if (!isChars(data)) + throw new IllegalArgumentException("illegal XML character: " + data); + if (data.indexOf("--") != -1) + throw new IllegalArgumentException("illegal comment: " + data); + endStartElement(); - if (data != null && data.indexOf("--") != -1) - throw new IllegalArgumentException(data); - writer.write(""); } @@ -511,6 +598,11 @@ public class XMLStreamWriterImpl { try { + if (!isName(target) || "xml".equalsIgnoreCase(target)) + throw new IllegalArgumentException("illegal PITarget: " + target); + if (data != null && !isChars(data)) + throw new IllegalArgumentException("illegal XML character: " + data); + endStartElement(); writer.write('<'); @@ -519,7 +611,20 @@ public class XMLStreamWriterImpl if (data != null) { writer.write(' '); - writer.write(data); + if (hasXML11RestrictedChars) + { + int[] seq = UnicodeReader.toCodePointArray(data); + for (int i = 0; i < seq.length; i++) + { + int c = seq[i]; + if (XMLParser.isXML11RestrictedChar(c)) + writer.write("&#x" + Integer.toHexString(c) + ";"); + else + writer.write(Character.toChars(i)); + } + } + else + writer.write(data); } writer.write('?'); writer.write('>'); @@ -537,10 +642,12 @@ public class XMLStreamWriterImpl { try { - endStartElement(); - + if (!isChars(data) || hasXML11RestrictedChars) + throw new IllegalArgumentException("illegal XML character: " + data); if (data.indexOf("]]") != -1) - throw new IllegalArgumentException(data); + throw new IllegalArgumentException("illegal CDATA section: " + data); + + endStartElement(); writer.write("'); @@ -576,6 +687,9 @@ public class XMLStreamWriterImpl { try { + if (!isName(name)) + throw new IllegalArgumentException("illegal Name: " + name); + endStartElement(); writer.write('&'); @@ -607,6 +721,8 @@ public class XMLStreamWriterImpl { if (version == null) version = "1.0"; + else if ("1.1".equals(version)) + xml11 = true; encoding = this.encoding; // YES: the parameter must be ignored if (encoding == null) encoding = "UTF-8"; @@ -632,11 +748,18 @@ public class XMLStreamWriterImpl public void writeCharacters(String text) throws XMLStreamException { + if (text == null) + return; try { + if (!isChars(text)) + throw new IllegalArgumentException("illegal XML character: " + text); + endStartElement(); - if (text != null) + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(text, false); + else writeEncoded(text, false); } catch (IOException e) @@ -650,39 +773,7 @@ public class XMLStreamWriterImpl public void writeCharacters(char[] text, int start, int len) throws XMLStreamException { - try - { - endStartElement(); - - int end = start + len; - len = 0; - for (int i = start; i < end; i++) - { - char c = text[i]; - if (c == '<' || c == '>' || c == '&') - { - writer.write(text, start, len); - if (c == '<') - writer.write("<"); - else if (c == '>') - writer.write(">"); - else - writer.write("&"); - start = i + 1; - len = 0; - } - else - len++; - } - if (len > 0) - writer.write(text, start, len); - } - catch (IOException e) - { - XMLStreamException e2 = new XMLStreamException(e); - e2.initCause(e); - throw e2; - } + writeCharacters(new String(text, start, len)); } public String getPrefix(String uri) @@ -697,6 +788,19 @@ public class XMLStreamWriterImpl public void setPrefix(String prefix, String uri) throws XMLStreamException { + try + { + if (!isURI(uri)) + throw new IllegalArgumentException("illegal URI: " + uri); + if (!isNCName(prefix)) + throw new IllegalArgumentException("illegal NCName: " + prefix); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } if (!namespaces.declarePrefix(prefix, uri)) throw new XMLStreamException("illegal prefix " + prefix); } @@ -704,6 +808,8 @@ public class XMLStreamWriterImpl public void setDefaultNamespace(String uri) throws XMLStreamException { + if (!isURI(uri)) + throw new IllegalArgumentException("illegal URI: " + uri); if (!namespaces.declarePrefix(XMLConstants.DEFAULT_NS_PREFIX, uri)) throw new XMLStreamException("illegal default namespace prefix"); } @@ -769,6 +875,131 @@ public class XMLStreamWriterImpl if (len > 0) writer.write(chars, start, len); } + + /** + * Writes the specified text, in the knowledge that some of the + * characters are XML 1.1 restricted characters. + */ + private void writeEncodedWithRestrictedChars(String text, boolean inAttr) + throws IOException + { + int[] seq = UnicodeReader.toCodePointArray(text); + for (int i = 0; i < seq.length; i++) + { + int c = seq[i]; + switch (c) + { + case 0x3c: // '<' + writer.write("<"); + break; + case 0x3e: // '>' + writer.write(">"); + break; + case 0x26: // '&' + writer.write("&"); + break; + case 0x22: // '"' + if (inAttr) + writer.write("""); + else + writer.write(c); + break; + case 0x27: // '\'' + if (inAttr) + writer.write("'"); + else + writer.write(c); + break; + default: + if (XMLParser.isXML11RestrictedChar(c)) + writer.write("&#x" + Integer.toHexString(c) + ";"); + else + { + char[] chars = Character.toChars(c); + writer.write(chars, 0, chars.length); + } + } + } + } + + private boolean isName(String text) + throws IOException + { + if (text == null) + return false; + int[] seq = UnicodeReader.toCodePointArray(text); + if (seq.length < 1) + return false; + if (!XMLParser.isNameStartCharacter(seq[0], xml11)) + return false; + for (int i = 1; i < seq.length; i++) + { + if (!XMLParser.isNameCharacter(seq[i], xml11)) + return false; + } + return true; + } + + private boolean isNCName(String text) + throws IOException + { + if (text == null) + return false; + int[] seq = UnicodeReader.toCodePointArray(text); + if (seq.length < 1) + return false; + if (!XMLParser.isNameStartCharacter(seq[0], xml11) || seq[0] == 0x3a) + return false; + for (int i = 1; i < seq.length; i++) + { + if (!XMLParser.isNameCharacter(seq[i], xml11) || seq[i] == 0x3a) + return false; + } + return true; + } + + private boolean isChars(String text) + throws IOException + { + if (text == null) + return false; + int[] seq = UnicodeReader.toCodePointArray(text); + hasXML11RestrictedChars = false; + if (xml11) + { + for (int i = 0; i < seq.length; i++) + { + if (!XMLParser.isXML11Char(seq[i])) + return false; + if (XMLParser.isXML11RestrictedChar(seq[i])) + hasXML11RestrictedChars = true; + } + } + else + { + for (int i = 0; i < seq.length; i++) + { + if (!XMLParser.isChar(seq[i])) + return false; + } + } + return true; + } + + private boolean isURI(String text) + { + if (text == null) + return false; + char[] chars = text.toCharArray(); + if (chars.length < 1) + return false; + for (int i = 0; i < chars.length; i++) + { + if (chars[i] < 0x20 || chars[i] >= 0x7f) + return false; + } + return true; + } } diff --git a/gnu/xml/transform/AbstractNumberNode.java b/gnu/xml/transform/AbstractNumberNode.java index 91029d6d0..6d1202e69 100644 --- a/gnu/xml/transform/AbstractNumberNode.java +++ b/gnu/xml/transform/AbstractNumberNode.java @@ -317,7 +317,7 @@ abstract class AbstractNumberNode public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("number"); buf.append('['); buf.append("format="); buf.append(format); diff --git a/gnu/xml/transform/ApplyImportsNode.java b/gnu/xml/transform/ApplyImportsNode.java index 60dec85d3..4b06eea10 100644 --- a/gnu/xml/transform/ApplyImportsNode.java +++ b/gnu/xml/transform/ApplyImportsNode.java @@ -1,5 +1,5 @@ /* ApplyImportsNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -54,13 +54,9 @@ final class ApplyImportsNode { TemplateNode ret = new ApplyImportsNode(); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } @@ -71,15 +67,16 @@ final class ApplyImportsNode { TemplateNode t = stylesheet.getTemplate(mode, context, true); if (t != null) - { - t.apply(stylesheet, mode, context, pos, len, - parent, nextSibling); - } + t.apply(stylesheet, mode, context, pos, len, + parent, nextSibling); if (next != null) - { - next.apply(stylesheet, mode, context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, context, pos, len, + parent, nextSibling); + } + + public String toString() + { + return "apply-imports"; } } diff --git a/gnu/xml/transform/ApplyTemplatesNode.java b/gnu/xml/transform/ApplyTemplatesNode.java index ab26058bc..38b605a07 100644 --- a/gnu/xml/transform/ApplyTemplatesNode.java +++ b/gnu/xml/transform/ApplyTemplatesNode.java @@ -1,5 +1,5 @@ /* ApplyTemplatesNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -76,29 +76,21 @@ final class ApplyTemplatesNode TemplateNode clone(Stylesheet stylesheet) { - int len = sortKeys.size(); + int len = sortKeys != null ? sortKeys.size() : 0; List sortKeys2 = new ArrayList(len); for (int i = 0; i < len; i++) - { - sortKeys2.add(((Key) sortKeys.get(i)).clone(stylesheet)); - } + sortKeys2.add(((Key) sortKeys.get(i)).clone(stylesheet)); len = withParams.size(); List withParams2 = new ArrayList(len); for (int i = 0; i < len; i++) - { - withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet)); - } + withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet)); TemplateNode ret = new ApplyTemplatesNode(select.clone(stylesheet), mode, sortKeys2, withParams2, isDefault); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } @@ -147,9 +139,7 @@ final class ApplyTemplatesNode Collections.sort(nodes, new XSLComparator(sortKeys)); } else - { - Collections.sort(nodes, documentOrderComparator); - } + Collections.sort(nodes, documentOrderComparator); int l = nodes.size(); QName effectiveMode = isDefault ? mode : this.mode; for (int i = 0; i < l; i++) @@ -172,27 +162,21 @@ final class ApplyTemplatesNode } // apply-templates doesn't have processable children if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } public boolean references(QName var) { if (select != null && select.references(var)) - { - return true; - } + return true; if (withParams != null) { for (Iterator i = withParams.iterator(); i.hasNext(); ) { if (((WithParam) i.next()).references(var)) - { - return true; - } + return true; } } if (sortKeys != null) @@ -200,9 +184,7 @@ final class ApplyTemplatesNode for (Iterator i = sortKeys.iterator(); i.hasNext(); ) { if (((SortKey) i.next()).references(var)) - { - return true; - } + return true; } } return super.references(var); @@ -210,7 +192,7 @@ final class ApplyTemplatesNode public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("apply-templates"); buf.append('['); boolean o = false; if (select != null) diff --git a/gnu/xml/transform/AttributeNode.java b/gnu/xml/transform/AttributeNode.java index bc5bc30c9..71e2ed0f7 100644 --- a/gnu/xml/transform/AttributeNode.java +++ b/gnu/xml/transform/AttributeNode.java @@ -231,7 +231,7 @@ final class AttributeNode public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("attribute"); buf.append('['); buf.append("name="); buf.append(name); diff --git a/gnu/xml/transform/CallTemplateNode.java b/gnu/xml/transform/CallTemplateNode.java index b678219d7..31b26cbcd 100644 --- a/gnu/xml/transform/CallTemplateNode.java +++ b/gnu/xml/transform/CallTemplateNode.java @@ -1,5 +1,5 @@ /* CallTemplateNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -69,18 +69,12 @@ final class CallTemplateNode int len = withParams.size(); List withParams2 = new ArrayList(len); for (int i = 0; i < len; i++) - { - withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet)); - } + withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet)); TemplateNode ret = new CallTemplateNode(name, withParams2); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } @@ -89,52 +83,52 @@ final class CallTemplateNode Node parent, Node nextSibling) throws TransformerException { - if (withParams != null) + TemplateNode t = stylesheet.getTemplate(mode, name); + if (t != null) { - // compute the parameter values - LinkedList values = new LinkedList(); - for (Iterator i = withParams.iterator(); i.hasNext(); ) + if (withParams != null) { - WithParam p = (WithParam) i.next(); - Object value = p.getValue(stylesheet, mode, context, pos, len); - Object[] pair = new Object[2]; - pair[0] = p.name; - pair[1] = value; - values.add(pair); - } - // push the parameter context - stylesheet.bindings.push(Bindings.WITH_PARAM); - // set the parameters - for (Iterator i = values.iterator(); i.hasNext(); ) - { - Object[] pair = (Object[]) i.next(); - QName name = (QName) pair[0]; - Object value = pair[1]; - stylesheet.bindings.set(name, value, Bindings.WITH_PARAM); - if (stylesheet.debug) + // compute the parameter values + LinkedList values = new LinkedList(); + for (Iterator i = withParams.iterator(); i.hasNext(); ) + { + WithParam p = (WithParam) i.next(); + if (t.hasParam(p.name)) // ignore parameters not specified + { + Object value = p.getValue(stylesheet, mode, context, + pos, len); + Object[] pair = new Object[2]; + pair[0] = p.name; + pair[1] = value; + values.add(pair); + } + } + // push the parameter context + stylesheet.bindings.push(Bindings.WITH_PARAM); + // set the parameters + for (Iterator i = values.iterator(); i.hasNext(); ) { - System.err.println("with-param: " + name + " = " + value); + Object[] pair = (Object[]) i.next(); + QName name = (QName) pair[0]; + Object value = pair[1]; + stylesheet.bindings.set(name, value, Bindings.WITH_PARAM); + if (stylesheet.debug) + System.err.println("with-param: " + name + " = " + value); } } - } - TemplateNode t = stylesheet.getTemplate(mode, name); - if (t != null) - { t.apply(stylesheet, mode, context, pos, len, parent, nextSibling); - } - if (withParams != null) - { - // pop the variable context - stylesheet.bindings.pop(Bindings.WITH_PARAM); + if (withParams != null) + { + // pop the variable context + stylesheet.bindings.pop(Bindings.WITH_PARAM); + } } // call-template doesn't have processable children if (next != null) - { next.apply(stylesheet, mode, context, pos, len, parent, nextSibling); - } } public boolean references(QName var) @@ -144,9 +138,7 @@ final class CallTemplateNode for (Iterator i = withParams.iterator(); i.hasNext(); ) { if (((WithParam) i.next()).references(var)) - { - return true; - } + return true; } } return super.references(var); @@ -154,7 +146,7 @@ final class CallTemplateNode public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("call-template"); buf.append('['); buf.append("name="); buf.append(name); diff --git a/gnu/xml/transform/ChooseNode.java b/gnu/xml/transform/ChooseNode.java index fb1f2c45e..cf07fa54b 100644 --- a/gnu/xml/transform/ChooseNode.java +++ b/gnu/xml/transform/ChooseNode.java @@ -1,5 +1,5 @@ /* ChooseNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -54,13 +54,9 @@ final class ChooseNode { TemplateNode ret = new ChooseNode(); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } @@ -70,22 +66,18 @@ final class ChooseNode throws TransformerException { if (children != null) - { - children.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("choose"); buf.append('['); buf.append(']'); return buf.toString(); diff --git a/gnu/xml/transform/CommentNode.java b/gnu/xml/transform/CommentNode.java index 1428a46fc..8131fb286 100644 --- a/gnu/xml/transform/CommentNode.java +++ b/gnu/xml/transform/CommentNode.java @@ -1,5 +1,5 @@ /* CommentNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -58,13 +58,9 @@ final class CommentNode { TemplateNode ret = new CommentNode(); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } @@ -90,27 +86,18 @@ final class CommentNode Comment comment = doc.createComment(value); // Insert into result tree if (nextSibling != null) - { - parent.insertBefore(comment, nextSibling); - } + parent.insertBefore(comment, nextSibling); else - { - parent.appendChild(comment); - } + parent.appendChild(comment); if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); - buf.append('['); - buf.append(']'); - return buf.toString(); + return "comment"; } } diff --git a/gnu/xml/transform/CopyNode.java b/gnu/xml/transform/CopyNode.java index 3e019445a..64cfa5191 100644 --- a/gnu/xml/transform/CopyNode.java +++ b/gnu/xml/transform/CopyNode.java @@ -1,5 +1,5 @@ /* CopyNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -65,13 +65,9 @@ final class CopyNode { TemplateNode ret = new CopyNode(uas); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } @@ -102,44 +98,32 @@ final class CopyNode { NamedNodeMap attrs = parent.getAttributes(); if (attrs != null) - { - attrs.setNamedItemNS(copy); - } + attrs.setNamedItemNS(copy); } } else { if (nextSibling != null) - { - parent.insertBefore(copy, nextSibling); - } + parent.insertBefore(copy, nextSibling); else - { - parent.appendChild(copy); - } + parent.appendChild(copy); } } if (uas != null) { StringTokenizer st = new StringTokenizer(uas, " "); while (st.hasMoreTokens()) - { - addAttributeSet(stylesheet, mode, context, pos, len, - copy, null, st.nextToken()); - } + addAttributeSet(stylesheet, mode, context, pos, len, + copy, null, st.nextToken()); } if (children != null) - { - children.apply(stylesheet, mode, - context, pos, len, - copy, null); - } + children.apply(stylesheet, mode, + context, pos, len, + copy, null); if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } void addAttributeSet(Stylesheet stylesheet, QName mode, @@ -151,32 +135,31 @@ final class CopyNode { AttributeSet as = (AttributeSet) i.next(); if (!as.name.equals(attributeSet)) - { - continue; - } + continue; if (as.uas != null) { StringTokenizer st = new StringTokenizer(as.uas, " "); while (st.hasMoreTokens()) - { - addAttributeSet(stylesheet, mode, context, pos, len, - parent, nextSibling, st.nextToken()); - } + addAttributeSet(stylesheet, mode, context, pos, len, + parent, nextSibling, st.nextToken()); } if (as.children != null) - { - as.children.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + as.children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } } public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); - buf.append('['); - buf.append(']'); + StringBuffer buf = new StringBuffer("copy"); + if (uas != null) + { + buf.append('['); + buf.append("uas="); + buf.append(uas); + buf.append(']'); + } return buf.toString(); } diff --git a/gnu/xml/transform/CopyOfNode.java b/gnu/xml/transform/CopyOfNode.java index a43e3ba84..ed4358c90 100644 --- a/gnu/xml/transform/CopyOfNode.java +++ b/gnu/xml/transform/CopyOfNode.java @@ -1,5 +1,5 @@ /* CopyOfNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -70,13 +70,9 @@ final class CopyOfNode { TemplateNode ret = new CopyOfNode(select.clone(stylesheet)); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } @@ -102,9 +98,7 @@ final class CopyOfNode // Use document element src = ((Document) src).getDocumentElement(); if (src == null) - { - continue; - } + continue; nodeType = Node.ELEMENT_NODE; } else if (nodeType == Node.ATTRIBUTE_NODE) @@ -128,20 +122,14 @@ final class CopyOfNode { NamedNodeMap attrs = parent.getAttributes(); if (attrs != null) - { - attrs.setNamedItemNS(node); - } + attrs.setNamedItemNS(node); } else { if (nextSibling != null) - { - parent.insertBefore(node, nextSibling); - } + parent.insertBefore(node, nextSibling); else - { - parent.appendChild(node); - } + parent.appendChild(node); } } } @@ -152,36 +140,28 @@ final class CopyOfNode { Text textNode = doc.createTextNode(value); if (nextSibling != null) - { - parent.insertBefore(textNode, nextSibling); - } + parent.insertBefore(textNode, nextSibling); else - { - parent.appendChild(textNode); - } + parent.appendChild(textNode); } } // copy-of doesn't process children if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } public boolean references(QName var) { if (select != null && select.references(var)) - { - return true; - } + return true; return super.references(var); } public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("copy-of"); buf.append('['); buf.append("select="); buf.append(select); diff --git a/gnu/xml/transform/DocumentFunction.java b/gnu/xml/transform/DocumentFunction.java index d8f6090be..29f3d4a45 100644 --- a/gnu/xml/transform/DocumentFunction.java +++ b/gnu/xml/transform/DocumentFunction.java @@ -126,9 +126,7 @@ final class DocumentFunction Object arg1 = values.get(0); Object arg2 = values.get(1); if (!(arg2 instanceof Collection)) - { - throw new RuntimeException("second argument is not a node-set"); - } + throw new RuntimeException("second argument is not a node-set"); Collection arg2ns = (Collection) arg2; String base2 = arg2ns.isEmpty() ? null : ((Node) arg2ns.iterator().next()).getBaseURI(); @@ -166,9 +164,7 @@ final class DocumentFunction Collection document(String uri, String base) { if ("".equals(uri) || uri == null) - { - uri = this.base.getBaseURI(); - } + uri = this.base.getBaseURI(); // Get fragment Expr fragment = null; @@ -197,10 +193,10 @@ final class DocumentFunction source = resolver.resolveDOM(null, base, uri); } Node node = source.getNode(); + // Strip whitespace + TransformerImpl.strip(stylesheet, node); if (fragment == null) - { - return Collections.singleton(node); - } + return Collections.singleton(node); else { Object ret = fragment.evaluate(node, 1, 1); @@ -216,9 +212,7 @@ final class DocumentFunction { String msg = "can't open " + uri; if (base != null) - { - msg += " with base " + base; - } + msg += " with base " + base; throw new RuntimeException(msg); } } @@ -227,16 +221,12 @@ final class DocumentFunction { Stylesheet s = stylesheet; if (context instanceof Stylesheet) - { - s = (Stylesheet) context; - } + s = (Stylesheet) context; DocumentFunction f = new DocumentFunction(s, base); int len = args.size(); List args2 = new ArrayList(len); for (int i = 0; i < len; i++) - { - args2.add(((Expr) args.get(i)).clone(context)); - } + args2.add(((Expr) args.get(i)).clone(context)); f.setArguments(args2); return f; } @@ -246,9 +236,7 @@ final class DocumentFunction for (Iterator i = args.iterator(); i.hasNext(); ) { if (((Expr) i.next()).references(var)) - { - return true; - } + return true; } return false; } diff --git a/gnu/xml/transform/ElementNode.java b/gnu/xml/transform/ElementNode.java index 092c56a4b..b6a5c365b 100644 --- a/gnu/xml/transform/ElementNode.java +++ b/gnu/xml/transform/ElementNode.java @@ -1,5 +1,5 @@ /* ElementNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -238,7 +238,7 @@ final class ElementNode public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("element"); buf.append('['); buf.append("name="); if (namespace != null) diff --git a/gnu/xml/transform/ForEachNode.java b/gnu/xml/transform/ForEachNode.java index 8f9220f67..c8f51a6fe 100644 --- a/gnu/xml/transform/ForEachNode.java +++ b/gnu/xml/transform/ForEachNode.java @@ -1,5 +1,5 @@ /* ForEachNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -70,19 +70,13 @@ final class ForEachNode int len = sortKeys.size(); List sortKeys2 = new ArrayList(len); for (int i = 0; i < len; i++) - { - sortKeys2.add(((Key) sortKeys.get(i)).clone(stylesheet)); - } + sortKeys2.add(((Key) sortKeys.get(i)).clone(stylesheet)); TemplateNode ret = new ForEachNode(select.clone(stylesheet), sortKeys2); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } @@ -113,9 +107,7 @@ final class ForEachNode Collections.sort(list, new XSLComparator(sortKeys)); } else - { - Collections.sort(list, documentOrderComparator); - } + Collections.sort(list, documentOrderComparator); // Perform children for each node int l = list.size(); int p = 1; @@ -132,27 +124,21 @@ final class ForEachNode stylesheet.currentTemplate = saved; } if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } public boolean references(QName var) { if (select != null && select.references(var)) - { - return true; - } + return true; if (sortKeys != null) { for (Iterator i = sortKeys.iterator(); i.hasNext(); ) { if (((SortKey) i.next()).references(var)) - { - return true; - } + return true; } } return super.references(var); @@ -160,7 +146,7 @@ final class ForEachNode public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("for-each"); buf.append('['); buf.append("select="); buf.append(select); diff --git a/gnu/xml/transform/IfNode.java b/gnu/xml/transform/IfNode.java index 17e2486fe..2a00d64ca 100644 --- a/gnu/xml/transform/IfNode.java +++ b/gnu/xml/transform/IfNode.java @@ -1,5 +1,5 @@ /* IfNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -62,19 +62,15 @@ final class IfNode { TemplateNode ret = new IfNode(test.clone(stylesheet)); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } void doApply(Stylesheet stylesheet, QName mode, - Node context, int pos, int len, - Node parent, Node nextSibling) + Node context, int pos, int len, + Node parent, Node nextSibling) throws TransformerException { Object ret = test.evaluate(context, pos, len); @@ -84,32 +80,26 @@ final class IfNode if (success) { if (children != null) - { - children.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } public boolean references(QName var) { if (test != null && test.references(var)) - { - return true; - } + return true; return super.references(var); } public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("if"); buf.append('['); buf.append("test="); buf.append(test); diff --git a/gnu/xml/transform/LiteralNode.java b/gnu/xml/transform/LiteralNode.java index 453c22c5e..d4e283a65 100644 --- a/gnu/xml/transform/LiteralNode.java +++ b/gnu/xml/transform/LiteralNode.java @@ -196,12 +196,7 @@ final class LiteralNode public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); - buf.append('['); - buf.append("source="); - buf.append(source); - buf.append(']'); - return buf.toString(); + return source.toString(); } } diff --git a/gnu/xml/transform/MessageNode.java b/gnu/xml/transform/MessageNode.java index e8e07c6da..890d76f6b 100644 --- a/gnu/xml/transform/MessageNode.java +++ b/gnu/xml/transform/MessageNode.java @@ -92,5 +92,17 @@ final class MessageNode if (next != null && !terminate) next.apply(stylesheet, mode, context, pos, len, parent, nextSibling); } + + public String toString() + { + StringBuffer buf = new StringBuffer("message"); + if (terminate) + { + buf.append('['); + buf.append("terminate"); + buf.append(']'); + } + return buf.toString(); + } } diff --git a/gnu/xml/transform/OtherwiseNode.java b/gnu/xml/transform/OtherwiseNode.java index 570310f6b..9d8168ce4 100644 --- a/gnu/xml/transform/OtherwiseNode.java +++ b/gnu/xml/transform/OtherwiseNode.java @@ -1,5 +1,5 @@ /* OtherwiseNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -54,13 +54,9 @@ final class OtherwiseNode { TemplateNode ret = new OtherwiseNode(); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } @@ -70,25 +66,18 @@ final class OtherwiseNode throws TransformerException { if (children != null) - { - children.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); - buf.append('['); - buf.append(']'); - return buf.toString(); + return "otherwise"; } } diff --git a/gnu/xml/transform/ParameterNode.java b/gnu/xml/transform/ParameterNode.java index ef09ea5f9..8cd2677cf 100644 --- a/gnu/xml/transform/ParameterNode.java +++ b/gnu/xml/transform/ParameterNode.java @@ -1,5 +1,5 @@ /* ParameterNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -73,13 +73,9 @@ final class ParameterNode select.clone(stylesheet), type); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } @@ -96,18 +92,14 @@ final class ParameterNode { stylesheet.bindings.set(name, value, type); if (stylesheet.debug) - { - System.err.println(this + ": set to " + value); - } + System.err.println(this + ": set to " + value); } // variable and param don't process children as such // all subsequent instructions are processed with that variable context if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); // pop the variable context stylesheet.bindings.pop(type); } @@ -117,9 +109,7 @@ final class ParameterNode throws TransformerException { if (select != null) - { - return select.evaluate(context, pos, len); - } + return select.evaluate(context, pos, len); else if (children != null) { Document doc = (context instanceof Document) ? (Document) context : @@ -129,17 +119,13 @@ final class ParameterNode return Collections.singleton(fragment); } else - { - return null; - } + return null; } public boolean references(QName var) { if (select != null && select.references(var)) - { - return true; - } + return true; return super.references(var); } @@ -151,33 +137,18 @@ final class ParameterNode boolean r1 = references(pn.name); boolean r2 = pn.references(name); if (r1 && r2) - { - throw new IllegalArgumentException("circular definitions"); - } + throw new IllegalArgumentException("circular definitions"); if (r1) - { - return 1; - } + return 1; if (r2) - { - return -1; - } + return -1; } return 0; } public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); - buf.append('['); - buf.append("name="); - buf.append(name); - if (select != null) - { - buf.append(",select="); - buf.append(select); - } - buf.append(",type="); + StringBuffer buf = new StringBuffer(); switch (type) { case Bindings.VARIABLE: @@ -190,6 +161,14 @@ final class ParameterNode buf.append("with-param"); break; } + buf.append('['); + buf.append("name="); + buf.append(name); + if (select != null) + { + buf.append(",select="); + buf.append(select); + } buf.append(']'); return buf.toString(); } diff --git a/gnu/xml/transform/ProcessingInstructionNode.java b/gnu/xml/transform/ProcessingInstructionNode.java index d75f69366..bf61fc038 100644 --- a/gnu/xml/transform/ProcessingInstructionNode.java +++ b/gnu/xml/transform/ProcessingInstructionNode.java @@ -1,5 +1,5 @@ /* ProcessingInstructionNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -66,19 +66,15 @@ final class ProcessingInstructionNode { TemplateNode ret = new ProcessingInstructionNode(name); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } void doApply(Stylesheet stylesheet, QName mode, - Node context, int pos, int len, - Node parent, Node nextSibling) + Node context, int pos, int len, + Node parent, Node nextSibling) throws TransformerException { String data = null; @@ -98,24 +94,18 @@ final class ProcessingInstructionNode ProcessingInstruction pi = doc.createProcessingInstruction(name, data); // Insert into result tree if (nextSibling != null) - { - parent.insertBefore(pi, nextSibling); - } + parent.insertBefore(pi, nextSibling); else - { - parent.appendChild(pi); - } + parent.appendChild(pi); if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("processing-instruction"); buf.append('['); buf.append("name="); buf.append(name); diff --git a/gnu/xml/transform/Stylesheet.java b/gnu/xml/transform/Stylesheet.java index 51accaa3b..73b229691 100644 --- a/gnu/xml/transform/Stylesheet.java +++ b/gnu/xml/transform/Stylesheet.java @@ -408,7 +408,7 @@ class Stylesheet { if (debug) System.err.println("getTemplate: mode="+mode+" context="+context); - Set candidates = new TreeSet(); + Template selected = null; for (Iterator j = templates.iterator(); j.hasNext(); ) { Template t = (Template) j.next(); @@ -426,10 +426,21 @@ class Stylesheet } //System.err.println("\t"+context+" "+t+"="+isMatch); if (isMatch) - candidates.add(t); + { + // Conflict resolution + // @see http://www.w3.org/TR/xslt#conflict + if (selected == null) + selected = t; + else + { + if (t.precedence < selected.precedence || + t.priority < selected.priority) + continue; + selected = t; + } + } } - //System.err.println("\tcandidates="+candidates); - if (candidates.isEmpty()) + if (selected == null) { // Apply built-in template // Current template is unchanged @@ -451,32 +462,39 @@ class Stylesheet return null; } } - else - { - Template t = (Template) candidates.iterator().next(); - // Set current template - currentTemplate = t; - if (debug) - System.err.println("\ttemplate="+t+" context="+context); - return t.node; - } + // Set current template + currentTemplate = selected; + if (debug) + System.err.println("\ttemplate="+currentTemplate+" context="+context); + return currentTemplate.node; } TemplateNode getTemplate(QName mode, QName name) throws TransformerException { - Set candidates = new TreeSet(); + Template selected = null; for (Iterator j = templates.iterator(); j.hasNext(); ) { Template t = (Template) j.next(); boolean isMatch = t.matches(name); if (isMatch) - candidates.add(t); + { + // Conflict resolution + // @see http://www.w3.org/TR/xslt#conflict + if (selected == null) + selected = t; + else + { + if (t.precedence < selected.precedence || + t.priority < selected.priority) + continue; + selected = t; + } + } } - if (candidates.isEmpty()) + if (selected == null) return null; - Template t = (Template) candidates.iterator().next(); - return t.node; + return selected.node; } /** @@ -504,11 +522,9 @@ class Stylesheet String p = getAttribute(attrs, "priority"); String mm = getAttribute(attrs, "mode"); QName mode = (mm == null) ? null : getQName(mm); - double priority = (p == null) ? Template.DEFAULT_PRIORITY : - Double.parseDouble(p); Node children = node.getFirstChild(); return new Template(this, name, match, parse(children), - precedence, priority, mode); + precedence, p, mode); } /** @@ -799,7 +815,7 @@ class Stylesheet templates.add(new Template(this, null, new Root(), parse(rootClone), precedence, - Template.DEFAULT_PRIORITY, + null, null)); } else diff --git a/gnu/xml/transform/Template.java b/gnu/xml/transform/Template.java index e3c172fb5..1414dac9e 100644 --- a/gnu/xml/transform/Template.java +++ b/gnu/xml/transform/Template.java @@ -1,5 +1,5 @@ /* Template.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -66,51 +66,77 @@ class Template final double priority; final int precedence; final QName mode; + final boolean isAnyNode; // is the match simply "node()"? Template(Stylesheet stylesheet, QName name, Pattern match, TemplateNode node, - int precedence, double priority, QName mode) + int precedence, String priorityAttr, QName mode) { this.stylesheet = stylesheet; this.name = name; this.match = match; this.node = node; - // adjust priority if necessary - // see XSLT section 5.5 - Test test = getNodeTest(match); - if (test != null) + this.precedence = precedence; + this.mode = mode; + + double p = DEFAULT_PRIORITY; + boolean a = false; + if (priorityAttr != null) + p = Double.parseDouble(priorityAttr); + else { - if (test instanceof NameTest) + // adjust priority if necessary + // see XSLT section 5.5 + if (match instanceof Selector) { - NameTest nameTest = (NameTest) test; - if (nameTest.matchesAny() || - nameTest.matchesAnyLocalName()) - { - priority = -0.25d; - } - else + Selector selector = (Selector) match; + Test[] tests = selector.getTests(); + if (tests.length > 0) { - priority = 0.0d; - } - } - else - { - NodeTypeTest nodeTypeTest = (NodeTypeTest) test; - if (nodeTypeTest.getNodeType() == - Node.PROCESSING_INSTRUCTION_NODE && - nodeTypeTest.getData() != null) - { - priority = 0.0d; - } - else - { - priority = -0.5d; + Test test = tests[0]; + if (test instanceof NameTest) + { + NameTest nameTest = (NameTest) test; + if (nameTest.matchesAny()) + p = -0.25d; + else if (nameTest.matchesAnyLocalName()) + p = -0.20d; + else + p = 0.0d; + } + else + { + NodeTypeTest nodeTypeTest = (NodeTypeTest) test; + if (nodeTypeTest.getNodeType() == + Node.PROCESSING_INSTRUCTION_NODE && + nodeTypeTest.getData() != null) + p = 0.0d; + else + p = -0.5d; + a = (nodeTypeTest.getNodeType() == 0); + } + // Add a small difference for predicates + if (tests.length > 1) + p += ((double) tests.length - 1) * 0.001; } } } + this.priority = p; + this.isAnyNode = a; + } + + private Template(Stylesheet stylesheet, + QName name, Pattern match, TemplateNode node, + int precedence, double priority, QName mode, boolean isAnyNode) + { + this.stylesheet = stylesheet; + this.name = name; + this.match = match; + this.node = node; this.precedence = precedence; this.priority = priority; this.mode = mode; + this.isAnyNode = isAnyNode; } Template clone(Stylesheet stylesheet) @@ -124,7 +150,8 @@ class Template (node == null) ? null : node.clone(stylesheet), precedence, priority, - mode); + mode, + isAnyNode); } public int compareTo(Object other) @@ -134,29 +161,16 @@ class Template Template t = (Template) other; int d = t.precedence - precedence; if (d != 0) - { - return d; - } + return d; double d2 = t.priority - priority; if (d2 != 0.0d) - { - return (int) Math.round(d2 * 1000.0d); - } + return (int) Math.round(d2 * 1000.0d); } return 0; } Test getNodeTest(Expr expr) { - if (expr instanceof Selector) - { - Selector selector = (Selector) expr; - Test[] tests = selector.getTests(); - if (tests.length > 0) - { - return tests[0]; - } - } return null; } @@ -164,13 +178,11 @@ class Template { if ((mode == null && this.mode != null) || (mode != null && !mode.equals(this.mode))) - { - return false; - } + return false; if (match == null) - { - return false; - } + return false; + if (isAnyNode && node.getNodeType() == Node.DOCUMENT_NODE) + return false; // don't match document node return match.matches(node); } @@ -186,9 +198,7 @@ class Template ctx = ctx.parent) { if (ctx == stylesheet) - { - return true; - } + return true; } return false; } @@ -206,13 +216,12 @@ class Template Node parent, Node nextSibling) throws TransformerException { - System.err.println("...applying " + toString() + " to " + context); + if (stylesheet.debug) + System.err.println("...applying " + toString() + " to " + context); if (node != null) - { - node.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + node.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } public String toString() @@ -244,9 +253,7 @@ class Template { out.println(toString()); if (node != null) - { - node.list(1, out, true); - } + node.list(1, out, true); } } diff --git a/gnu/xml/transform/TemplateNode.java b/gnu/xml/transform/TemplateNode.java index 36b25cf52..6ff727c07 100644 --- a/gnu/xml/transform/TemplateNode.java +++ b/gnu/xml/transform/TemplateNode.java @@ -64,9 +64,7 @@ abstract class TemplateNode throws TransformerException { if (stylesheet.terminated) - { - return; - } + return; if (Thread.currentThread().isInterrupted()) { // Try to head off any infinite loops at the pass @@ -91,13 +89,9 @@ abstract class TemplateNode public boolean references(QName var) { if (children != null && children.references(var)) - { - return true; - } + return true; if (next != null && next.references(var)) - { - return true; - } + return true; return false; } @@ -107,18 +101,30 @@ abstract class TemplateNode void list(int depth, PrintStream out, boolean listNext) { for (int i = 0; i < depth; i++) - { - out.print(" "); - } + out.print(" "); out.println(toString()); if (children != null) - { - children.list(depth + 1, out, true); - } + children.list(depth + 1, out, true); if (listNext && next != null) + next.list(depth, out, listNext); + } + + /** + * Indicates whether the template for which this template node is the + * first node specifies the given parameter. + */ + boolean hasParam(QName name) + { + for (TemplateNode ctx = this; ctx != null; ctx = ctx.next) { - next.list(depth, out, listNext); + if (ctx instanceof ParameterNode) + { + ParameterNode param = (ParameterNode) ctx; + if (param.type == Bindings.PARAM && param.name.equals(name)) + return true; + } } + return false; } } diff --git a/gnu/xml/transform/TextNode.java b/gnu/xml/transform/TextNode.java index 1b581e5ac..39423b270 100644 --- a/gnu/xml/transform/TextNode.java +++ b/gnu/xml/transform/TextNode.java @@ -1,5 +1,5 @@ /* TextNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -65,19 +65,15 @@ final class TextNode { TemplateNode ret = new TextNode(disableOutputEscaping); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } void doApply(Stylesheet stylesheet, QName mode, - Node context, int pos, int len, - Node parent, Node nextSibling) + Node context, int pos, int len, + Node parent, Node nextSibling) throws TransformerException { String value = ""; @@ -96,24 +92,28 @@ final class TextNode } Text text = doc.createTextNode(value); if (disableOutputEscaping) - { - text.setUserData("disable-output-escaping", "yes", stylesheet); - } + text.setUserData("disable-output-escaping", "yes", stylesheet); // Insert into result tree if (nextSibling != null) - { - parent.insertBefore(text, nextSibling); - } + parent.insertBefore(text, nextSibling); else - { - parent.appendChild(text); - } + parent.appendChild(text); if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + StringBuffer buf = new StringBuffer("text"); + if (disableOutputEscaping) { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); + buf.append('['); + buf.append("disable-output-escaping"); + buf.append(']'); } + return buf.toString(); } } diff --git a/gnu/xml/transform/TransformerImpl.java b/gnu/xml/transform/TransformerImpl.java index b7ff66884..2c57e970b 100644 --- a/gnu/xml/transform/TransformerImpl.java +++ b/gnu/xml/transform/TransformerImpl.java @@ -162,7 +162,7 @@ class TransformerImpl } // Make a copy of the source node, and strip it context = context.cloneNode(true); - strip(context); + strip(stylesheet, context); // XSLT transformation try { @@ -321,7 +321,7 @@ class TransformerImpl if (indent) { parent.normalize(); - strip(parent); + strip(stylesheet, parent); Document resultDoc = (parent instanceof Document) ? (Document) parent : parent.getOwnerDocument(); @@ -393,7 +393,7 @@ class TransformerImpl /** * Strip whitespace from the source tree. */ - boolean strip(Node node) + static boolean strip(Stylesheet stylesheet, Node node) throws TransformerConfigurationException { short nt = node.getNodeType(); @@ -444,7 +444,7 @@ class TransformerImpl Node child = node.getFirstChild(); while (child != null) { - boolean remove = strip(child); + boolean remove = strip(stylesheet, child); Node next = child.getNextSibling(); if (remove) node.removeChild(child); @@ -691,7 +691,7 @@ class TransformerImpl for (Iterator i = children.iterator(); i.hasNext(); ) { ctx = (Node) i.next(); - reindent(doc, ctx, offset + 1); + reindent(doc, ctx, offset); } } else @@ -709,9 +709,9 @@ class TransformerImpl } buf = new StringBuffer(); buf.append('\n'); - ws = buf.toString(); for (int i = 0; i < offset; i++) buf.append(INDENT_WHITESPACE); + ws = buf.toString(); node.appendChild(doc.createTextNode(ws)); } } diff --git a/gnu/xml/transform/ValueOfNode.java b/gnu/xml/transform/ValueOfNode.java index 24c229ea3..68f31e05a 100644 --- a/gnu/xml/transform/ValueOfNode.java +++ b/gnu/xml/transform/ValueOfNode.java @@ -126,7 +126,7 @@ final class ValueOfNode public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("value-of"); buf.append('['); buf.append("select="); buf.append(select); diff --git a/gnu/xml/transform/WhenNode.java b/gnu/xml/transform/WhenNode.java index 231f2693b..fe3f403ab 100644 --- a/gnu/xml/transform/WhenNode.java +++ b/gnu/xml/transform/WhenNode.java @@ -1,5 +1,5 @@ /* WhenNode.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -62,19 +62,15 @@ final class WhenNode { TemplateNode ret = new WhenNode(test.clone(stylesheet)); if (children != null) - { - ret.children = children.clone(stylesheet); - } + ret.children = children.clone(stylesheet); if (next != null) - { - ret.next = next.clone(stylesheet); - } + ret.next = next.clone(stylesheet); return ret; } void doApply(Stylesheet stylesheet, QName mode, - Node context, int pos, int len, - Node parent, Node nextSibling) + Node context, int pos, int len, + Node parent, Node nextSibling) throws TransformerException { Object ret = test.evaluate(context, pos, len); @@ -84,35 +80,29 @@ final class WhenNode if (success) { if (children != null) - { - children.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } else { if (next != null) - { - next.apply(stylesheet, mode, - context, pos, len, - parent, nextSibling); - } + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); } } public boolean references(QName var) { if (test != null && test.references(var)) - { - return true; - } + return true; return super.references(var); } public String toString() { - StringBuffer buf = new StringBuffer(getClass().getName()); + StringBuffer buf = new StringBuffer("when"); buf.append('['); buf.append("test="); buf.append(test); diff --git a/gnu/xml/util/XHTMLWriter.java b/gnu/xml/util/XHTMLWriter.java index 272c66cd3..02a0afca8 100644 --- a/gnu/xml/util/XHTMLWriter.java +++ b/gnu/xml/util/XHTMLWriter.java @@ -55,6 +55,8 @@ import java.io.Writer; * data loss. * * @author David Brownell + * + * @deprecated Please use the javax.xml.stream APIs instead */ public class XHTMLWriter extends XMLWriter { diff --git a/gnu/xml/util/XMLWriter.java b/gnu/xml/util/XMLWriter.java index fd36b7153..24b38923f 100644 --- a/gnu/xml/util/XMLWriter.java +++ b/gnu/xml/util/XMLWriter.java @@ -102,6 +102,8 @@ import org.xml.sax.helpers.*; * @see gnu.xml.pipeline.TextConsumer * * @author David Brownell + * + * @deprecated Please use the javax.xml.stream APIs instead */ public class XMLWriter implements ContentHandler, LexicalHandler, DTDHandler, DeclHandler diff --git a/gnu/xml/validation/datatype/Annotation.java b/gnu/xml/validation/datatype/Annotation.java new file mode 100644 index 000000000..cba6954b6 --- /dev/null +++ b/gnu/xml/validation/datatype/Annotation.java @@ -0,0 +1,61 @@ +/* Annotation.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +/** + * A schema component annotation. + * + * @author Chris Burdess + */ +public class Annotation +{ + + public final String documentation; + + public Annotation(String documentation) + { + this.documentation = documentation; + } + + public String toString() + { + return documentation; + } + +} + diff --git a/gnu/xml/validation/datatype/AnySimpleType.java b/gnu/xml/validation/datatype/AnySimpleType.java new file mode 100644 index 000000000..63441c70a --- /dev/null +++ b/gnu/xml/validation/datatype/AnySimpleType.java @@ -0,0 +1,59 @@ +/* AnySimpleType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Set; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; + +final class AnySimpleType + extends SimpleType +{ + + AnySimpleType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "anySimpleType"), + ANY, /* variety */ + (Set) null, /* facets */ + 0, /* fundametalFacets */ + (SimpleType) Type.ANY_TYPE, /* baseType */ + null); + } + +} + diff --git a/gnu/xml/validation/datatype/AnyType.java b/gnu/xml/validation/datatype/AnyType.java new file mode 100644 index 000000000..f26a0756d --- /dev/null +++ b/gnu/xml/validation/datatype/AnyType.java @@ -0,0 +1,58 @@ +/* AnyType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; + +final class AnyType + extends SimpleType +{ + + AnyType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "anyType"), + ANY, /* variety */ + null, /* facets */ + 0, /* fundamentalFacets */ + null, /* baseType */ + null); + } + +} + diff --git a/gnu/xml/validation/datatype/AnyURIType.java b/gnu/xml/validation/datatype/AnyURIType.java new file mode 100644 index 000000000..56c0a0658 --- /dev/null +++ b/gnu/xml/validation/datatype/AnyURIType.java @@ -0,0 +1,94 @@ +/* AnyURIType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.net.URI; +import java.net.URISyntaxException; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema anyURI type. + * + * @author Chris Burdess + */ +final class AnyURIType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + AnyURIType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "anyURI"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + try + { + new URI(value); + } + catch (URISyntaxException e) + { + DatatypeException e2 = new DatatypeException(e.getIndex(), + e.getReason()); + e2.initCause(e); + throw e2; + } + } + +} + diff --git a/gnu/xml/validation/datatype/AtomicSimpleType.java b/gnu/xml/validation/datatype/AtomicSimpleType.java new file mode 100644 index 000000000..d685e5cf0 --- /dev/null +++ b/gnu/xml/validation/datatype/AtomicSimpleType.java @@ -0,0 +1,78 @@ +/* AtomicSimpleType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Set; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * An XML Schema atomic simple type. + * + * @author Chris Burdess + */ +public class AtomicSimpleType + extends SimpleType +{ + + public AtomicSimpleType(QName name, + Set facets, + int fundamentalFacets, + SimpleType baseType, + Annotation annotation) + { + super(name, ATOMIC, facets, fundamentalFacets, baseType, annotation); + } + + // Only for use by built-in types + AtomicSimpleType(QName name, SimpleType baseType) + { + super(name, ATOMIC, null, 0, baseType, null); + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + if (baseType != null) + baseType.checkValid(value, context); + } + +} + diff --git a/gnu/xml/validation/datatype/Base64BinaryType.java b/gnu/xml/validation/datatype/Base64BinaryType.java new file mode 100644 index 000000000..5a72a280d --- /dev/null +++ b/gnu/xml/validation/datatype/Base64BinaryType.java @@ -0,0 +1,131 @@ +/* Base64BinaryType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Collections; +import java.util.Set; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema base64Binary type. + * + * @author Chris Burdess + */ +final class Base64BinaryType + extends AtomicSimpleType +{ + + static final String B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "abcdefghijklmnopqrstuvwxyz0123456789+/"; + static final String B16 = "AEIMQUYcgkosw048"; + static final String B04 = "AQgw"; + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + Base64BinaryType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "base64Binary"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + // TODO value = collapseWhitespace(value); + int len = value.length(); + try + { + for (int i = len - 1; i >= 0; ) + { + char c4 = value.charAt(i--); + if (c4 == ' ') + c4 = value.charAt(i--); + char c3 = value.charAt(i--); + if (c3 == ' ') + c3 = value.charAt(i--); + char c2 = value.charAt(i--); + if (c2 == ' ') + c2 = value.charAt(i--); + char c1 = value.charAt(i--); + if (c1 == ' ') + c1 = value.charAt(i--); + + if (c4 == '=') + { + if (c3 == '=') + { + if (B04.indexOf(c2) != -1 && + B64.indexOf(c1) != -1) + continue; + } + else if (B16.indexOf(c3) != -1) + { + if (B64.indexOf(c2) != -1 && + B64.indexOf(c1) != -1) + continue; + } + } + else if (B64.indexOf(c4) != -1) + continue; + throw new DatatypeException(i, "illegal BASE64"); + } + } + catch (IndexOutOfBoundsException e) + { + throw new DatatypeException("illegal BASE64"); + } + } + +} + diff --git a/gnu/xml/validation/datatype/BooleanType.java b/gnu/xml/validation/datatype/BooleanType.java new file mode 100644 index 000000000..5a2d9ecfa --- /dev/null +++ b/gnu/xml/validation/datatype/BooleanType.java @@ -0,0 +1,91 @@ +/* BooleanType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema boolean type. + * + * @author Chris Burdess + */ +final class BooleanType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.WHITESPACE + }; + + static final Set VALUE_SPACE = + new TreeSet(Arrays.asList(new String[] {"true", "false", "1", "0"})); + + BooleanType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "boolean"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + if (!VALUE_SPACE.contains(value)) + throw new DatatypeException("invalid boolean value"); + } + + public Object createValue(String literal, ValidationContext context) { + return ("1".equals(literal) || "true".equals(literal)) ? Boolean.TRUE : + Boolean.FALSE; + } + +} + diff --git a/gnu/xml/validation/datatype/ByteType.java b/gnu/xml/validation/datatype/ByteType.java new file mode 100644 index 000000000..539dba29a --- /dev/null +++ b/gnu/xml/validation/datatype/ByteType.java @@ -0,0 +1,133 @@ +/* ByteType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema byte type. + * + * @author Chris Burdess + */ +final class ByteType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + static final String MAX_VALUE = "127"; + static final String MIN_VALUE = "128"; + static final int LENGTH = MAX_VALUE.length(); + + ByteType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "byte"), + TypeLibrary.SHORT); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValue(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid byte value"); + int i = 0, off = 0; + boolean compare = false; + String compareTo = MAX_VALUE; + char c = value.charAt(0); + if (c == '+') + i++; + else if (c == '-') + { + compareTo = MIN_VALUE; + i++; + } + if (len - i > LENGTH) + throw new DatatypeException(0, "invalid byte value"); + else if (len - i == LENGTH) + compare = true; + for (; i < len; i++) + { + c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + { + if (compare) + { + char d = compareTo.charAt(off); + if (Character.digit(c, 10) > Character.digit(d, 10)) + throw new DatatypeException(i, "invalid byte value"); + } + off++; + continue; + } + throw new DatatypeException(i, "invalid byte value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new Byte(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/DateTimeType.java b/gnu/xml/validation/datatype/DateTimeType.java new file mode 100644 index 000000000..749ba8106 --- /dev/null +++ b/gnu/xml/validation/datatype/DateTimeType.java @@ -0,0 +1,335 @@ +/* DateTimeType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.TimeZone; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema dateTime type. + * + * @author Chris Burdess + */ +final class DateTimeType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + DateTimeType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "dateTime"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValue(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + int state = 0; + int start = 0; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '-' && i == 0) + { + start++; + continue; + } + if (c >= 0x30 && c <= 0x39) + continue; + switch (state) + { + case 0: // year + if (c == '-') + { + String year = value.substring(start, i); + if ("0000".equals(year) || year.length() < 4) + throw new DatatypeException(i, "invalid dateTime value"); + state = 1; + start = i + 1; + continue; + } + break; + case 1: // month + if (c == '-') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid dateTime value"); + state = 2; + start = i + 1; + continue; + } + break; + case 2: // day + if (c == 'T') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid dateTime value"); + state = 3; + start = i + 1; + continue; + } + break; + case 3: // hour + if (c == ':') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid dateTime value"); + state = 4; + start = i + 1; + continue; + } + break; + case 4: // minute + if (c == ':') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid dateTime value"); + state = 5; + start = i + 1; + continue; + } + break; + case 5: // second + if (c == '.') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid dateTime value"); + state = 6; + start = i + 1; + continue; + } + else if (c == ' ') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid dateTime value"); + state = 7; + start = i + 1; + continue; + } + break; + case 6: // second fraction + if (c == ' ') + { + state = 7; + start = i + 1; + continue; + } + break; + case 7: // timezone 1 + if (start == i) + { + if (c == '+' || c == '-') + continue; + else if (c == 'Z') + { + state = 9; + start = i + 1; + continue; + } + } + if (c == ':') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid dateTime value"); + state = 8; + start = i + 1; + continue; + } + break; + } + throw new DatatypeException(i, "invalid dateTime value"); + } + switch (state) + { + case 5: // second + if (len - start != 2) + throw new DatatypeException(len, "invalid dateTime value"); + break; + case 6: // second fraction + break; + case 8: // timezone 2 + if (len - start != 2) + throw new DatatypeException(len, "invalid dateTime value"); + break; + case 9: // post Z + break; + default: + throw new DatatypeException(len, "invalid dateTime value"); + } + } + + public Object createValue(String value, ValidationContext context) { + int len = value.length(); + int state = 0; + int start = 0; + Calendar cal = new GregorianCalendar(); + try + { + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '-' && i == 0) + { + start++; + continue; + } + if (c >= 0x30 && c <= 0x39) + continue; + switch (state) + { + case 0: // year + if (c == '-') + { + cal.set(Calendar.YEAR, + Integer.parseInt(value.substring(0, i))); + state = 1; + start = i + 1; + continue; + } + break; + case 1: // month + if (c == '-') + { + cal.set(Calendar.MONTH, + Integer.parseInt(value.substring(start, i))); + state = 2; + start = i + 1; + continue; + } + break; + case 2: // day + if (c == 'T') + { + cal.set(Calendar.DATE, + Integer.parseInt(value.substring(start, i))); + state = 3; + start = i + 1; + continue; + } + break; + case 3: // hour + if (c == ':') + { + cal.set(Calendar.HOUR, + Integer.parseInt(value.substring(start, i))); + state = 4; + start = i + 1; + continue; + } + break; + case 4: // minute + if (c == ':') + { + cal.set(Calendar.MINUTE, + Integer.parseInt(value.substring(start, i))); + state = 5; + start = i + 1; + continue; + } + break; + case 5: // second + if (c == ' ') + { + float second = Float.parseFloat(value.substring(start, i)); + // TODO adjust non-integer values + cal.set(Calendar.SECOND, (int) second); + state = 7; + start = i + 1; + continue; + } + break; + } + } + // end of input + if (len - start > 0 && state == 7) + { + // Timezone + String timezone = value.substring(len - start); + int i = timezone.indexOf(':'); + if (i == -1) + { + if ("Z".equals(timezone)) + timezone = "UTC"; + TimeZone tz = TimeZone.getTimeZone(timezone); + if (tz == null) + return null; + cal.set(Calendar.ZONE_OFFSET, tz.getRawOffset()); + } + else + { + String tzh = timezone.substring(0, i); + String tzm = timezone.substring(i + 1); + int offset = Integer.parseInt(tzh) * 360000; + if (offset < 0) + offset -= Integer.parseInt(tzm) * 60000; + else + offset += Integer.parseInt(tzm) * 60000; + cal.set(Calendar.ZONE_OFFSET, offset); + } + } + return cal.getTime(); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/DateType.java b/gnu/xml/validation/datatype/DateType.java new file mode 100644 index 000000000..6a4e1d771 --- /dev/null +++ b/gnu/xml/validation/datatype/DateType.java @@ -0,0 +1,222 @@ +/* DateType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.TimeZone; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema date type. + * + * @author Chris Burdess + */ +final class DateType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + DateType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "date"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + int state = 0; + int start = 0; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '-' && i == 0) + { + start++; + continue; + } + if (c >= 0x30 && c <= 0x39) + continue; + switch (state) + { + case 0: // year + if (c == '-') + { + String year = value.substring(start, i); + if ("0000".equals(year) || year.length() < 4) + throw new DatatypeException(i, "invalid date value"); + state = 1; + start = i + 1; + continue; + } + break; + case 1: // month + if (c == '-') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid date value"); + state = 2; + start = i + 1; + continue; + } + break; + } + throw new DatatypeException(i, "invalid date value"); + } + switch (state) + { + case 2: // day + if (len - start != 2) + throw new DatatypeException("invalid date value"); + break; + default: + throw new DatatypeException("invalid date value"); + } + } + + public Object createValue(String value, ValidationContext context) { + int len = value.length(); + int state = 0; + int start = 0; + Calendar cal = new GregorianCalendar(); + cal.set(Calendar.HOUR, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + try + { + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '-' && i == 0) + { + start++; + continue; + } + if (c >= 0x30 && c <= 0x39) + continue; + switch (state) + { + case 0: // year + if (c == '-') + { + cal.set(Calendar.YEAR, + Integer.parseInt(value.substring(0, i))); + state = 1; + start = i + 1; + continue; + } + break; + case 1: // month + if (c == '-') + { + cal.set(Calendar.MONTH, + Integer.parseInt(value.substring(start, i))); + state = 2; + start = i + 1; + continue; + } + break; + case 2: // day + if (c == 'T') + { + cal.set(Calendar.DATE, + Integer.parseInt(value.substring(start, i))); + state = 7; + start = i + 1; + continue; + } + break; + } + } + // end of input + if (len - start > 0 && state == 7) + { + // Timezone + String timezone = value.substring(len - start); + int i = timezone.indexOf(':'); + if (i == -1) + { + if ("Z".equals(timezone)) + timezone = "UTC"; + TimeZone tz = TimeZone.getTimeZone(timezone); + if (tz == null) + return null; + cal.set(Calendar.ZONE_OFFSET, tz.getRawOffset()); + } + else + { + String tzh = timezone.substring(0, i); + String tzm = timezone.substring(i + 1); + int offset = Integer.parseInt(tzh) * 360000; + if (offset < 0) + offset -= Integer.parseInt(tzm) * 60000; + else + offset += Integer.parseInt(tzm) * 60000; + cal.set(Calendar.ZONE_OFFSET, offset); + } + } + return cal.getTime(); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/DecimalType.java b/gnu/xml/validation/datatype/DecimalType.java new file mode 100644 index 000000000..08fe3304c --- /dev/null +++ b/gnu/xml/validation/datatype/DecimalType.java @@ -0,0 +1,121 @@ +/* DecimalType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.Set; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema decimal type. + * + * @author Chris Burdess + */ +final class DecimalType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + DecimalType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "decimal"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException("invalid decimal value"); + boolean seenDot = false; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + continue; + else if (c == '.') + { + if (seenDot) + throw new DatatypeException(i, "invalid decimal value"); + seenDot = true; + continue; + } + else if (c == '+' && i == 0) + continue; + else if (c == '-' && i == 0) + continue; + else + throw new DatatypeException(i, "invalid decimal value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new BigDecimal(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/DoubleType.java b/gnu/xml/validation/datatype/DoubleType.java new file mode 100644 index 000000000..e25d060fa --- /dev/null +++ b/gnu/xml/validation/datatype/DoubleType.java @@ -0,0 +1,112 @@ +/* DoubleType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema double type. + * + * @author Chris Burdess + */ +final class DoubleType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + static final Set SPECIAL = + new TreeSet(Arrays.asList(new String[] {"INF", "-INF", "NaN"})); + + DoubleType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "double"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + if (SPECIAL.contains(value)) + return; + try + { + Double.parseDouble(value); + } + catch (NumberFormatException e) + { + DatatypeException e2 = new DatatypeException("invalid double value"); + e2.initCause(e); + throw e2; + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new Double(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/DurationType.java b/gnu/xml/validation/datatype/DurationType.java new file mode 100644 index 000000000..2cb92baae --- /dev/null +++ b/gnu/xml/validation/datatype/DurationType.java @@ -0,0 +1,239 @@ +/* DurationType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema duration type. + * + * @author Chris Burdess + */ +final class DurationType + extends AtomicSimpleType +{ + + static class Duration + implements Comparable + { + int years; + int months; + int days; + int minutes; + float seconds; + + public int hashCode() + { + int hc = years; + hc = hc * 31 + months; + hc = hc * 31 + days; + hc = hc * 31 + minutes; + hc = hc * 31 + new Float(seconds).hashCode(); + return hc; + } + + public boolean equals(Object other) + { + if (other instanceof Duration) + { + Duration duration = (Duration) other; + return duration.years ==years && + duration.months == months && + duration.days == days && + duration.minutes == minutes && + duration.seconds == seconds; + } + return false; + } + + public int compareTo(Object other) + { + if (other instanceof Duration) + { + Duration duration = (Duration) other; + if (duration.years != years) + return years - duration.years; + if (duration.months != months) + return months - duration.months; + if (duration.days != days) + return days - duration.days; + if (duration.minutes != minutes) + return minutes = duration.minutes; + if (duration.seconds == seconds) + return 0; + return (seconds < duration.seconds) ? -1 : 1; + } + return 0; + } + + } + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + DurationType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "duration"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + char expect = 'P'; + boolean seenT = false; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '-' && expect == 'P') + continue; + if (c == expect) + { + if (c == 'P') + expect = 'Y'; + else if (c == 'Y') + expect = 'M'; + else if (c == 'M' && !seenT) + expect = 'D'; + else if (c == 'D') + expect = 'T'; + else if (c == 'T') + { + expect = 'H'; + seenT = true; + } + else if (c == 'H') + expect = 'M'; + else if (c == 'M' && seenT) + expect = 'S'; + else if (c == 'S') + { + if (i + 1 != len) + throw new DatatypeException(i, "illegal duration value"); + } + continue; + } + if (c >= 0x30 && c <= 0x39 && expect != 'P' && expect != 'T') + continue; + throw new DatatypeException(i, "illegal duration value"); + } + } + + public Object createValue(String value, ValidationContext context) { + boolean negative = false; + int days = 0, months = 0, years = 0; + int minutes = 0; + float seconds = 0.0f; + int len = value.length(); + char expect = 'P'; + boolean seenT = false; + int start = 0; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '-' && expect == 'P') + { + negative = true; + continue; + } + if (c == expect) + { + if (c == 'P') + expect = 'Y'; + else if (c == 'Y') + { + expect = 'M'; + years = Integer.parseInt(value.substring(start, i)); + } + else if (c == 'M' && !seenT) + expect = 'D'; + else if (c == 'D') + expect = 'T'; + else if (c == 'T') + { + expect = 'H'; + seenT = true; + } + else if (c == 'H') + expect = 'M'; + else if (c == 'M' && seenT) + expect = 'S'; + else if (c == 'S') + { + if (i + 1 != len) + return null; + } + start = i + 1; + continue; + } + if (c >= 0x30 && c <= 0x39 && expect != 'P' && expect != 'T') + continue; + return null; + } + if (negative) + { + days = days * -1; + minutes = minutes * -1; + seconds = seconds * -1.0f; + } + Duration duration = new Duration(); + duration.days = days; + duration.minutes = minutes; + duration.seconds = seconds; + return duration; + } + +} + diff --git a/gnu/xml/validation/datatype/EntitiesType.java b/gnu/xml/validation/datatype/EntitiesType.java new file mode 100644 index 000000000..98554e184 --- /dev/null +++ b/gnu/xml/validation/datatype/EntitiesType.java @@ -0,0 +1,107 @@ +/* EntitiesType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema ENTITIES type. + * + * @author Chris Burdess + */ +final class EntitiesType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + EntitiesType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "ENTITIES"), + TypeLibrary.ENTITY); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + StringBuffer buf = new StringBuffer(); + int len = value.length(); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == ' ') + { + String token = buf.toString(); + if (token.length() > 0) + { + if (!context.isUnparsedEntity(token)) + throw new DatatypeException(i, "invalid ENTITIES value"); + } + buf.setLength(0); + } + else + buf.append(c); + } + String token = buf.toString(); + if (token.length() == 0 || !context.isUnparsedEntity(token)) + throw new DatatypeException("invalid ENTITIES value"); + } + + public boolean isContextDependent() + { + return true; + } + +} + diff --git a/gnu/xml/validation/datatype/EntityType.java b/gnu/xml/validation/datatype/EntityType.java new file mode 100644 index 000000000..f1443bcb9 --- /dev/null +++ b/gnu/xml/validation/datatype/EntityType.java @@ -0,0 +1,88 @@ +/* EntityType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema ENTITY type. + * + * @author Chris Burdess + */ +final class EntityType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + EntityType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "ENTITY"), + TypeLibrary.NCNAME); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + if (value.length() == 0 || !context.isUnparsedEntity(value)) + throw new DatatypeException("invalid ENTITY value"); + } + + public boolean isContextDependent() + { + return true; + } + +} + diff --git a/gnu/xml/validation/datatype/EnumerationFacet.java b/gnu/xml/validation/datatype/EnumerationFacet.java new file mode 100644 index 000000000..0ad3d3fa4 --- /dev/null +++ b/gnu/xml/validation/datatype/EnumerationFacet.java @@ -0,0 +1,69 @@ +/* EnumerationFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +/** + * The enumeration facet. + * + * @author Chris Burdess + */ +public final class EnumerationFacet + extends Facet +{ + + public final String value; + + public EnumerationFacet(String value, Annotation annotation) + { + super(ENUMERATION, annotation); + this.value = value; + } + + public int hashCode() + { + return value.hashCode(); + } + + public boolean equals(Object other) + { + return (other instanceof EnumerationFacet && + ((EnumerationFacet) other).value.equals(value)); + } + +} + diff --git a/gnu/xml/validation/datatype/Facet.java b/gnu/xml/validation/datatype/Facet.java new file mode 100644 index 000000000..490abf8ee --- /dev/null +++ b/gnu/xml/validation/datatype/Facet.java @@ -0,0 +1,78 @@ +/* Facet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +/** + * An XML Schema constraining facet. + * + * @author Chris Burdess + */ +public abstract class Facet +{ + + public static final int LENGTH = 1; + public static final int MIN_LENGTH = 2; + public static final int MAX_LENGTH = 3; + public static final int PATTERN = 4; + public static final int ENUMERATION = 5; + public static final int WHITESPACE = 6; + public static final int MAX_INCLUSIVE = 7; + public static final int MAX_EXCLUSIVE = 8; + public static final int MIN_EXCLUSIVE = 9; + public static final int MIN_INCLUSIVE = 10; + public static final int TOTAL_DIGITS = 11; + public static final int FRACTION_DIGITS = 12; + + /** + * The type of this facet. + */ + public final int type; + + /** + * Optional annotation. + */ + public Annotation annotation; + + protected Facet(int type, Annotation annotation) + { + this.type = type; + this.annotation = annotation; + } + +} + diff --git a/gnu/xml/validation/datatype/FloatType.java b/gnu/xml/validation/datatype/FloatType.java new file mode 100644 index 000000000..a81a56c1a --- /dev/null +++ b/gnu/xml/validation/datatype/FloatType.java @@ -0,0 +1,112 @@ +/* FloatType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema float type. + * + * @author Chris Burdess + */ +final class FloatType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + static final Set SPECIAL = + new TreeSet(Arrays.asList(new String[] {"INF", "-INF", "NaN"})); + + FloatType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "float"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + if (SPECIAL.contains(value)) + return; + try + { + Float.parseFloat(value); + } + catch (NumberFormatException e) + { + DatatypeException e2 = new DatatypeException("invalid float value"); + e2.initCause(e); + throw e2; + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new Float(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/FractionDigitsFacet.java b/gnu/xml/validation/datatype/FractionDigitsFacet.java new file mode 100644 index 000000000..efd986200 --- /dev/null +++ b/gnu/xml/validation/datatype/FractionDigitsFacet.java @@ -0,0 +1,72 @@ +/* FractionDigitsFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +/** + * The fractionDigits facet. + * + * @author Chris Burdess + */ +public final class FractionDigitsFacet + extends Facet +{ + + public final int value; + + public final boolean fixed; + + public FractionDigitsFacet(int value, boolean fixed, Annotation annotation) + { + super(FRACTION_DIGITS, annotation); + this.value = value; + this.fixed = fixed; + } + + public int hashCode() + { + return value; + } + + public boolean equals(Object other) + { + return (other instanceof FractionDigitsFacet && + ((FractionDigitsFacet) other).value == value); + } + +} + diff --git a/gnu/xml/validation/datatype/GDayType.java b/gnu/xml/validation/datatype/GDayType.java new file mode 100644 index 000000000..009af3585 --- /dev/null +++ b/gnu/xml/validation/datatype/GDayType.java @@ -0,0 +1,175 @@ +/* GDayType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema gDay type. + * + * @author Chris Burdess + */ +final class GDayType + extends AtomicSimpleType +{ + + static class GDay + implements Comparable + { + + int day; + + public int hashCode() + { + return day; + } + + public boolean equals(Object other) + { + if (other instanceof GDay) + return ((GDay) other).day == day; + return false; + } + + public int compareTo(Object other) + { + if (other instanceof GDay) + { + GDay gd = (GDay) other; + if (gd.day == day) + return 0; + return (day < gd.day) ? -1 : 1; + } + return 0; + } + + } + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + GDayType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gDay"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + int state = 0; + int start = 0; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + continue; + switch (state) + { + case 0: // year + if (c == '-') + { + switch (i) + { + case 0: + continue; + case 1: + state = 1; + start = i + 1; + continue; + default: + throw new DatatypeException(i, "invalid GDay value"); + } + } + break; + case 1: // month + if (c == '-') + { + if (i - start != 0) + throw new DatatypeException(i, "invalid GDay value"); + state = 2; + start = i + 1; + continue; + } + break; + } + throw new DatatypeException(i, "invalid GDay value"); + } + switch (state) + { + case 2: // day + if (len - start != 2) + throw new DatatypeException("invalid GDay value"); + break; + default: + throw new DatatypeException("invalid GDay value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + GDay ret = new GDay(); + ret.day = Integer.parseInt(literal.substring(3)); + return ret; + } + catch (Exception e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/GMonthDayType.java b/gnu/xml/validation/datatype/GMonthDayType.java new file mode 100644 index 000000000..a39a1cc43 --- /dev/null +++ b/gnu/xml/validation/datatype/GMonthDayType.java @@ -0,0 +1,184 @@ +/* GMonthDayType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema gMonthDay type. + * + * @author Chris Burdess + */ +final class GMonthDayType + extends AtomicSimpleType +{ + + static class GMonthDay + implements Comparable + { + + int month; + int day; + + public int hashCode() + { + return month * 31 + day; + } + + public boolean equals(Object other) + { + if (other instanceof GMonthDay) + { + GMonthDay gmd = (GMonthDay) other; + return gmd.month == month && gmd.day == day; + } + return false; + } + + public int compareTo(Object other) + { + if (other instanceof GMonthDay) + { + GMonthDay gmd = (GMonthDay) other; + if (gmd.month == month) + { + if (gmd.day == day) + return 0; + return (day < gmd.day) ? -1 : 1; + } + return (month < gmd.month) ? -1 : 1; + } + return 0; + } + + } + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + GMonthDayType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gMonthDay"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + int state = 0; + int start = 0; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + continue; + switch (state) + { + case 0: // year + if (c == '-') + { + switch (i) + { + case 0: + continue; + case 1: + state = 1; + start = i + 1; + continue; + default: + throw new DatatypeException(i, "illegal GMonthDay type"); + } + } + break; + case 1: // month + if (c == '-') + { + if (i - start != 2) + throw new DatatypeException(i, "illegal GMonthDay type"); + state = 2; + start = i + 1; + continue; + } + break; + } + throw new DatatypeException(i, "illegal GMonthDay type"); + } + switch (state) + { + case 2: // day + if (len - start != 2) + throw new DatatypeException("illegal GMonthDay type"); + break; + default: + throw new DatatypeException("illegal GMonthDay type"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + GMonthDay ret = new GMonthDay(); + ret.month = Integer.parseInt(literal.substring(2, 5)); + ret.day = Integer.parseInt(literal.substring(6)); + return ret; + } + catch (Exception e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/GMonthType.java b/gnu/xml/validation/datatype/GMonthType.java new file mode 100644 index 000000000..5a08af287 --- /dev/null +++ b/gnu/xml/validation/datatype/GMonthType.java @@ -0,0 +1,164 @@ +/* GMonthType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema gMonth type. + * + * @author Chris Burdess + */ +final class GMonthType + extends AtomicSimpleType +{ + + static class GMonth + implements Comparable + { + + int month; + + public int hashCode() + { + return month; + } + + public boolean equals(Object other) + { + if (other instanceof GMonth) + return ((GMonth) other).month == month; + return false; + } + + public int compareTo(Object other) + { + if (other instanceof GMonth) + { + GMonth gm = (GMonth) other; + if (gm.month == month) + return 0; + return (month < gm.month) ? -1 : 1; + } + return 0; + } + + } + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + GMonthType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gMonth"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + int len = value.length(); + int state = 0; + int start = 0; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + continue; + switch (state) + { + case 0: // year + if (c == '-') + { + switch (i) + { + case 0: + continue; + case 1: + state = 1; + start = i + 1; + continue; + default: + throw new DatatypeException(i, "illegal GMonth value"); + } + } + break; + } + throw new DatatypeException(i, "illegal GMonth value"); + } + switch (state) + { + case 1: // month + if (len - start != 2) + throw new DatatypeException("illegal GMonth value"); + break; + default: + throw new DatatypeException("illegal GMonth value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + GMonth ret = new GMonth(); + ret.month = Integer.parseInt(literal.substring(2)); + return ret; + } + catch (Exception e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/GYearMonthType.java b/gnu/xml/validation/datatype/GYearMonthType.java new file mode 100644 index 000000000..9ec38c0e7 --- /dev/null +++ b/gnu/xml/validation/datatype/GYearMonthType.java @@ -0,0 +1,177 @@ +/* GYearMonthType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema gYearMonth type. + * + * @author Chris Burdess + */ +final class GYearMonthType + extends AtomicSimpleType +{ + + static class GYearMonth + implements Comparable + { + + int year; + int month; + + public int hashCode() + { + return year * 31 + month; + } + + public boolean equals(Object other) + { + if (other instanceof GYearMonth) + { + GYearMonth gmy = (GYearMonth) other; + return gmy.year == year && gmy.month == month; + } + return false; + } + + public int compareTo(Object other) + { + if (other instanceof GYearMonth) + { + GYearMonth gmy = (GYearMonth) other; + if (gmy.year == year) + { + if (gmy.month == month) + return 0; + return (month < gmy.month) ? -1 : 1; + } + return (year < gmy.year) ? -1 : 1; + } + return 0; + } + + } + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + GYearMonthType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gYearMonth"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + int state = 0; + int start = 0; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '-' && i == 0) + { + start++; + continue; + } + if (c >= 0x30 && c <= 0x39) + continue; + switch (state) + { + case 0: // year + if (c == '-') + { + String year = value.substring(start, i); + if (year.length() < 4 || Integer.parseInt(year) == 0) + throw new DatatypeException(i, "illegal GYear value"); + state = 1; + start = i + 1; + continue; + } + break; + } + throw new DatatypeException(i, "illegal GYear value"); + } + switch (state) + { + case 1: // month + if (len - start != 2) + throw new DatatypeException("illegal GYear value"); + break; + default: + throw new DatatypeException("illegal GYear value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + int offset = 5; + if (literal.charAt(0) == '-') + offset++; + GYearMonth ret = new GYearMonth(); + ret.year = Integer.parseInt(literal.substring(0, offset)); + ret.month = Integer.parseInt(literal.substring(offset + 1)); + return ret; + } + catch (Exception e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/GYearType.java b/gnu/xml/validation/datatype/GYearType.java new file mode 100644 index 000000000..6dea89b76 --- /dev/null +++ b/gnu/xml/validation/datatype/GYearType.java @@ -0,0 +1,152 @@ +/* GYearType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema gYear type. + * + * @author Chris Burdess + */ +final class GYearType + extends AtomicSimpleType +{ + + static class GYear + implements Comparable + { + + int year; + + public int hashCode() + { + return year; + } + + public boolean equals(Object other) + { + if (other instanceof GYear) + return ((GYear) other).year == year; + return false; + } + + public int compareTo(Object other) + { + if (other instanceof GYear) + { + GYear gy = (GYear) other; + if (gy.year == year) + return 0; + return (year < gy.year) ? -1 : 1; + } + return 0; + } + + } + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + GYearType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gYear"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + int state = 0; + int start = 0; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '-' && i == 0) + { + start++; + continue; + } + if (c >= 0x30 && c <= 0x39) + continue; + throw new DatatypeException(i, "invalid GYear value"); + } + switch (state) + { + case 0: // year + String year = value.substring(start, len); + if (year.length() < 4 || Integer.parseInt(year) == 0) + throw new DatatypeException("invalid GYear value"); + break; + default: + throw new DatatypeException("invalid GYear value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + GYear ret = new GYear(); + ret.year = Integer.parseInt(literal); + return ret; + } + catch (Exception e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/HexBinaryType.java b/gnu/xml/validation/datatype/HexBinaryType.java new file mode 100644 index 000000000..686e09d98 --- /dev/null +++ b/gnu/xml/validation/datatype/HexBinaryType.java @@ -0,0 +1,92 @@ +/* HexBinaryType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Collections; +import java.util.Set; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema hexBinary type. + * + * @author Chris Burdess + */ +final class HexBinaryType + extends AtomicSimpleType +{ + + static final String HEX = "0123456789ABCDEF"; + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + HexBinaryType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "hexBinary"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (HEX.indexOf(c) == -1) + throw new DatatypeException(i, "invalid hexBinary value"); + } + } + +} + diff --git a/gnu/xml/validation/datatype/IDRefType.java b/gnu/xml/validation/datatype/IDRefType.java new file mode 100644 index 000000000..8ea9805b0 --- /dev/null +++ b/gnu/xml/validation/datatype/IDRefType.java @@ -0,0 +1,87 @@ +/* IDRefType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema IDREF type. + * + * @author Chris Burdess + */ +final class IDRefType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + IDRefType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "IDREF"), + TypeLibrary.NCNAME); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + // TODO + } + + public int getIdType() + { + return ID_TYPE_IDREF; + } + +} + diff --git a/gnu/xml/validation/datatype/IDRefsType.java b/gnu/xml/validation/datatype/IDRefsType.java new file mode 100644 index 000000000..57f7e56d7 --- /dev/null +++ b/gnu/xml/validation/datatype/IDRefsType.java @@ -0,0 +1,87 @@ +/* IDRefsType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema IDREFS type. + * + * @author Chris Burdess + */ +final class IDRefsType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + IDRefsType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "IDREFS"), + TypeLibrary.IDREF); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + // TODO + } + + public int getIdType() + { + return ID_TYPE_IDREFS; + } + +} + diff --git a/gnu/xml/validation/datatype/IDType.java b/gnu/xml/validation/datatype/IDType.java new file mode 100644 index 000000000..c55601aaf --- /dev/null +++ b/gnu/xml/validation/datatype/IDType.java @@ -0,0 +1,87 @@ +/* IDType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema ID type. + * + * @author Chris Burdess + */ +final class IDType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + IDType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "ID"), + TypeLibrary.NCNAME); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + // TODO + } + + public int getIdType() + { + return ID_TYPE_ID; + } + +} + diff --git a/gnu/xml/validation/datatype/IntType.java b/gnu/xml/validation/datatype/IntType.java new file mode 100644 index 000000000..6bf786604 --- /dev/null +++ b/gnu/xml/validation/datatype/IntType.java @@ -0,0 +1,133 @@ +/* IntType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema int type. + * + * @author Chris Burdess + */ +final class IntType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + static final String MAX_VALUE = "2147483647"; + static final String MIN_VALUE = "2147483648"; + static final int LENGTH = MAX_VALUE.length(); + + IntType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "int"), + TypeLibrary.LONG); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid int value"); + int i = 0, off = 0; + boolean compare = false; + String compareTo = MAX_VALUE; + char c = value.charAt(0); + if (c == '+') + i++; + else if (c == '-') + { + compareTo = MIN_VALUE; + i++; + } + if (len - i > LENGTH) + throw new DatatypeException("invalid int value"); + else if (len - i == LENGTH) + compare = true; + for (; i < len; i++) + { + c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + { + if (compare) + { + char d = compareTo.charAt(off); + if (Character.digit(c, 10) > Character.digit(d, 10)) + throw new DatatypeException(i, "invalid int value"); + } + off++; + continue; + } + throw new DatatypeException(i, "invalid int value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new Integer(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/IntegerType.java b/gnu/xml/validation/datatype/IntegerType.java new file mode 100644 index 000000000..2098a7d8d --- /dev/null +++ b/gnu/xml/validation/datatype/IntegerType.java @@ -0,0 +1,110 @@ +/* IntegerType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.math.BigInteger; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema integer type. + * + * @author Chris Burdess + */ +final class IntegerType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + IntegerType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "integer"), + TypeLibrary.DECIMAL); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid integer value"); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + continue; + else if (c == '+' && i == 0) + continue; + else if (c == '-' && i == 0) + continue; + throw new DatatypeException(i, "invalid integer value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new BigInteger(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/LanguageType.java b/gnu/xml/validation/datatype/LanguageType.java new file mode 100644 index 000000000..3df903c48 --- /dev/null +++ b/gnu/xml/validation/datatype/LanguageType.java @@ -0,0 +1,87 @@ +/* LanguageType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.regex.Pattern; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema language type. + * + * @author Chris Burdess + */ +final class LanguageType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + static final Pattern PATTERN = + Pattern.compile("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*"); + + LanguageType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "language"), + TypeLibrary.TOKEN); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + if (!PATTERN.matcher(value).matches()) + throw new DatatypeException("invalid language value"); + } + +} + diff --git a/gnu/xml/validation/datatype/LengthFacet.java b/gnu/xml/validation/datatype/LengthFacet.java new file mode 100644 index 000000000..cab4496b1 --- /dev/null +++ b/gnu/xml/validation/datatype/LengthFacet.java @@ -0,0 +1,72 @@ +/* LengthFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +/** + * The length facet. + * + * @author Chris Burdess + */ +public final class LengthFacet + extends Facet +{ + + public final int value; + + public final boolean fixed; + + public LengthFacet(int value, boolean fixed, Annotation annotation) + { + super(LENGTH, annotation); + this.value = value; + this.fixed = fixed; + } + + public int hashCode() + { + return value; + } + + public boolean equals(Object other) + { + return (other instanceof LengthFacet && + ((LengthFacet) other).value == value); + } + +} + diff --git a/gnu/xml/validation/datatype/ListSimpleType.java b/gnu/xml/validation/datatype/ListSimpleType.java new file mode 100644 index 000000000..1f0cb76fa --- /dev/null +++ b/gnu/xml/validation/datatype/ListSimpleType.java @@ -0,0 +1,83 @@ +/* ListSimpleType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Set; +import java.util.StringTokenizer; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * An XML Schema list simple type. + * + * @author Chris Burdess + */ +public class ListSimpleType + extends SimpleType +{ + + /** + * The type of the items in this list (atomic or union). + */ + public final SimpleType itemType; + + public ListSimpleType(QName name, Set facets, + int fundamentalFacets, SimpleType baseType, + Annotation annotation, SimpleType itemType) + { + super(name, LIST, facets, fundamentalFacets, baseType, annotation); + this.itemType = itemType; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + StringTokenizer st = new StringTokenizer(value, " "); + if (!st.hasMoreTokens()) + throw new DatatypeException("invalid list value"); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + itemType.checkValid(token, context); + } + } + +} + diff --git a/gnu/xml/validation/datatype/LongType.java b/gnu/xml/validation/datatype/LongType.java new file mode 100644 index 000000000..eaf69df38 --- /dev/null +++ b/gnu/xml/validation/datatype/LongType.java @@ -0,0 +1,133 @@ +/* LongType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema long type. + * + * @author Chris Burdess + */ +final class LongType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + static final String MAX_VALUE = "9223372036854775807"; + static final String MIN_VALUE = "9223372036854775808"; + static final int LENGTH = MAX_VALUE.length(); + + LongType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "long"), + TypeLibrary.INTEGER); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid long value"); + int i = 0, off = 0; + boolean compare = false; + String compareTo = MAX_VALUE; + char c = value.charAt(0); + if (c == '+') + i++; + else if (c == '-') + { + compareTo = MIN_VALUE; + i++; + } + if (len - i > LENGTH) + throw new DatatypeException(i, "invalid long value"); + else if (len - i == LENGTH) + compare = true; + for (; i < len; i++) + { + c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + { + if (compare) + { + char d = compareTo.charAt(off); + if (Character.digit(c, 10) > Character.digit(d, 10)) + throw new DatatypeException(i, "invalid long value"); + } + off++; + continue; + } + throw new DatatypeException(i, "invalid long value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new Long(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/MaxExclusiveFacet.java b/gnu/xml/validation/datatype/MaxExclusiveFacet.java new file mode 100644 index 000000000..7aac1f743 --- /dev/null +++ b/gnu/xml/validation/datatype/MaxExclusiveFacet.java @@ -0,0 +1,111 @@ +/* MaxExclusiveFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * The maxExclusive facet. + * + * @author Chris Burdess + */ +public final class MaxExclusiveFacet + extends Facet +{ + + public final Object value; // date or number + + public final boolean fixed; + + public MaxExclusiveFacet(Object value, boolean fixed, Annotation annotation) + { + super(MAX_EXCLUSIVE, annotation); + this.value = value; + this.fixed = fixed; + } + + public int hashCode() + { + return value.hashCode(); + } + + public boolean equals(Object other) + { + return (other instanceof MaxExclusiveFacet && + ((MaxExclusiveFacet) other).value.equals(value)); + } + + boolean matches(Object test) + { + if (value instanceof Date) + { + Date dvalue = (Date) value; + if (!(test instanceof Date)) + return false; + return ((Date) test).before(dvalue); + } + else if (value instanceof BigInteger) + { + BigInteger ivalue = (BigInteger) value; + if (!(test instanceof BigInteger)) + return false; + return ((BigInteger) test).compareTo(ivalue) < 0; + } + else if (value instanceof BigDecimal) + { + BigDecimal dvalue = (BigDecimal) value; + if (!(test instanceof BigDecimal)) + return false; + return ((BigDecimal) test).compareTo(dvalue) < 0; + } + else if (value instanceof Comparable) + { + if (!(test.getClass().equals(value.getClass()))) + return false; + return ((Comparable) test).compareTo(value) < 0; + } + Number nvalue = (Number) value; + if (!(test instanceof Number)) + return false; + return ((Number) test).doubleValue() < nvalue.doubleValue(); + } + +} + diff --git a/gnu/xml/validation/datatype/MaxInclusiveFacet.java b/gnu/xml/validation/datatype/MaxInclusiveFacet.java new file mode 100644 index 000000000..bb145ed41 --- /dev/null +++ b/gnu/xml/validation/datatype/MaxInclusiveFacet.java @@ -0,0 +1,112 @@ +/* MaxInclusiveFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * The maxInclusive facet. + * + * @author Chris Burdess + */ +public final class MaxInclusiveFacet + extends Facet +{ + + public final Object value; + + public final boolean fixed; + + public MaxInclusiveFacet(Object value, boolean fixed, Annotation annotation) + { + super(MAX_INCLUSIVE, annotation); + this.value = value; + this.fixed = fixed; + } + + public int hashCode() + { + return value.hashCode(); + } + + public boolean equals(Object other) + { + return (other instanceof MaxInclusiveFacet && + ((MaxInclusiveFacet) other).value.equals(value)); + } + + boolean matches(Object test) + { + if (value instanceof Date) + { + Date dvalue = (Date) value; + if (!(test instanceof Date)) + return false; + Date dtest = (Date) test; + return dtest.equals(dvalue) || dtest.before(dvalue); + } + else if (value instanceof BigInteger) + { + BigInteger ivalue = (BigInteger) value; + if (!(test instanceof BigInteger)) + return false; + return ((BigInteger) test).compareTo(ivalue) <= 0; + } + else if (value instanceof BigDecimal) + { + BigDecimal dvalue = (BigDecimal) value; + if (!(test instanceof BigDecimal)) + return false; + return ((BigDecimal) test).compareTo(dvalue) <= 0; + } + else if (value instanceof Comparable) + { + if (!(test.getClass().equals(value.getClass()))) + return false; + return ((Comparable) test).compareTo(value) <= 0; + } + Number nvalue = (Number) value; + if (!(test instanceof Number)) + return false; + return ((Number) test).doubleValue() <= nvalue.doubleValue(); + } + +} + diff --git a/gnu/xml/validation/datatype/MaxLengthFacet.java b/gnu/xml/validation/datatype/MaxLengthFacet.java new file mode 100644 index 000000000..d03326311 --- /dev/null +++ b/gnu/xml/validation/datatype/MaxLengthFacet.java @@ -0,0 +1,72 @@ +/* MaxLengthFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +/** + * The maxLength facet. + * + * @author Chris Burdess + */ +public final class MaxLengthFacet + extends Facet +{ + + public final int value; + + public final boolean fixed; + + public MaxLengthFacet(int value, boolean fixed, Annotation annotation) + { + super(MAX_LENGTH, annotation); + this.value = value; + this.fixed = fixed; + } + + public int hashCode() + { + return value; + } + + public boolean equals(Object other) + { + return (other instanceof MaxLengthFacet && + ((MaxLengthFacet) other).value == value); + } + +} + diff --git a/gnu/xml/validation/datatype/MinExclusiveFacet.java b/gnu/xml/validation/datatype/MinExclusiveFacet.java new file mode 100644 index 000000000..2289bb11c --- /dev/null +++ b/gnu/xml/validation/datatype/MinExclusiveFacet.java @@ -0,0 +1,111 @@ +/* MinExclusiveFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * The minExclusive facet. + * + * @author Chris Burdess + */ +public final class MinExclusiveFacet + extends Facet +{ + + public final Object value; + + public final boolean fixed; + + public MinExclusiveFacet(Object value, boolean fixed, Annotation annotation) + { + super(MIN_EXCLUSIVE, annotation); + this.value = value; + this.fixed = fixed; + } + + public int hashCode() + { + return value.hashCode(); + } + + public boolean equals(Object other) + { + return (other instanceof MinExclusiveFacet && + ((MinExclusiveFacet) other).value.equals(value)); + } + + boolean matches(Object test) + { + if (value instanceof Date) + { + Date dvalue = (Date) value; + if (!(test instanceof Date)) + return false; + return ((Date) test).after(dvalue); + } + else if (value instanceof BigInteger) + { + BigInteger ivalue = (BigInteger) value; + if (!(test instanceof BigInteger)) + return false; + return ((BigInteger) test).compareTo(ivalue) > 0; + } + else if (value instanceof BigDecimal) + { + BigDecimal dvalue = (BigDecimal) value; + if (!(test instanceof BigDecimal)) + return false; + return ((BigDecimal) test).compareTo(dvalue) > 0; + } + else if (value instanceof Comparable) + { + if (!(test.getClass().equals(value.getClass()))) + return false; + return ((Comparable) test).compareTo(value) > 0; + } + Number nvalue = (Number) value; + if (!(test instanceof Number)) + return false; + return ((Number) test).doubleValue() > nvalue.doubleValue(); + } + +} + diff --git a/gnu/xml/validation/datatype/MinInclusiveFacet.java b/gnu/xml/validation/datatype/MinInclusiveFacet.java new file mode 100644 index 000000000..6c07c3644 --- /dev/null +++ b/gnu/xml/validation/datatype/MinInclusiveFacet.java @@ -0,0 +1,112 @@ +/* MinInclusiveFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +/** + * The minInclusive facet. + * + * @author Chris Burdess + */ +public final class MinInclusiveFacet + extends Facet +{ + + public final Object value; + + public final boolean fixed; + + public MinInclusiveFacet(Object value, boolean fixed, Annotation annotation) + { + super(MIN_INCLUSIVE, annotation); + this.value = value; + this.fixed = fixed; + } + + public int hashCode() + { + return value.hashCode(); + } + + public boolean equals(Object other) + { + return (other instanceof MinInclusiveFacet && + ((MinInclusiveFacet) other).value.equals(value)); + } + + boolean matches(Object test) + { + if (value instanceof Date) + { + Date dvalue = (Date) value; + if (!(test instanceof Date)) + return false; + Date dtest = (Date) test; + return dtest.equals(dvalue) || dtest.after(dvalue); + } + else if (value instanceof BigInteger) + { + BigInteger ivalue = (BigInteger) value; + if (!(test instanceof BigInteger)) + return false; + return ((BigInteger) test).compareTo(ivalue) >= 0; + } + else if (value instanceof BigDecimal) + { + BigDecimal dvalue = (BigDecimal) value; + if (!(test instanceof BigDecimal)) + return false; + return ((BigDecimal) test).compareTo(dvalue) >= 0; + } + else if (value instanceof Comparable) + { + if (!(test.getClass().equals(value.getClass()))) + return false; + return ((Comparable) test).compareTo(value) >= 0; + } + Number nvalue = (Number) value; + if (!(test instanceof Number)) + return false; + return ((Number) test).doubleValue() >= nvalue.doubleValue(); + } + +} + diff --git a/gnu/xml/validation/datatype/MinLengthFacet.java b/gnu/xml/validation/datatype/MinLengthFacet.java new file mode 100644 index 000000000..c7dee200b --- /dev/null +++ b/gnu/xml/validation/datatype/MinLengthFacet.java @@ -0,0 +1,72 @@ +/* MinLengthFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +/** + * The minLength facet. + * + * @author Chris Burdess + */ +public final class MinLengthFacet + extends Facet +{ + + public final int value; + + public final boolean fixed; + + public MinLengthFacet(int value, boolean fixed, Annotation annotation) + { + super(MIN_LENGTH, annotation); + this.value = value; + this.fixed = fixed; + } + + public int hashCode() + { + return value; + } + + public boolean equals(Object other) + { + return (other instanceof MinLengthFacet && + ((MinLengthFacet) other).value == value); + } + +} + diff --git a/gnu/xml/validation/datatype/NCNameType.java b/gnu/xml/validation/datatype/NCNameType.java new file mode 100644 index 000000000..4188d886a --- /dev/null +++ b/gnu/xml/validation/datatype/NCNameType.java @@ -0,0 +1,111 @@ +/* NCNameType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.io.IOException; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; +import gnu.xml.stream.UnicodeReader; +import gnu.xml.stream.XMLParser; + +/** + * The XML Schema NCName type. + * + * @author Chris Burdess + */ +final class NCNameType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + NCNameType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "NCName"), + TypeLibrary.NAME); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + try + { + int[] cp = UnicodeReader.toCodePointArray(value); + if (cp.length == 0) + throw new DatatypeException("invalid NCName value"); + // XXX XML 1.1 documents? + if (cp[0] == ':' || !XMLParser.isNameStartCharacter(cp[0], false)) + throw new DatatypeException(0, "invalid NCName value"); + boolean seenColon = false; + for (int i = 1; i < cp.length; i++) + { + if (cp[i] == ':') + { + if (seenColon || (i + 1 == cp.length)) + throw new DatatypeException(i, "invalid NCName value"); + seenColon = true; + } + else if (!XMLParser.isNameCharacter(cp[i], false)) + throw new DatatypeException(i, "invalid NCName value"); + } + } + catch (IOException e) + { + DatatypeException e2 = new DatatypeException("invalid NCName value"); + e2.initCause(e); + throw e2; + } + } + +} + diff --git a/gnu/xml/validation/datatype/NMTokenType.java b/gnu/xml/validation/datatype/NMTokenType.java new file mode 100644 index 000000000..4498fecfa --- /dev/null +++ b/gnu/xml/validation/datatype/NMTokenType.java @@ -0,0 +1,102 @@ +/* NMTokenType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.io.IOException; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; +import gnu.xml.stream.UnicodeReader; +import gnu.xml.stream.XMLParser; + +/** + * The XML Schema NMTOKEN type. + * + * @author Chris Burdess + */ +final class NMTokenType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + NMTokenType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "NMTOKEN"), + TypeLibrary.TOKEN); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + try + { + int[] cp = UnicodeReader.toCodePointArray(value); + if (cp.length == 0) + throw new DatatypeException("invalid NMTOKEN value"); + for (int i = 0; i < cp.length; i++) + { + // XXX XML 1.1 documents? + if (!XMLParser.isNameCharacter(cp[i], false)) + throw new DatatypeException(i, "invalid NMTOKEN value"); + } + } + catch (IOException e) + { + DatatypeException e2 = new DatatypeException("invalid NMTOKEN value"); + e2.initCause(e); + throw e2; + } + } + +} + diff --git a/gnu/xml/validation/datatype/NMTokensType.java b/gnu/xml/validation/datatype/NMTokensType.java new file mode 100644 index 000000000..62524edf7 --- /dev/null +++ b/gnu/xml/validation/datatype/NMTokensType.java @@ -0,0 +1,124 @@ +/* NMTokensType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.io.IOException; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; +import gnu.xml.stream.UnicodeReader; +import gnu.xml.stream.XMLParser; + +/** + * The XML Schema NMTOKENS type. + * + * @author Chris Burdess + */ +final class NMTokensType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + NMTokensType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "NMTOKENS"), + TypeLibrary.NMTOKEN); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == ' ') + { + String token = buf.toString(); + if (token.length() > 0) + checkNmtoken(token, i); + buf.setLength(0); + } + else + buf.append(c); + } + checkNmtoken(buf.toString(), len); + } + + private void checkNmtoken(String text, int i) + throws DatatypeException + { + try + { + int[] cp = UnicodeReader.toCodePointArray(text); + if (cp.length == 0) + throw new DatatypeException("invalid NMTOKEN value"); + for (int j = 0; j < cp.length; j++) + { + // XXX XML 1.1 documents? + if (!XMLParser.isNameCharacter(cp[j], false)) + throw new DatatypeException(i, "invalid NMTOKEN value"); + } + } + catch (IOException e) + { + DatatypeException e2 = new DatatypeException("invalid NMTOKEN value"); + e2.initCause(e); + throw e2; + } + } + + +} + diff --git a/gnu/xml/validation/datatype/NameType.java b/gnu/xml/validation/datatype/NameType.java new file mode 100644 index 000000000..a2fbb9d5b --- /dev/null +++ b/gnu/xml/validation/datatype/NameType.java @@ -0,0 +1,104 @@ +/* NameType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.io.IOException; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; +import gnu.xml.stream.UnicodeReader; +import gnu.xml.stream.XMLParser; + +/** + * The XML Schema Name type. + * + * @author Chris Burdess + */ +final class NameType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + NameType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "Name"), + TypeLibrary.TOKEN); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + try + { + int[] cp = UnicodeReader.toCodePointArray(value); + if (cp.length == 0) + throw new DatatypeException("invalid Name value"); + // XXX XML 1.1 documents? + if (!XMLParser.isNameStartCharacter(cp[0], false)) + throw new DatatypeException(0, "invalid Name value"); + for (int i = 1; i < cp.length; i++) + { + if (!XMLParser.isNameCharacter(cp[i], false)) + throw new DatatypeException(i, "invalid Name value"); + } + } + catch (IOException e) + { + DatatypeException e2 = new DatatypeException("invalid Name value"); + e2.initCause(e); + throw e2; + } + } + +} + diff --git a/gnu/xml/validation/datatype/NegativeIntegerType.java b/gnu/xml/validation/datatype/NegativeIntegerType.java new file mode 100644 index 000000000..fd436cb55 --- /dev/null +++ b/gnu/xml/validation/datatype/NegativeIntegerType.java @@ -0,0 +1,111 @@ +/* NegativeIntegerType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.math.BigInteger; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema negativeInteger type. + * + * @author Chris Burdess + */ +final class NegativeIntegerType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + NegativeIntegerType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "negativeInteger"), + TypeLibrary.NON_POSITIVE_INTEGER); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValue(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid negative integer value"); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '-') + { + if (i == 0) + continue; + } + else if (c >= 0x30 && c <= 0x39) + continue; + throw new DatatypeException(i, "invalid negative integer value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new BigInteger(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/NonNegativeIntegerType.java b/gnu/xml/validation/datatype/NonNegativeIntegerType.java new file mode 100644 index 000000000..857778582 --- /dev/null +++ b/gnu/xml/validation/datatype/NonNegativeIntegerType.java @@ -0,0 +1,121 @@ +/* NonNegativeIntegerType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.math.BigInteger; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema nonNegativeInteger type. + * + * @author Chris Burdess + */ +final class NonNegativeIntegerType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + NonNegativeIntegerType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "nonNegativeInteger"), + TypeLibrary.INTEGER); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid non-negative integer value"); + boolean negative = false; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == 0x30) + continue; + else if (c >= 0x31 && c <= 0x39) + { + if (negative) + throw new DatatypeException(i, + "invalid non-negative integer value"); + continue; + } + else if (c == '+' && i == 0) + continue; + else if (c == '-' && i == 0) + { + negative = true; + continue; + } + throw new DatatypeException(i, "invalid non-negative integer value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new BigInteger(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/NonPositiveIntegerType.java b/gnu/xml/validation/datatype/NonPositiveIntegerType.java new file mode 100644 index 000000000..0b43d5227 --- /dev/null +++ b/gnu/xml/validation/datatype/NonPositiveIntegerType.java @@ -0,0 +1,121 @@ +/* NonPositiveIntegerType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.math.BigInteger; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema nonPositiveInteger type. + * + * @author Chris Burdess + */ +final class NonPositiveIntegerType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + NonPositiveIntegerType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "nonPositiveInteger"), + TypeLibrary.INTEGER); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid non-positive integer value"); + boolean positive = true; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == 0x30) + continue; + else if (c >= 0x31 && c <= 0x39) + { + if (positive) + throw new DatatypeException(i, + "invalid non-positive integer value"); + continue; + } + else if (c == '+' && i == 0) + continue; + else if (c == '-' && i == 0) + { + positive = false; + continue; + } + throw new DatatypeException(i, "invalid non-positive integer value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new BigInteger(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/NormalizedStringType.java b/gnu/xml/validation/datatype/NormalizedStringType.java new file mode 100644 index 000000000..a74312d11 --- /dev/null +++ b/gnu/xml/validation/datatype/NormalizedStringType.java @@ -0,0 +1,88 @@ +/* NormalizedStringType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema normalizedString type. + * + * @author Chris Burdess + */ +final class NormalizedStringType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + NormalizedStringType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "normalizedString"), + TypeLibrary.STRING); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == 0x0a || c == 0x0d || c == 0x09) + throw new DatatypeException(i, "invalid normalized-string value"); + } + } + +} + diff --git a/gnu/xml/validation/datatype/NotationType.java b/gnu/xml/validation/datatype/NotationType.java new file mode 100644 index 000000000..59c7f25e5 --- /dev/null +++ b/gnu/xml/validation/datatype/NotationType.java @@ -0,0 +1,90 @@ +/* NotationType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Collections; +import java.util.Set; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema NOTATION type. + * + * @author Chris Burdess + */ +final class NotationType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + NotationType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "NOTATION"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + if (!context.isNotation(value)) + throw new DatatypeException("invalid NOTATION value"); + } + + public boolean isContextDependent() + { + return true; + } + +} + diff --git a/gnu/xml/validation/datatype/PatternFacet.java b/gnu/xml/validation/datatype/PatternFacet.java new file mode 100644 index 000000000..d594b26b9 --- /dev/null +++ b/gnu/xml/validation/datatype/PatternFacet.java @@ -0,0 +1,71 @@ +/* PatternFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.regex.Pattern; + +/** + * The pattern facet. + * + * @author Chris Burdess + */ +public final class PatternFacet + extends Facet +{ + + public final Pattern value; + + public PatternFacet(Pattern value, Annotation annotation) + { + super(PATTERN, annotation); + this.value = value; + } + + public int hashCode() + { + return value.hashCode(); + } + + public boolean equals(Object other) + { + return (other instanceof PatternFacet && + ((PatternFacet) other).value.equals(value)); + } + +} + diff --git a/gnu/xml/validation/datatype/PositiveIntegerType.java b/gnu/xml/validation/datatype/PositiveIntegerType.java new file mode 100644 index 000000000..0c10df3ab --- /dev/null +++ b/gnu/xml/validation/datatype/PositiveIntegerType.java @@ -0,0 +1,111 @@ +/* PositiveIntegerType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.math.BigInteger; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema positiveInteger type. + * + * @author Chris Burdess + */ +final class PositiveIntegerType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + PositiveIntegerType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "positiveInteger"), + TypeLibrary.NON_NEGATIVE_INTEGER); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid positive integer value"); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '+') + { + if (i == 0) + continue; + } + else if (c >= 0x30 && c <= 0x39) + continue; + throw new DatatypeException(i, "invalid positive integer value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new BigInteger(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/QNameType.java b/gnu/xml/validation/datatype/QNameType.java new file mode 100644 index 000000000..1eaa51895 --- /dev/null +++ b/gnu/xml/validation/datatype/QNameType.java @@ -0,0 +1,122 @@ +/* QNameType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.io.IOException; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; +import gnu.xml.stream.UnicodeReader; +import gnu.xml.stream.XMLParser; + +/** + * The XML Schema QName type. + * + * @author Chris Burdess + */ +final class QNameType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + QNameType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "QName"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int ci = -1; + try + { + int[] cp = UnicodeReader.toCodePointArray(value); + if (cp.length == 0) + throw new DatatypeException("invalid NCName value"); + // XXX XML 1.1 documents? + if (cp[0] == ':' || !XMLParser.isNameStartCharacter(cp[0], false)) + throw new DatatypeException(0, "invalid NCName value"); + for (int i = 1; i < cp.length; i++) + { + if (cp[i] == ':') + { + if (ci != -1 || (i + 1 == cp.length)) + throw new DatatypeException(i, "invalid NCName value"); + ci = i; + } + else if (!XMLParser.isNameCharacter(cp[i], false)) + throw new DatatypeException(i, "invalid NCName value"); + } + } + catch (IOException e) + { + DatatypeException e2 = new DatatypeException("invalid NCName value"); + e2.initCause(e); + throw e2; + } + if (ci != -1) + { + String prefix = value.substring(0, ci); + if (context.resolveNamespacePrefix(prefix) == null) + throw new DatatypeException("invalid namespace prefix"); + } + } + + public boolean isContextDependent() + { + return true; + } + +} + diff --git a/gnu/xml/validation/datatype/ShortType.java b/gnu/xml/validation/datatype/ShortType.java new file mode 100644 index 000000000..3179c8dae --- /dev/null +++ b/gnu/xml/validation/datatype/ShortType.java @@ -0,0 +1,133 @@ +/* ShortType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema short type. + * + * @author Chris Burdess + */ +final class ShortType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + static final String MAX_VALUE = "32767"; + static final String MIN_VALUE = "32768"; + static final int LENGTH = MAX_VALUE.length(); + + ShortType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "short"), + TypeLibrary.INT); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid short value"); + int i = 0, off = 0; + boolean compare = false; + String compareTo = MAX_VALUE; + char c = value.charAt(0); + if (c == '+') + i++; + else if (c == '-') + { + compareTo = MIN_VALUE; + i++; + } + if (len - i > LENGTH) + throw new DatatypeException(i, "invalid short value"); + else if (len - i == LENGTH) + compare = true; + for (; i < len; i++) + { + c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + { + if (compare) + { + char d = compareTo.charAt(off); + if (Character.digit(c, 10) > Character.digit(d, 10)) + throw new DatatypeException(i, "invalid short value"); + } + off++; + continue; + } + throw new DatatypeException(i, "invalid short value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new Short(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/SimpleType.java b/gnu/xml/validation/datatype/SimpleType.java new file mode 100644 index 000000000..6554f2fe0 --- /dev/null +++ b/gnu/xml/validation/datatype/SimpleType.java @@ -0,0 +1,257 @@ +/* SimpleType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Iterator; +import java.util.Set; +import java.util.regex.Matcher; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.Datatype; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.DatatypeStreamingValidator; +import org.relaxng.datatype.ValidationContext; + +/** + * An XML Schema simple type. + * + * @author Chris Burdess + */ +public class SimpleType + extends Type + implements Datatype +{ + + /** + * The variety of the anySimpleType datatype. + */ + public static final int ANY = 0; + + /** + * The atomic variety. + */ + public static final int ATOMIC = 1; + + /** + * The list variety. + */ + public static final int LIST = 2; + + /** + * The union variety. + */ + public static final int UNION = 3; + + public static final int ID_TYPE_NULL = 0; + public static final int ID_TYPE_ID = 1; + public static final int ID_TYPE_IDREF = 2; + public static final int ID_TYPE_IDREFS = 3; + + /** + * The variety of this simple type. + */ + public final int variety; + + /** + * The facets of this simple type. + */ + public Set facets; + + /** + * The fundamental facets of this simple type. + */ + public int fundamentalFacets; + + /** + * If this datatype has been derived by restriction, then the component + * from which it was derived. + */ + public final SimpleType baseType; + + /** + * Optional annotation. + */ + public final Annotation annotation; + + public SimpleType(QName name, int variety, Set facets, + int fundamentalFacets, SimpleType baseType, + Annotation annotation) + { + super(name); + this.variety = variety; + this.facets = facets; + this.fundamentalFacets = fundamentalFacets; + this.baseType = baseType; + this.annotation = annotation; + } + + /** + * Indicates whether this type permits the specified value. + */ + public boolean isValid(String value, ValidationContext context) + { + try + { + checkValid(value, context); + return true; + } + catch (DatatypeException e) + { + return false; + } + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + if (facets != null && !facets.isEmpty()) + { + Object parsedValue = createValue(value, context); + for (Iterator i = facets.iterator(); i.hasNext(); ) + { + Facet facet = (Facet) i.next(); + switch (facet.type) + { + case Facet.LENGTH: + LengthFacet lf = (LengthFacet) facet; + if (value.length() != lf.value) + throw new DatatypeException("invalid length"); + break; + case Facet.MIN_LENGTH: + MinLengthFacet nlf = (MinLengthFacet) facet; + if (value.length() < nlf.value) + throw new DatatypeException("invalid minimum length"); + break; + case Facet.MAX_LENGTH: + MaxLengthFacet xlf = (MaxLengthFacet) facet; + if (value.length() > xlf.value) + throw new DatatypeException("invalid maximum length"); + break; + case Facet.PATTERN: + PatternFacet pf = (PatternFacet) facet; + Matcher matcher = pf.value.matcher(value); + if (!matcher.find()) + throw new DatatypeException("invalid match for pattern"); + break; + case Facet.ENUMERATION: + // TODO + break; + case Facet.WHITESPACE: + // TODO + break; + case Facet.MAX_INCLUSIVE: + MaxInclusiveFacet xif = (MaxInclusiveFacet) facet; + if (!xif.matches(parsedValue)) + throw new DatatypeException("beyond upper bound"); + break; + case Facet.MAX_EXCLUSIVE: + MaxExclusiveFacet xef = (MaxExclusiveFacet) facet; + if (!xef.matches(parsedValue)) + throw new DatatypeException("beyond upper bound"); + break; + case Facet.MIN_EXCLUSIVE: + MinExclusiveFacet nef = (MinExclusiveFacet) facet; + if (!nef.matches(parsedValue)) + throw new DatatypeException("beyond lower bound"); + break; + case Facet.MIN_INCLUSIVE: + MinInclusiveFacet nif = (MinInclusiveFacet) facet; + if (!nif.matches(parsedValue)) + throw new DatatypeException("beyond lower bound"); + break; + case Facet.TOTAL_DIGITS: + TotalDigitsFacet tdf = (TotalDigitsFacet) facet; + if (countDigits(value, true) > tdf.value) + throw new DatatypeException("too many digits"); + break; + case Facet.FRACTION_DIGITS: + FractionDigitsFacet fdf = (FractionDigitsFacet) facet; + if (countDigits(value, false) > fdf.value) + throw new DatatypeException("too many fraction digits"); + break; + } + } + } + } + + private static int countDigits(String value, boolean any) + { + int count = 0; + int len = value.length(); + boolean seenDecimal = false; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == 0x2e) + seenDecimal = true; + else if (c >= 0x30 && c <= 0x39 && (any || seenDecimal)) + count++; + } + return count; + } + + // TODO createStreamingValidator + public DatatypeStreamingValidator createStreamingValidator(ValidationContext context) + { + throw new UnsupportedOperationException(); + } + + public Object createValue(String literal, ValidationContext context) { + return literal; + } + + public boolean sameValue(Object value1, Object value2) { + return value1.equals(value2); + } + + public int valueHashCode(Object value) { + return value.hashCode(); + } + + public int getIdType() + { + return ID_TYPE_NULL; + } + + public boolean isContextDependent() + { + return false; + } + +} + diff --git a/gnu/xml/validation/datatype/StringType.java b/gnu/xml/validation/datatype/StringType.java new file mode 100644 index 000000000..a2235f2df --- /dev/null +++ b/gnu/xml/validation/datatype/StringType.java @@ -0,0 +1,77 @@ +/* StringType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Collections; +import java.util.Set; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema string type. + * + * @author Chris Burdess + */ +final class StringType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + StringType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "string"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + +} + diff --git a/gnu/xml/validation/datatype/TimeType.java b/gnu/xml/validation/datatype/TimeType.java new file mode 100644 index 000000000..0152e1171 --- /dev/null +++ b/gnu/xml/validation/datatype/TimeType.java @@ -0,0 +1,303 @@ +/* TimeType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.TimeZone; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema time type. + * + * @author Chris Burdess + */ +final class TimeType + extends AtomicSimpleType +{ + + static class Time + implements Comparable + { + int minutes; + float seconds; + + public int hashCode() + { + return minutes * 31 + new Float(seconds).hashCode(); + } + + public boolean equals(Object other) + { + if (other instanceof Time) + { + Time time = (Time) other; + return time.minutes == minutes && time.seconds == seconds; + } + return false; + } + + public int compareTo(Object other) + { + if (other instanceof Time) + { + Time time = (Time) other; + if (time.minutes != minutes) + return minutes - time.minutes; + if (time.seconds == seconds) + return 0; + return (seconds < time.seconds) ? -1 : 1; + } + return 0; + } + + } + + static final int[] CONSTRAINING_FACETS = { + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + TimeType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "time"), + TypeLibrary.ANY_SIMPLE_TYPE); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + int state = 3; + int start = 0; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '-' && state == 0) + { + start++; + continue; + } + if (c >= 0x30 && c <= 0x39) + continue; + switch (state) + { + case 3: // hour + if (c == ':') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid time value"); + state = 4; + start = i + 1; + continue; + } + break; + case 4: // minute + if (c == ':') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid time value"); + state = 5; + start = i + 1; + continue; + } + break; + case 5: // second + if (c == '.') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid time value"); + state = 6; + start = i + 1; + continue; + } + else if (c == ' ') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid time value"); + state = 7; + start = i + 1; + continue; + } + break; + case 6: // second fraction + if (c == ' ') + { + state = 7; + start = i + 1; + continue; + } + break; + case 7: // timezone 1 + if (start == i) + { + if (c == '+' || c == '-') + continue; + else if (c == 'Z') + { + state = 9; + start = i + 1; + continue; + } + } + if (c == ':') + { + if (i - start != 2) + throw new DatatypeException(i, "invalid time value"); + state = 8; + start = i + 1; + continue; + } + break; + } + throw new DatatypeException(i, "invalid time value"); + } + switch (state) + { + case 5: // second + if (len - start != 2) + throw new DatatypeException(len, "invalid time value"); + break; + case 6: // second fraction + break; + case 8: // timezone 2 + if (len - start != 2) + throw new DatatypeException(len, "invalid time value"); + break; + case 9: // post Z + break; + default: + throw new DatatypeException(len, "invalid time value"); + } + } + + public Object createValue(String value, ValidationContext context) { + int len = value.length(); + int state = 3; + int start = 0; + Time time = new Time(); + try + { + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + continue; + switch (state) + { + case 3: // hour + if (c == ':') + { + time.minutes = + Integer.parseInt(value.substring(start, i)) * 60; + state = 4; + start = i + 1; + continue; + } + break; + case 4: // minute + if (c == ':') + { + time.minutes += + Integer.parseInt(value.substring(start, i)); + state = 5; + start = i + 1; + continue; + } + break; + case 5: // second + if (c == ' ') + { + time.seconds = + Float.parseFloat(value.substring(start, i)); + state = 7; + start = i + 1; + continue; + } + break; + } + } + // end of input + if (len - start > 0 && state == 7) + { + // Timezone + String timezone = value.substring(len - start); + int i = timezone.indexOf(':'); + if (i == -1) + { + if ("Z".equals(timezone)) + timezone = "UTC"; + TimeZone tz = TimeZone.getTimeZone(timezone); + if (tz == null) + return null; + time.minutes += tz.getRawOffset(); + } + else + { + String tzh = timezone.substring(0, i); + String tzm = timezone.substring(i + 1); + int offset = Integer.parseInt(tzh) * 60; + if (offset < 0) + offset -= Integer.parseInt(tzm); + else + offset += Integer.parseInt(tzm); + time.minutes += offset; + } + } + return time; + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/TokenType.java b/gnu/xml/validation/datatype/TokenType.java new file mode 100644 index 000000000..18e1e8ad5 --- /dev/null +++ b/gnu/xml/validation/datatype/TokenType.java @@ -0,0 +1,96 @@ +/* TokenType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema token type. + * + * @author Chris Burdess + */ +final class TokenType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.LENGTH, + Facet.MIN_LENGTH, + Facet.MAX_LENGTH, + Facet.PATTERN, + Facet.ENUMERATION, + Facet.WHITESPACE + }; + + TokenType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "token"), + TypeLibrary.NORMALIZED_STRING); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid token value"); + if (value.charAt(0) == ' ' || value.charAt(len - 1) == ' ') + throw new DatatypeException(0, "invalid token value"); + char last = '\u0000'; + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == 0x0a || c == 0x0d || c == 0x09) + throw new DatatypeException(i, "invalid token value"); + if (c == ' ' && last == ' ') + throw new DatatypeException(i, "invalid token value"); + last = c; + } + } + +} + diff --git a/gnu/xml/validation/datatype/TotalDigitsFacet.java b/gnu/xml/validation/datatype/TotalDigitsFacet.java new file mode 100644 index 000000000..4debc638e --- /dev/null +++ b/gnu/xml/validation/datatype/TotalDigitsFacet.java @@ -0,0 +1,72 @@ +/* TotalDigitsFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +/** + * The totalDigits facet. + * + * @author Chris Burdess + */ +public final class TotalDigitsFacet + extends Facet +{ + + public final int value; + + public final boolean fixed; + + public TotalDigitsFacet(int value, boolean fixed, Annotation annotation) + { + super(TOTAL_DIGITS, annotation); + this.value = value; + this.fixed = fixed; + } + + public int hashCode() + { + return value; + } + + public boolean equals(Object other) + { + return (other instanceof TotalDigitsFacet && + ((TotalDigitsFacet) other).value == value); + } + +} + diff --git a/gnu/xml/validation/datatype/Type.java b/gnu/xml/validation/datatype/Type.java new file mode 100644 index 000000000..e0662761f --- /dev/null +++ b/gnu/xml/validation/datatype/Type.java @@ -0,0 +1,65 @@ +/* Type.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.HashMap; +import java.util.Map; +import javax.xml.namespace.QName; +/** + * Abstract base class for XML Schema datatypes. + * @see http://www.w3.org/TR/xmlschema-2/ + * + * @author Chris Burdess + */ +public abstract class Type +{ + + public static final Type ANY_TYPE = new AnyType(); + + /** + * The name of this type. + */ + public final QName name; + + public Type(QName name) + { + this.name = name; + } + +} + diff --git a/gnu/xml/validation/datatype/TypeBuilder.java b/gnu/xml/validation/datatype/TypeBuilder.java new file mode 100644 index 000000000..606fd0e62 --- /dev/null +++ b/gnu/xml/validation/datatype/TypeBuilder.java @@ -0,0 +1,279 @@ +/* TypeBuilder.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.LinkedHashSet; +import java.util.regex.Pattern; +import javax.xml.namespace.QName; +import org.relaxng.datatype.Datatype; +import org.relaxng.datatype.DatatypeBuilder; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * Datatype builder. + * + * @author Chris Burdess + */ +public class TypeBuilder + implements DatatypeBuilder +{ + + final SimpleType type; + + TypeBuilder(SimpleType type) + { + this.type = type; + // TODO fundamental facets + type.facets = new LinkedHashSet(); + } + + public void addParameter(String name, String value, ValidationContext context) + throws DatatypeException + { + // TODO fundamental facets + if ("length".equals(name)) + type.facets.add(parseLengthFacet(value)); + else if ("minLength".equals(name)) + type.facets.add(parseMinLengthFacet(value)); + else if ("maxLength".equals(name)) + type.facets.add(parseMaxLengthFacet(value)); + else if ("pattern".equals(name)) + type.facets.add(parsePatternFacet(value)); + else if ("enumeration".equals(name)) + type.facets.add(parseEnumerationFacet(value)); + else if ("whiteSpace".equals(name)) + type.facets.add(parseWhiteSpaceFacet(value)); + else if ("maxInclusive".equals(name)) + type.facets.add(parseMaxInclusiveFacet(value, context)); + else if ("maxExclusive".equals(name)) + type.facets.add(parseMaxExclusiveFacet(value, context)); + else if ("minExclusive".equals(name)) + type.facets.add(parseMinExclusiveFacet(value, context)); + else if ("minInclusive".equals(name)) + type.facets.add(parseMinInclusiveFacet(value, context)); + else if ("totalDigits".equals(name)) + type.facets.add(parseTotalDigitsFacet(value)); + else if ("fractionDigits".equals(name)) + type.facets.add(parseFractionDigitsFacet(value)); + } + + LengthFacet parseLengthFacet(String value) + throws DatatypeException + { + int si = value.indexOf(' '); + boolean fixed = false; + if (si != -1) + { + if (!"FIXED".equalsIgnoreCase(value.substring(si + 1))) + throw new DatatypeException("second argument must be FIXED if present"); + fixed = true; + value = value.substring(0, si); + } + return new LengthFacet(Integer.parseInt(value), fixed, null); + } + + MinLengthFacet parseMinLengthFacet(String value) + throws DatatypeException + { + int si = value.indexOf(' '); + boolean fixed = false; + if (si != -1) + { + if (!"FIXED".equalsIgnoreCase(value.substring(si + 1))) + throw new DatatypeException("second argument must be FIXED if present"); + fixed = true; + value = value.substring(0, si); + } + return new MinLengthFacet(Integer.parseInt(value), fixed, null); + } + + MaxLengthFacet parseMaxLengthFacet(String value) + throws DatatypeException + { + int si = value.indexOf(' '); + boolean fixed = false; + if (si != -1) + { + if (!"FIXED".equalsIgnoreCase(value.substring(si + 1))) + throw new DatatypeException("second argument must be FIXED if present"); + fixed = true; + value = value.substring(0, si); + } + return new MaxLengthFacet(Integer.parseInt(value), fixed, null); + } + + PatternFacet parsePatternFacet(String value) + throws DatatypeException + { + return new PatternFacet(Pattern.compile(value), null); + } + + EnumerationFacet parseEnumerationFacet(String value) + throws DatatypeException + { + return new EnumerationFacet(value, null); + } + + WhiteSpaceFacet parseWhiteSpaceFacet(String value) + throws DatatypeException + { + int si = value.indexOf(' '); + boolean fixed = false; + if (si != -1) + { + if (!"FIXED".equalsIgnoreCase(value.substring(si + 1))) + throw new DatatypeException("second argument must be FIXED if present"); + fixed = true; + value = value.substring(0, si); + } + if ("preserve".equals(value)) + return new WhiteSpaceFacet(WhiteSpaceFacet.PRESERVE, fixed, null); + if ("replace".equals(value)) + return new WhiteSpaceFacet(WhiteSpaceFacet.REPLACE, fixed, null); + if ("collapse".equals(value)) + return new WhiteSpaceFacet(WhiteSpaceFacet.COLLAPSE, fixed, null); + throw new DatatypeException("argument must be preserve, replace, or collapse"); + } + + MaxInclusiveFacet parseMaxInclusiveFacet(String value, + ValidationContext context) + throws DatatypeException + { + int si = value.indexOf(' '); + boolean fixed = false; + if (si != -1) + { + if (!"FIXED".equalsIgnoreCase(value.substring(si + 1))) + throw new DatatypeException("second argument must be FIXED if present"); + fixed = true; + value = value.substring(0, si); + } + return new MaxInclusiveFacet(type.createValue(value, context), fixed, null); + } + + MaxExclusiveFacet parseMaxExclusiveFacet(String value, + ValidationContext context) + throws DatatypeException + { + int si = value.indexOf(' '); + boolean fixed = false; + if (si != -1) + { + if (!"FIXED".equalsIgnoreCase(value.substring(si + 1))) + throw new DatatypeException("second argument must be FIXED if present"); + fixed = true; + value = value.substring(0, si); + } + return new MaxExclusiveFacet(type.createValue(value, context), fixed, null); + } + + MinExclusiveFacet parseMinExclusiveFacet(String value, + ValidationContext context) + throws DatatypeException + { + int si = value.indexOf(' '); + boolean fixed = false; + if (si != -1) + { + if (!"FIXED".equalsIgnoreCase(value.substring(si + 1))) + throw new DatatypeException("second argument must be FIXED if present"); + fixed = true; + value = value.substring(0, si); + } + return new MinExclusiveFacet(type.createValue(value, context), fixed, null); + } + + MinInclusiveFacet parseMinInclusiveFacet(String value, + ValidationContext context) + throws DatatypeException + { + int si = value.indexOf(' '); + boolean fixed = false; + if (si != -1) + { + if (!"FIXED".equalsIgnoreCase(value.substring(si + 1))) + throw new DatatypeException("second argument must be FIXED if present"); + fixed = true; + value = value.substring(0, si); + } + return new MinInclusiveFacet(type.createValue(value, context), fixed, null); + } + + TotalDigitsFacet parseTotalDigitsFacet(String value) + throws DatatypeException + { + int si = value.indexOf(' '); + boolean fixed = false; + if (si != -1) + { + if (!"FIXED".equalsIgnoreCase(value.substring(si + 1))) + throw new DatatypeException("second argument must be FIXED if present"); + fixed = true; + value = value.substring(0, si); + } + int val = Integer.parseInt(value); + if (val < 0) + throw new DatatypeException("value must be a positiveInteger"); + return new TotalDigitsFacet(val, fixed, null); + } + + FractionDigitsFacet parseFractionDigitsFacet(String value) + throws DatatypeException + { + int si = value.indexOf(' '); + boolean fixed = false; + if (si != -1) + { + if (!"FIXED".equalsIgnoreCase(value.substring(si + 1))) + throw new DatatypeException("second argument must be FIXED if present"); + fixed = true; + value = value.substring(0, si); + } + int val = Integer.parseInt(value); + if (val < 0) + throw new DatatypeException("value must be a positiveInteger"); + return new FractionDigitsFacet(val, fixed, null); + } + + public Datatype createDatatype() + { + return type; + } + +} diff --git a/gnu/xml/validation/datatype/TypeLibrary.java b/gnu/xml/validation/datatype/TypeLibrary.java new file mode 100644 index 000000000..f1daecebd --- /dev/null +++ b/gnu/xml/validation/datatype/TypeLibrary.java @@ -0,0 +1,173 @@ +/* TypeLibrary.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.HashMap; +import java.util.Map; +import org.relaxng.datatype.Datatype; +import org.relaxng.datatype.DatatypeBuilder; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.DatatypeLibrary; + +/** + * Datatype library for XML Schema datatypes. + * + * @author Chris Burdess + */ +public class TypeLibrary + implements DatatypeLibrary +{ + + public static final SimpleType ANY_SIMPLE_TYPE = new AnySimpleType(); + + public static final SimpleType STRING = new StringType(); + public static final SimpleType BOOLEAN = new BooleanType(); + public static final SimpleType DECIMAL = new DecimalType(); + public static final SimpleType FLOAT = new FloatType(); + public static final SimpleType DOUBLE = new DoubleType(); + public static final SimpleType DURATION = new DurationType(); + public static final SimpleType DATE_TIME = new DateTimeType(); + public static final SimpleType TIME = new TimeType(); + public static final SimpleType DATE = new DateType(); + public static final SimpleType G_YEAR_MONTH = new GYearMonthType(); + public static final SimpleType G_YEAR = new GYearType(); + public static final SimpleType G_MONTH_DAY = new GMonthDayType(); + public static final SimpleType G_DAY = new GDayType(); + public static final SimpleType G_MONTH = new GMonthType(); + public static final SimpleType HEX_BINARY = new HexBinaryType(); + public static final SimpleType BASE64_BINARY = new Base64BinaryType(); + public static final SimpleType ANY_URI = new AnyURIType(); + public static final SimpleType QNAME = new QNameType(); + public static final SimpleType NOTATION = new NotationType(); + + public static final SimpleType NORMALIZED_STRING = new NormalizedStringType(); + public static final SimpleType TOKEN = new TokenType(); + public static final SimpleType LANGUAGE = new LanguageType(); + public static final SimpleType NMTOKEN = new NMTokenType(); + public static final SimpleType NMTOKENS = new NMTokensType(); + public static final SimpleType NAME = new NameType(); + public static final SimpleType NCNAME = new NCNameType(); + public static final SimpleType ID = new IDType(); + public static final SimpleType IDREF = new IDRefType(); + public static final SimpleType IDREFS = new IDRefsType(); + public static final SimpleType ENTITY = new EntityType(); + public static final SimpleType ENTITIES = new EntitiesType(); + public static final SimpleType INTEGER = new IntegerType(); + public static final SimpleType NON_POSITIVE_INTEGER = new NonPositiveIntegerType(); + public static final SimpleType NEGATIVE_INTEGER = new NegativeIntegerType(); + public static final SimpleType LONG = new LongType(); + public static final SimpleType INT = new IntType(); + public static final SimpleType SHORT = new ShortType(); + public static final SimpleType BYTE = new ByteType(); + public static final SimpleType NON_NEGATIVE_INTEGER = new NonNegativeIntegerType(); + public static final SimpleType UNSIGNED_LONG = new UnsignedLongType(); + public static final SimpleType UNSIGNED_INT = new UnsignedIntType(); + public static final SimpleType UNSIGNED_SHORT = new UnsignedShortType(); + public static final SimpleType UNSIGNED_BYTE = new UnsignedByteType(); + public static final SimpleType POSITIVE_INTEGER = new PositiveIntegerType(); + + private static Map byName; + static + { + byName = new HashMap(); + byName.put("anySimpleType", ANY_SIMPLE_TYPE); + byName.put("string", STRING); + byName.put("boolean", BOOLEAN); + byName.put("decimal", DECIMAL); + byName.put("float", FLOAT); + byName.put("double", DOUBLE); + byName.put("duration", DURATION); + byName.put("dateTime", DATE_TIME); + byName.put("time", TIME); + byName.put("date", DATE); + byName.put("gYearMonth", G_YEAR_MONTH); + byName.put("gYear", G_YEAR); + byName.put("gMonthDay", G_MONTH_DAY); + byName.put("gDay", G_DAY); + byName.put("gMonth",G_MONTH); + byName.put("hexBinary", HEX_BINARY); + byName.put("base64Binary", BASE64_BINARY); + byName.put("anyURI", ANY_URI); + byName.put("QName", QNAME); + byName.put("NOTATION", NOTATION); + byName.put("normalizedString", NORMALIZED_STRING); + byName.put("token", TOKEN); + byName.put("language", LANGUAGE); + byName.put("NMTOKEN", NMTOKEN); + byName.put("NMTOKENS", NMTOKENS); + byName.put("Name", NAME); + byName.put("NCName", NCNAME); + byName.put("ID", ID); + byName.put("IDREF", IDREF); + byName.put("IDREFS", IDREFS); + byName.put("ENTITY", ENTITY); + byName.put("ENTITIES", ENTITIES); + byName.put("integer", INTEGER); + byName.put("nonPositiveInteger", NON_POSITIVE_INTEGER); + byName.put("negativeInteger", NEGATIVE_INTEGER); + byName.put("long", LONG); + byName.put("int", INT); + byName.put("short", SHORT); + byName.put("byte", BYTE); + byName.put("nonNegativeInteger", NON_NEGATIVE_INTEGER); + byName.put("unsignedLong", UNSIGNED_LONG); + byName.put("unsignedInt", UNSIGNED_INT); + byName.put("unsignedShort", UNSIGNED_SHORT); + byName.put("unsignedByte", UNSIGNED_BYTE); + byName.put("positiveInteger", POSITIVE_INTEGER); + } + + public DatatypeBuilder createDatatypeBuilder(String baseTypeLocalName) + throws DatatypeException + { + SimpleType type = (SimpleType) byName.get(baseTypeLocalName); + if (type == null) + throw new DatatypeException("Unknown type name: " + baseTypeLocalName); + return new TypeBuilder(type); + } + + public Datatype createDatatype(String typeLocalName) + throws DatatypeException + { + SimpleType type = (SimpleType) byName.get(typeLocalName); + if (type == null) + throw new DatatypeException("Unknown type name: " + typeLocalName); + return type; + } + +} diff --git a/gnu/xml/validation/datatype/TypeLibraryFactory.java b/gnu/xml/validation/datatype/TypeLibraryFactory.java new file mode 100644 index 000000000..21ee64224 --- /dev/null +++ b/gnu/xml/validation/datatype/TypeLibraryFactory.java @@ -0,0 +1,60 @@ +/* TypeLibraryFactory.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import org.relaxng.datatype.DatatypeLibrary; +import org.relaxng.datatype.DatatypeLibraryFactory; + +/** + * Datatype library factory for XML Schema datatypes. + * + * @author Chris Burdess + */ +public class TypeLibraryFactory + implements DatatypeLibraryFactory +{ + + public DatatypeLibrary createDatatypeLibrary(String namespaceURI) + { + if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(namespaceURI)) + return new TypeLibrary(); + return null; + } + +} diff --git a/gnu/xml/validation/datatype/UnionSimpleType.java b/gnu/xml/validation/datatype/UnionSimpleType.java new file mode 100644 index 000000000..d87c2aa7a --- /dev/null +++ b/gnu/xml/validation/datatype/UnionSimpleType.java @@ -0,0 +1,83 @@ +/* UnionSimpleType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * An XML Schema union simple type. + * + * @author Chris Burdess + */ +public class UnionSimpleType + extends SimpleType +{ + + /** + * The member types in this union. + */ + public final List memberTypes; + + public UnionSimpleType(QName name, Set facets, + int fundamentalFacets, SimpleType baseType, + Annotation annotation, List memberTypes) + { + super(name, UNION, facets, fundamentalFacets, baseType, annotation); + this.memberTypes = memberTypes; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + for (Iterator i = memberTypes.iterator(); i.hasNext(); ) + { + SimpleType type = (SimpleType) i.next(); + if (type.isValid(value, context)) + return; + } + throw new DatatypeException("invalid union type value"); + } + +} + diff --git a/gnu/xml/validation/datatype/UnsignedByteType.java b/gnu/xml/validation/datatype/UnsignedByteType.java new file mode 100644 index 000000000..772c9cc0a --- /dev/null +++ b/gnu/xml/validation/datatype/UnsignedByteType.java @@ -0,0 +1,121 @@ +/* UnsignedByteType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema unsignedByte type. + * + * @author Chris Burdess + */ +final class UnsignedByteType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + static final String MAX_VALUE = "255"; + static final int LENGTH = MAX_VALUE.length(); + + UnsignedByteType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "unsignedByte"), + TypeLibrary.UNSIGNED_SHORT); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid unsigned byte value"); + boolean compare = false; + for (int i = 0; i < len; i++) + { + if (len - i > LENGTH) + throw new DatatypeException(i, "invalid unsigned byte value"); + else if (len - i == LENGTH) + compare = true; + char c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + { + if (compare) + { + char d = MAX_VALUE.charAt(i); + if (Character.digit(c, 10) > Character.digit(d, 10)) + throw new DatatypeException(i, "invalid unsigned byte value"); + } + continue; + } + throw new DatatypeException(i, "invalid unsigned byte value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new Byte(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/UnsignedIntType.java b/gnu/xml/validation/datatype/UnsignedIntType.java new file mode 100644 index 000000000..a4e8a6820 --- /dev/null +++ b/gnu/xml/validation/datatype/UnsignedIntType.java @@ -0,0 +1,121 @@ +/* UnsignedIntType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema unsignedInt type. + * + * @author Chris Burdess + */ +final class UnsignedIntType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + static final String MAX_VALUE = "4294967295"; + static final int LENGTH = MAX_VALUE.length(); + + UnsignedIntType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "unsignedInt"), + TypeLibrary.UNSIGNED_LONG); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid unsigned int value"); + boolean compare = false; + for (int i = 0; i < len; i++) + { + if (len - i > LENGTH) + throw new DatatypeException(i, "invalid unsigned int value"); + else if (len - i == LENGTH) + compare = true; + char c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + { + if (compare) + { + char d = MAX_VALUE.charAt(i); + if (Character.digit(c, 10) > Character.digit(d, 10)) + throw new DatatypeException(i, "invalid unsigned int value"); + } + continue; + } + throw new DatatypeException(i, "invalid unsigned int value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new Integer(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/UnsignedLongType.java b/gnu/xml/validation/datatype/UnsignedLongType.java new file mode 100644 index 000000000..5a36d8a31 --- /dev/null +++ b/gnu/xml/validation/datatype/UnsignedLongType.java @@ -0,0 +1,121 @@ +/* UnsignedLongType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema unsignedLong type. + * + * @author Chris Burdess + */ +final class UnsignedLongType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + static final String MAX_VALUE = "18446744073709551615"; + static final int LENGTH = MAX_VALUE.length(); + + UnsignedLongType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "unsignedLong"), + TypeLibrary.NON_NEGATIVE_INTEGER); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid unsigned long value"); + boolean compare = false; + for (int i = 0; i < len; i++) + { + if (len - i > LENGTH) + throw new DatatypeException(i, "invalid unsigned long value"); + else if (len - i == LENGTH) + compare = true; + char c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + { + if (compare) + { + char d = MAX_VALUE.charAt(i); + if (Character.digit(c, 10) > Character.digit(d, 10)) + throw new DatatypeException(i, "invalid unsigned long value"); + } + continue; + } + throw new DatatypeException(i, "invalid unsigned long value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new Long(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/UnsignedShortType.java b/gnu/xml/validation/datatype/UnsignedShortType.java new file mode 100644 index 000000000..49f621be7 --- /dev/null +++ b/gnu/xml/validation/datatype/UnsignedShortType.java @@ -0,0 +1,122 @@ +/* UnsignedShortType.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import org.relaxng.datatype.DatatypeException; +import org.relaxng.datatype.ValidationContext; + +/** + * The XML Schema unsignedShort type. + * + * @author Chris Burdess + */ +final class UnsignedShortType + extends AtomicSimpleType +{ + + static final int[] CONSTRAINING_FACETS = { + Facet.TOTAL_DIGITS, + Facet.FRACTION_DIGITS, + Facet.PATTERN, + Facet.WHITESPACE, + Facet.ENUMERATION, + Facet.MAX_INCLUSIVE, + Facet.MAX_EXCLUSIVE, + Facet.MIN_INCLUSIVE, + Facet.MIN_EXCLUSIVE + }; + + static final String MAX_VALUE = "65535"; + static final int LENGTH = MAX_VALUE.length(); + + UnsignedShortType() + { + super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "unsignedShort"), + TypeLibrary.UNSIGNED_INT); + } + + public int[] getConstrainingFacets() + { + return CONSTRAINING_FACETS; + } + + public void checkValid(String value, ValidationContext context) + throws DatatypeException + { + super.checkValid(value, context); + int len = value.length(); + if (len == 0) + throw new DatatypeException(0, "invalid unsigned short value"); + boolean compare = false; + for (int i = 0; i < len; i++) + { + if (len - i > LENGTH) + throw new DatatypeException(i, "invalid unsigned short value"); + else if (len - i == LENGTH) + compare = true; + char c = value.charAt(i); + if (c >= 0x30 && c <= 0x39) + { + if (compare) + { + char d = MAX_VALUE.charAt(i); + if (Character.digit(c, 10) > Character.digit(d, 10)) + throw new DatatypeException(i, + "invalid unsigned short value"); + } + continue; + } + throw new DatatypeException(i, "invalid unsigned short value"); + } + } + + public Object createValue(String literal, ValidationContext context) { + try + { + return new Short(literal); + } + catch (NumberFormatException e) + { + return null; + } + } + +} + diff --git a/gnu/xml/validation/datatype/WhiteSpaceFacet.java b/gnu/xml/validation/datatype/WhiteSpaceFacet.java new file mode 100644 index 000000000..5920e1c88 --- /dev/null +++ b/gnu/xml/validation/datatype/WhiteSpaceFacet.java @@ -0,0 +1,75 @@ +/* WhiteSpaceFacet.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.xml.validation.datatype; + +/** + * The whiteSpace facet. + * + * @author Chris Burdess + */ +public final class WhiteSpaceFacet + extends Facet +{ + + public static final int PRESERVE = 0; + public static final int REPLACE = 1; + public static final int COLLAPSE = 2; + + public final int value; + public final boolean fixed; + + public WhiteSpaceFacet(int value, boolean fixed, Annotation annotation) + { + super(WHITESPACE, annotation); + this.value = value; + this.fixed = fixed; + } + + public int hashCode() + { + return value; + } + + public boolean equals(Object other) + { + return (other instanceof WhiteSpaceFacet && + ((WhiteSpaceFacet) other).value == value); + } + +} + diff --git a/gnu/xml/xpath/LangFunction.java b/gnu/xml/xpath/LangFunction.java index 2c2506d1b..584787efb 100644 --- a/gnu/xml/xpath/LangFunction.java +++ b/gnu/xml/xpath/LangFunction.java @@ -1,5 +1,5 @@ /* LangFunction.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -91,9 +91,15 @@ final class LangFunction String getLang(Node node) { - if (node.getNodeType() == Node.ELEMENT_NODE) + while (node != null) { - return ((Element) node).getAttribute("xml:lang"); + if (node.getNodeType() == Node.ELEMENT_NODE) + { + String lang = ((Element) node).getAttribute("xml:lang"); + if (lang != null) + return lang; + } + node = node.getParentNode(); } return null; } diff --git a/gnu/xml/xpath/NodeTypeTest.java b/gnu/xml/xpath/NodeTypeTest.java index 09e92d0d9..4fe164625 100644 --- a/gnu/xml/xpath/NodeTypeTest.java +++ b/gnu/xml/xpath/NodeTypeTest.java @@ -84,6 +84,7 @@ public final class NodeTypeTest case Node.TEXT_NODE: case Node.CDATA_SECTION_NODE: case Node.COMMENT_NODE: + case Node.DOCUMENT_NODE: if (type > 0) { if (nodeType != type) diff --git a/gnu/xml/xpath/Selector.java b/gnu/xml/xpath/Selector.java index 93408e48b..c7abb33e2 100644 --- a/gnu/xml/xpath/Selector.java +++ b/gnu/xml/xpath/Selector.java @@ -90,7 +90,7 @@ public final class Selector if (len > 0) tests.toArray(this.tests); else - this.tests[0] = new NameTest(null, true, true); + this.tests[0] = new NodeTypeTest((short) 0); if (axis == NAMESPACE && this.tests[0] instanceof NameTest) { NameTest nt = (NameTest) this.tests[0]; @@ -107,6 +107,14 @@ public final class Selector } public boolean matches(Node context) + { + // If called directly, selector is the top level of the path + return matches(context, + getContextPosition(context), + getContextSize(context)); + } + + boolean matches(Node context, int pos, int len) { short nodeType = context.getNodeType(); switch (axis) @@ -125,19 +133,11 @@ public final class Selector default: return false; } - int tlen = tests.length; - if (tlen > 0) + for (int j = 0; j < tests.length && len > 0; j++) { - int pos = getContextPosition(context); - int len = getContextSize(context); - if (len == 0) - System.err.println("WARNING: context size is 0"); - for (int j = 0; j < tlen && len > 0; j++) - { - Test test = tests[j]; - if (!test.matches(context, pos, len)) - return false; - } + Test test = tests[j]; + if (!test.matches(context, pos, len)) + return false; } return true; } @@ -147,7 +147,10 @@ public final class Selector int pos = 1; for (ctx = ctx.getPreviousSibling(); ctx != null; ctx = ctx.getPreviousSibling()) - pos++; + { + if (tests[0].matches(ctx, 1, 1)) + pos++; + } return pos; } @@ -161,10 +164,16 @@ public final class Selector int count = 1; Node sib = ctx.getPreviousSibling(); for (; sib != null; sib = sib.getPreviousSibling()) - count++; + { + if (tests[0].matches(ctx, 1, 1)) + count++; + } sib = ctx.getNextSibling(); for (; sib != null; sib = sib.getNextSibling()) - count++; + { + if (tests[0].matches(ctx, 1, 1)) + count++; + } return count; } diff --git a/include/Makefile.am b/include/Makefile.am index f829ba4ea..0517e125a 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -127,9 +127,9 @@ $(top_srcdir)/include/gnu_java_nio_charset_iconv_IconvDecoder.h \ $(top_srcdir)/include/java_io_VMFile.h \ $(top_srcdir)/include/java_io_VMObjectInputStream.h \ $(top_srcdir)/include/java_io_VMObjectStreamClass.h \ -$(top_srcdir)/include/java_lang_Math.h \ $(top_srcdir)/include/java_lang_VMDouble.h \ $(top_srcdir)/include/java_lang_VMFloat.h \ +$(top_srcdir)/include/java_lang_VMMath.h \ $(top_srcdir)/include/java_lang_VMProcess.h \ $(top_srcdir)/include/java_lang_VMSystem.h \ $(top_srcdir)/include/java_lang_reflect_Array.h \ @@ -178,8 +178,8 @@ $(top_srcdir)/include/java_io_VMObjectInputStream.h: $(top_srcdir)/vm/reference/ $(JAVAH) -o $@ java.io.VMObjectInputStream $(top_srcdir)/include/java_io_VMObjectStreamClass.h: $(top_srcdir)/vm/reference/java/io/VMObjectStreamClass.java $(JAVAH) -o $@ java.io.VMObjectStreamClass -$(top_srcdir)/include/java_lang_Math.h: $(top_srcdir)/java/lang/Math.java - $(JAVAH) -o $@ java.lang.Math +$(top_srcdir)/include/java_lang_VMMath.h: $(top_srcdir)/vm/reference/java/lang/VMMath.java + $(JAVAH) -o $@ java.lang.VMMath $(top_srcdir)/include/java_lang_VMDouble.h: $(top_srcdir)/vm/reference/java/lang/VMDouble.java $(JAVAH) -o $@ java.lang.VMDouble $(top_srcdir)/include/java_lang_VMFloat.h: $(top_srcdir)/vm/reference/java/lang/VMFloat.java diff --git a/include/gnu_java_awt_peer_gtk_GtkMenuBarPeer.h b/include/gnu_java_awt_peer_gtk_GtkMenuBarPeer.h index 6d855be66..61a4641e6 100644 --- a/include/gnu_java_awt_peer_gtk_GtkMenuBarPeer.h +++ b/include/gnu_java_awt_peer_gtk_GtkMenuBarPeer.h @@ -12,7 +12,6 @@ extern "C" JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_create (JNIEnv *env, jobject); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_addMenu (JNIEnv *env, jobject, jobject); -JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_nativeSetHelpMenu (JNIEnv *env, jobject, jobject); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_delMenu (JNIEnv *env, jobject, jint); #ifdef __cplusplus diff --git a/include/gnu_java_awt_peer_gtk_GtkScrollbarPeer.h b/include/gnu_java_awt_peer_gtk_GtkScrollbarPeer.h index b3e52027b..397035010 100644 --- a/include/gnu_java_awt_peer_gtk_GtkScrollbarPeer.h +++ b/include/gnu_java_awt_peer_gtk_GtkScrollbarPeer.h @@ -14,7 +14,7 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_create (JNIEn JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_connectSignals (JNIEnv *env, jobject); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_setLineIncrement (JNIEnv *env, jobject, jint); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_setPageIncrement (JNIEnv *env, jobject, jint); -JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_setValues (JNIEnv *env, jobject, jint, jint, jint, jint); +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkScrollbarPeer_setBarValues (JNIEnv *env, jobject, jint, jint, jint, jint); #ifdef __cplusplus } diff --git a/include/gnu_java_awt_peer_gtk_GtkTextFieldPeer.h b/include/gnu_java_awt_peer_gtk_GtkTextFieldPeer.h index a3b3c4dcd..260c2d75a 100644 --- a/include/gnu_java_awt_peer_gtk_GtkTextFieldPeer.h +++ b/include/gnu_java_awt_peer_gtk_GtkTextFieldPeer.h @@ -23,7 +23,6 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_select (JNIEn JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_setEditable (JNIEnv *env, jobject, jboolean); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_setText (JNIEnv *env, jobject, jstring); JNIEXPORT jint JNICALL Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_gtkEntryGetBorderWidth (JNIEnv *env, jobject); -JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_gtkWidgetModifyFont (JNIEnv *env, jobject, jstring, jint, jint); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_setEchoChar (JNIEnv *env, jobject, jchar); #ifdef __cplusplus diff --git a/include/gnu_java_awt_peer_gtk_GtkWindowPeer.h b/include/gnu_java_awt_peer_gtk_GtkWindowPeer.h index 1d80f0a82..ad447f16a 100644 --- a/include/gnu_java_awt_peer_gtk_GtkWindowPeer.h +++ b/include/gnu_java_awt_peer_gtk_GtkWindowPeer.h @@ -22,6 +22,8 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toBack (JNIEnv * JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_toFront (JNIEnv *env, jobject); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetBounds (JNIEnv *env, jobject, jint, jint, jint, jint); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetBoundsUnlocked (JNIEnv *env, jobject, jint, jint, jint, jint); +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetLocation (JNIEnv *env, jobject, jint, jint); +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetLocationUnlocked (JNIEnv *env, jobject, jint, jint); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_setSize (JNIEnv *env, jobject, jint, jint); #undef gnu_java_awt_peer_gtk_GtkWindowPeer_GDK_WINDOW_TYPE_HINT_NORMAL #define gnu_java_awt_peer_gtk_GtkWindowPeer_GDK_WINDOW_TYPE_HINT_NORMAL 0L diff --git a/include/java_lang_Math.h b/include/java_lang_Math.h deleted file mode 100644 index 26fa62bea..000000000 --- a/include/java_lang_Math.h +++ /dev/null @@ -1,37 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ - -#ifndef __java_lang_Math__ -#define __java_lang_Math__ - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -JNIEXPORT jdouble JNICALL Java_java_lang_Math_sin (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_cos (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_tan (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_asin (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_acos (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_atan (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_atan2 (JNIEnv *env, jclass, jdouble, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_exp (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_log (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_sqrt (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_pow (JNIEnv *env, jclass, jdouble, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_IEEEremainder (JNIEnv *env, jclass, jdouble, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_ceil (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_floor (JNIEnv *env, jclass, jdouble); -JNIEXPORT jdouble JNICALL Java_java_lang_Math_rint (JNIEnv *env, jclass, jdouble); -#undef java_lang_Math_E -#define java_lang_Math_E 0x1.5bf0a8b145769p+1 -#undef java_lang_Math_PI -#define java_lang_Math_PI 0x1.921fb54442d18p+1 - -#ifdef __cplusplus -} -#endif - -#endif /* __java_lang_Math__ */ diff --git a/include/java_lang_VMMath.h b/include/java_lang_VMMath.h new file mode 100644 index 000000000..b2a2c3b46 --- /dev/null +++ b/include/java_lang_VMMath.h @@ -0,0 +1,41 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ + +#ifndef __java_lang_VMMath__ +#define __java_lang_VMMath__ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_sin (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_cos (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_tan (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_asin (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_acos (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_atan (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_atan2 (JNIEnv *env, jclass, jdouble, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_exp (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_log (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_sqrt (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_pow (JNIEnv *env, jclass, jdouble, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_IEEEremainder (JNIEnv *env, jclass, jdouble, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_ceil (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_floor (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_rint (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_cbrt (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_cosh (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_expm1 (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_hypot (JNIEnv *env, jclass, jdouble, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_log10 (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_log1p (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_sinh (JNIEnv *env, jclass, jdouble); +JNIEXPORT jdouble JNICALL Java_java_lang_VMMath_tanh (JNIEnv *env, jclass, jdouble); + +#ifdef __cplusplus +} +#endif + +#endif /* __java_lang_VMMath__ */ diff --git a/java/awt/AWTEvent.java b/java/awt/AWTEvent.java index ad9533f9c..d10433cb3 100644 --- a/java/awt/AWTEvent.java +++ b/java/awt/AWTEvent.java @@ -39,6 +39,19 @@ exception statement from your version. */ package java.awt; +import java.awt.event.ActionEvent; +import java.awt.event.AdjustmentEvent; +import java.awt.event.ComponentEvent; +import java.awt.event.ContainerEvent; +import java.awt.event.FocusEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.InvocationEvent; +import java.awt.event.ItemEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.PaintEvent; +import java.awt.event.TextEvent; +import java.awt.event.WindowEvent; import java.util.EventObject; /** @@ -275,4 +288,94 @@ public abstract class AWTEvent extends EventObject { return consumed; } + + /** + * Converts an event id to the appropriate event mask. + * + * @param id the event id + * + * @return the event mask for the specified id + */ + static long eventIdToMask(int id) + { + long mask = 0; + switch (id) + { + case ActionEvent.ACTION_PERFORMED: + mask = ACTION_EVENT_MASK; + break; + case AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED: + mask = ADJUSTMENT_EVENT_MASK; + break; + case ComponentEvent.COMPONENT_MOVED: + case ComponentEvent.COMPONENT_RESIZED: + case ComponentEvent.COMPONENT_SHOWN: + case ComponentEvent.COMPONENT_HIDDEN: + mask = COMPONENT_EVENT_MASK; + break; + case ContainerEvent.COMPONENT_ADDED: + case ContainerEvent.COMPONENT_REMOVED: + mask = CONTAINER_EVENT_MASK; + break; + case FocusEvent.FOCUS_GAINED: + case FocusEvent.FOCUS_LOST: + mask = FOCUS_EVENT_MASK; + break; + case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: + case InputMethodEvent.CARET_POSITION_CHANGED: + mask = INPUT_METHOD_EVENT_MASK; + break; + case InvocationEvent.INVOCATION_DEFAULT: + mask = INVOCATION_EVENT_MASK; + break; + case ItemEvent.ITEM_STATE_CHANGED: + mask = ITEM_EVENT_MASK; + break; + case KeyEvent.KEY_TYPED: + case KeyEvent.KEY_PRESSED: + case KeyEvent.KEY_RELEASED: + mask = KEY_EVENT_MASK; + break; + case MouseEvent.MOUSE_CLICKED: + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + mask = MOUSE_EVENT_MASK; + break; + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + case MouseEvent.MOUSE_DRAGGED: + mask = MOUSE_MOTION_EVENT_MASK; + break; + case MouseEvent.MOUSE_WHEEL: + mask = MOUSE_WHEEL_EVENT_MASK; + break; + case PaintEvent.PAINT: + case PaintEvent.UPDATE: + mask = PAINT_EVENT_MASK; + break; + case TextEvent.TEXT_VALUE_CHANGED: + mask = TEXT_EVENT_MASK; + break; + case WindowEvent.WINDOW_OPENED: + case WindowEvent.WINDOW_CLOSING: + case WindowEvent.WINDOW_CLOSED: + case WindowEvent.WINDOW_ICONIFIED: + case WindowEvent.WINDOW_DEICONIFIED: + case WindowEvent.WINDOW_ACTIVATED: + case WindowEvent.WINDOW_DEACTIVATED: + mask = WINDOW_EVENT_MASK; + break; + case WindowEvent.WINDOW_GAINED_FOCUS: + case WindowEvent.WINDOW_LOST_FOCUS: + mask = WINDOW_FOCUS_EVENT_MASK; + break; + case WindowEvent.WINDOW_STATE_CHANGED: + mask = WINDOW_STATE_EVENT_MASK; + break; + default: + mask = 0; + } + return mask; + } } // class AWTEvent diff --git a/java/awt/BasicStroke.java b/java/awt/BasicStroke.java index bb008e4c7..4eece75c9 100644 --- a/java/awt/BasicStroke.java +++ b/java/awt/BasicStroke.java @@ -1,5 +1,5 @@ /* BasicStroke.java -- - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,38 +41,89 @@ package java.awt; import java.util.Arrays; /** - * STUB CLASS ONLY + * A general purpose {@link Stroke} implementation that can represent a wide + * variety of line styles for use with subclasses of {@link Graphics2D}. + *

    + * The line cap and join styles can be set using the options illustrated + * here: + *

    + * Illustration of line cap and join styles + *

    + * A dash array can be used to specify lines with alternating opaque and + * transparent sections. */ public class BasicStroke implements Stroke { + /** + * Indicates a mitered line join style. See the class overview for an + * illustration. + */ public static final int JOIN_MITER = 0; + + /** + * Indicates a rounded line join style. See the class overview for an + * illustration. + */ public static final int JOIN_ROUND = 1; + + /** + * Indicates a bevelled line join style. See the class overview for an + * illustration. + */ public static final int JOIN_BEVEL = 2; + /** + * Indicates a flat line cap style. See the class overview for an + * illustration. + */ public static final int CAP_BUTT = 0; + + /** + * Indicates a rounded line cap style. See the class overview for an + * illustration. + */ public static final int CAP_ROUND = 1; + + /** + * Indicates a square line cap style. See the class overview for an + * illustration. + */ public static final int CAP_SQUARE = 2; + /** The stroke width. */ private final float width; + + /** The line cap style. */ private final int cap; + + /** The line join style. */ private final int join; + + /** The miter limit. */ private final float limit; + + /** The dash array. */ private final float[] dash; + + /** The dash phase. */ private final float phase; /** - * Creates a basic stroke. + * Creates a new BasicStroke instance with the given attributes. * - * @param width May not be negative . - * @param cap May be either CAP_BUTT, CAP_ROUND or CAP_SQUARE. - * @param join May be either JOIN_ROUND, JOIN_BEVEL, or JOIN_MITER. - * @param miterlimit the limit to trim the miter join. The miterlimit must be + * @param width the line width (>= 0.0f). + * @param cap the line cap style (one of {@link #CAP_BUTT}, + * {@link #CAP_ROUND} or {@link #CAP_SQUARE}). + * @param join the line join style (one of {@link #JOIN_ROUND}, + * {@link #JOIN_BEVEL}, or {@link #JOIN_MITER}). + * @param miterlimit the limit to trim the miter join. The miterlimit must be * greater than or equal to 1.0f. * @param dash The array representing the dashing pattern. There must be at * least one non-zero entry. * @param dashPhase is negative and dash is not null. * - * @exception IllegalArgumentException If one input parameter doesn't meet + * @throws IllegalArgumentException If one input parameter doesn't meet * its needs. */ public BasicStroke(float width, int cap, int join, float miterlimit, @@ -122,15 +173,17 @@ public class BasicStroke implements Stroke } /** - * Creates a basic stroke. + * Creates a new BasicStroke instance with the given attributes. * - * @param width The width of the BasicStroke. May not be negative . - * @param cap May be either CAP_BUTT, CAP_ROUND or CAP_SQUARE. - * @param join May be either JOIN_ROUND, JOIN_BEVEL, or JOIN_MITER. + * @param width the line width (>= 0.0f). + * @param cap the line cap style (one of {@link #CAP_BUTT}, + * {@link #CAP_ROUND} or {@link #CAP_SQUARE}). + * @param join the line join style (one of {@link #JOIN_ROUND}, + * {@link #JOIN_BEVEL}, or {@link #JOIN_MITER}). * @param miterlimit the limit to trim the miter join. The miterlimit must be * greater than or equal to 1.0f. * - * @exception IllegalArgumentException If one input parameter doesn't meet + * @throws IllegalArgumentException If one input parameter doesn't meet * its needs. */ public BasicStroke(float width, int cap, int join, float miterlimit) @@ -139,15 +192,17 @@ public class BasicStroke implements Stroke } /** - * Creates a basic stroke. + * Creates a new BasicStroke instance with the given attributes. + * The miter limit defaults to 10.0. * - * @param width The width of the BasicStroke. May not be nehative. - * @param cap May be either CAP_BUTT, CAP_ROUND or CAP_SQUARE. - * @param join May be either JOIN_ROUND, JOIN_BEVEL, or JOIN_MITER. + * @param width the line width (>= 0.0f). + * @param cap the line cap style (one of {@link #CAP_BUTT}, + * {@link #CAP_ROUND} or {@link #CAP_SQUARE}). + * @param join the line join style (one of {@link #JOIN_ROUND}, + * {@link #JOIN_BEVEL}, or {@link #JOIN_MITER}). * - * @exception IllegalArgumentException If one input parameter doesn't meet + * @throws IllegalArgumentException If one input parameter doesn't meet * its needs. - * @exception IllegalArgumentException FIXME */ public BasicStroke(float width, int cap, int join) { @@ -155,11 +210,17 @@ public class BasicStroke implements Stroke } /** - * Creates a basic stroke. - * - * @param width The width of the BasicStroke. + * Creates a new BasicStroke instance with the given line + * width. The default values are: + *

      + *
    • line cap style: {@link #CAP_SQUARE};
    • + *
    • line join style: {@link #JOIN_MITER};
    • + *
    • miter limit: 10.0f. + *
    + * + * @param width the line width (>= 0.0f). * - * @exception IllegalArgumentException If width is negative. + * @throws IllegalArgumentException If width is negative. */ public BasicStroke(float width) { @@ -167,43 +228,92 @@ public class BasicStroke implements Stroke } /** - * Creates a basic stroke. + * Creates a new BasicStroke instance. The default values are: + *
      + *
    • line width: 1.0f;
    • + *
    • line cap style: {@link #CAP_SQUARE};
    • + *
    • line join style: {@link #JOIN_MITER};
    • + *
    • miter limit: 10.0f. + *
    */ public BasicStroke() { this(1, CAP_SQUARE, JOIN_MITER, 10, null, 0); } + /** + * Creates a shape representing the stroked outline of the given shape. + * THIS METHOD IS NOT YET IMPLEMENTED. + * + * @param s the shape. + */ public Shape createStrokedShape(Shape s) { + // FIXME: Implement this throw new Error("not implemented"); } + /** + * Returns the line width. + * + * @return The line width. + */ public float getLineWidth() { return width; } + /** + * Returns a code indicating the line cap style (one of {@link #CAP_BUTT}, + * {@link #CAP_ROUND}, {@link #CAP_SQUARE}). + * + * @return A code indicating the line cap style. + */ public int getEndCap() { return cap; } + /** + * Returns a code indicating the line join style (one of {@link #JOIN_BEVEL}, + * {@link #JOIN_MITER} or {@link #JOIN_ROUND}). + * + * @return A code indicating the line join style. + */ public int getLineJoin() { return join; } + /** + * Returns the miter limit. + * + * @return The miter limit. + */ public float getMiterLimit() { return limit; } + /** + * Returns the dash array, which defines the length of alternate opaque and + * transparent sections in lines drawn with this stroke. If + * null, a continuous line will be drawn. + * + * @return The dash array (possibly null). + */ public float[] getDashArray() { return dash; } + /** + * Returns the dash phase for the stroke. This is the offset from the start + * of a path at which the pattern defined by {@link #getDashArray()} is + * rendered. + * + * @return The dash phase. + */ public float getDashPhase() { return phase; @@ -215,6 +325,8 @@ public class BasicStroke implements Stroke * (converted to int first with * Float.floatToIntBits() if the value is a * float). + * + * @return The hash code. */ public int hashCode() { @@ -233,9 +345,18 @@ public class BasicStroke implements Stroke } /** - * Returns true if the given Object is an instance of BasicStroke - * and the width, cap, join, limit, dash array and phase are all - * equal. + * Compares this BasicStroke for equality with an arbitrary + * object. This method returns true if and only if: + *
      + *
    • o is an instanceof BasicStroke;
    • + *
    • this object has the same width, line cap style, line join style, + * miter limit, dash array and dash phase as o.
    • + *
    + * + * @param o the object (null permitted). + * + * @return true if this stroke is equal to o and + * false otherwise. */ public boolean equals(Object o) { @@ -245,4 +366,4 @@ public class BasicStroke implements Stroke return width == s.width && cap == s.cap && join == s.join && limit == s.limit && Arrays.equals(dash, s.dash) && phase == s.phase; } -} // class BasicStroke +} diff --git a/java/awt/BorderLayout.java b/java/awt/BorderLayout.java index 7c8c582a9..50061ec67 100644 --- a/java/awt/BorderLayout.java +++ b/java/awt/BorderLayout.java @@ -460,27 +460,30 @@ public class BorderLayout implements LayoutManager2, java.io.Serializable } /** - * Lays out the specified container according to the constraints - * in this object. - * + * Lays out the specified container according to the constraints in this + * object. + * * @param target The container to lay out. */ public void layoutContainer(Container target) { - synchronized (target.getTreeLock ()) + synchronized (target.getTreeLock()) { Insets i = target.getInsets(); + int top = i.top; + int bottom = target.height - i.bottom; + int left = i.left; + int right = target.width - i.right; - ComponentOrientation orient = target.getComponentOrientation (); - boolean left_to_right = orient.isLeftToRight (); + boolean left_to_right = target.getComponentOrientation().isLeftToRight(); Component my_north = north; Component my_east = east; Component my_south = south; Component my_west = west; - // Note that we currently don't handle vertical layouts. Neither - // does JDK 1.3. + // Note that we currently don't handle vertical layouts. + // Neither does JDK 1.3. if (firstLine != null) my_north = firstLine; if (lastLine != null) @@ -500,65 +503,42 @@ public class BorderLayout implements LayoutManager2, java.io.Serializable my_west = lastItem; } - Dimension c = calcCompSize(center, PREF); - Dimension n = calcCompSize(my_north, PREF); - Dimension s = calcCompSize(my_south, PREF); - Dimension e = calcCompSize(my_east, PREF); - Dimension w = calcCompSize(my_west, PREF); - int targetWidth = target.getWidth(); - int targetHeight = target.getHeight(); - - /* - <-> hgap <-> hgap - +----------------------------+ } - |t | } i.top - | +----------------------+ | --- y1 } - | |n | | - | +----------------------+ | } vgap - | +---+ +----------+ +---+ | --- y2 } } - | |w | |c | |e | | } hh - | +---+ +----------+ +---+ | } vgap } - | +----------------------+ | --- y3 } - | |s | | - | +----------------------+ | } - | | } i.bottom - +----------------------------+ } - |x1 |x2 |x3 - <----------------------> - <--> ww <--> - i.left i.right - */ - - int x1 = i.left; - int x2 = x1 + w.width + (w.width == 0 ? 0 : hgap); - int x3; - if (targetWidth <= i.right + e.width) - x3 = x2 + w.width + (w.width == 0 ? 0 : hgap); - else - x3 = targetWidth - i.right - e.width; - int ww = targetWidth - i.right - i.left; - - int y1 = i.top; - int y2 = y1 + n.height + (n.height == 0 ? 0 : vgap); - int midh = Math.max(e.height, Math.max(w.height, c.height)); - int y3; - if (targetHeight <= i.bottom + s.height) - y3 = y2 + midh + vgap; - else - y3 = targetHeight - i.bottom - s.height; - int hh = y3-y2-(s.height == 0 ? 0 : vgap); - - setBounds(center, x2, y2, x3-x2-(w.width == 0 ? 0 : hgap), hh); - setBounds(my_north, x1, y1, ww, n.height); - setBounds(my_south, x1, y3, ww, s.height); - setBounds(my_west, x1, y2, w.width, hh); - setBounds(my_east, x3, y2, e.width, hh); + if (my_north != null) + { + Dimension n = calcCompSize(my_north, PREF); + my_north.setBounds(left, top, right - left, n.height); + top += n.height + vgap; + } + + if (my_south != null) + { + Dimension s = calcCompSize(my_south, PREF); + my_south.setBounds(left, bottom - s.height, right - left, s.height); + bottom -= s.height + vgap; + } + + if (my_east != null) + { + Dimension e = calcCompSize(my_east, PREF); + my_east.setBounds(right - e.width, top, e.width, bottom - top); + right -= e.width + hgap; + } + + if (my_west != null) + { + Dimension w = calcCompSize(my_west, PREF); + my_west.setBounds(left, top, w.width, bottom - top); + left += w.width + hgap; + } + + if (center != null) + center.setBounds(left, top, right - left, bottom - top); } } /** * Returns a string representation of this layout manager. - * + * * @return A string representation of this object. */ public String toString() @@ -566,20 +546,9 @@ public class BorderLayout implements LayoutManager2, java.io.Serializable return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]"; } - /** - * This is a convenience method to set the bounds on a component. - * If the indicated component is null, nothing is done. - */ - private void setBounds(Component comp, int x, int y, int w, int h) - { - if (comp == null) - return; - comp.setBounds(x, y, w, h); - } - private Dimension calcCompSize(Component comp, int what) { - if (comp == null || !comp.isVisible()) + if (comp == null || ! comp.isVisible()) return new Dimension(0, 0); if (what == MIN) return comp.getMinimumSize(); @@ -589,12 +558,12 @@ public class BorderLayout implements LayoutManager2, java.io.Serializable } /** - * This is a helper function used to compute the various sizes for - * this layout. + * This is a helper function used to compute the various sizes for this + * layout. */ private Dimension calcSize(Container target, int what) { - synchronized (target.getTreeLock ()) + synchronized (target.getTreeLock()) { Insets ins = target.getInsets(); diff --git a/java/awt/CardLayout.java b/java/awt/CardLayout.java index 8582c5f09..8b3fea2ca 100644 --- a/java/awt/CardLayout.java +++ b/java/awt/CardLayout.java @@ -117,7 +117,7 @@ public class CardLayout implements LayoutManager2, Serializable /** * Cause the first component in the container to be displayed. * - * @param parent The parent container + * @param parent The parent container, not null. */ public void first (Container parent) { @@ -181,7 +181,7 @@ public class CardLayout implements LayoutManager2, Serializable /** * Cause the last component in the container to be displayed. * - * @param parent The parent container + * @param parent The parent container, not null. */ public void last (Container parent) { @@ -247,7 +247,7 @@ public class CardLayout implements LayoutManager2, Serializable * this current card is the last one in the deck, the first * component is displayed. * - * @param parent The parent container + * @param parent The parent container, not null. */ public void next (Container parent) { @@ -271,7 +271,7 @@ public class CardLayout implements LayoutManager2, Serializable * If this current card is the first one in the deck, the last * component is displayed. * - * @param parent The parent container + * @param parent The parent container, not null. */ public void previous (Container parent) { @@ -321,13 +321,19 @@ public class CardLayout implements LayoutManager2, Serializable /** * Cause the named component to be shown. If the component name is - * unknown, this method does nothing. + * unknown or null, this method does nothing. * - * @param parent The parent container - * @param name The name of the component to show + * @param parent The parent container, not null. + * @param name The name of the component to show */ public void show (Container parent, String name) { + if (name == null) + return; + + if (parent.getLayout() != this) + throw new IllegalArgumentException("parent's layout is not this CardLayout"); + Object target = tab.get (name); if (target != null) { @@ -362,9 +368,15 @@ public class CardLayout implements LayoutManager2, Serializable * * @param parent The parent container * @param what The type of goto: FIRST, LAST, NEXT or PREV + * + * @throws IllegalArgumentException if parent has not this + * CardLayout set as its layout. */ private void gotoComponent (Container parent, int what) { + if (parent.getLayout() != this) + throw new IllegalArgumentException("parent's layout is not this CardLayout"); + synchronized (parent.getTreeLock ()) { int num = parent.ncomponents; diff --git a/java/awt/Checkbox.java b/java/awt/Checkbox.java index 93f609247..eea443edf 100644 --- a/java/awt/Checkbox.java +++ b/java/awt/Checkbox.java @@ -1,5 +1,6 @@ /* Checkbox.java -- An AWT checkbox widget - Copyright (C) 1999, 2000, 2001, 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -459,11 +460,14 @@ getState() public synchronized void setState(boolean state) { - this.state = state; - if (peer != null) + if (this.state != state) { - CheckboxPeer cp = (CheckboxPeer) peer; - cp.setState (state); + this.state = state; + if (peer != null) + { + CheckboxPeer cp = (CheckboxPeer) peer; + cp.setState (state); + } } } @@ -599,10 +603,15 @@ void dispatchEventImpl(AWTEvent e) { if (e.id <= ItemEvent.ITEM_LAST - && e.id >= ItemEvent.ITEM_FIRST - && (item_listeners != null - || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)) - processEvent(e); + && e.id >= ItemEvent.ITEM_FIRST) + { + ItemEvent ie = (ItemEvent) e; + int itemState = ie.getStateChange(); + setState(itemState == ItemEvent.SELECTED ? true : false); + if (item_listeners != null + || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0) + processEvent(e); + } else super.dispatchEventImpl(e); } diff --git a/java/awt/Choice.java b/java/awt/Choice.java index 9b9fe4b97..9fbcd9343 100644 --- a/java/awt/Choice.java +++ b/java/awt/Choice.java @@ -468,15 +468,16 @@ getSelectedIndex() public synchronized void select(int index) { - if ((index < 0) || (index > getItemCount())) + if ((index < 0) || (index >= getItemCount())) throw new IllegalArgumentException("Bad index: " + index); - this.selectedIndex = index; - if (peer != null) - { + if (pItems.size() > 0) { + selectedIndex = index; ChoicePeer cp = (ChoicePeer) peer; - cp.select (index); - } + if (cp != null) { + cp.select(index); + } + } } /*************************************************************************/ @@ -573,18 +574,6 @@ processItemEvent(ItemEvent event) item_listeners.itemStateChanged(event); } -void -dispatchEventImpl(AWTEvent e) -{ - if (e.id <= ItemEvent.ITEM_LAST - && e.id >= ItemEvent.ITEM_FIRST - && (item_listeners != null - || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)) - processEvent(e); - else - super.dispatchEventImpl(e); -} - /*************************************************************************/ /** diff --git a/java/awt/Component.java b/java/awt/Component.java index 7d4346582..eb0352147 100644 --- a/java/awt/Component.java +++ b/java/awt/Component.java @@ -1,5 +1,6 @@ /* Component.java -- a graphics component - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2006 + Free Software Foundation This file is part of GNU Classpath. @@ -40,6 +41,7 @@ package java.awt; import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; +import java.awt.event.AdjustmentEvent; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.FocusEvent; @@ -900,7 +902,7 @@ public abstract class Component // Avoid NullPointerExceptions by creating a local reference. ComponentPeer currentPeer=peer; if (currentPeer != null) - currentPeer.setVisible(true); + currentPeer.show(); // The JDK repaints the component before invalidating the parent. // So do we. @@ -1388,18 +1390,20 @@ public abstract class Component int oldy = this.y; int oldwidth = this.width; int oldheight = this.height; - - if (this.x == x && this.y == y - && this.width == width && this.height == height) + + if (this.x == x && this.y == y && this.width == width + && this.height == height) return; - invalidate (); + + invalidate(); + this.x = x; this.y = y; this.width = width; this.height = height; if (peer != null) peer.setBounds (x, y, width, height); - + // Erase old bounds and repaint new bounds for lightweights. if (isLightweight() && isShowing()) { @@ -1598,16 +1602,18 @@ public abstract class Component public Dimension preferredSize() { if (prefSize == null) - if (peer == null) - return new Dimension(width, height); - else - prefSize = peer.getPreferredSize(); + { + if (peer == null) + prefSize = minimumSize(); + else + prefSize = peer.getPreferredSize(); + } return prefSize; } /** * Returns the component's minimum size. - * + * * @return the component's minimum size * @see #getPreferredSize() * @see LayoutManager @@ -1882,8 +1888,7 @@ public abstract class Component */ public void repaint() { - if (isShowing()) - repaint(0, 0, 0, width, height); + repaint(0, 0, 0, width, height); } /** @@ -1897,8 +1902,7 @@ public abstract class Component */ public void repaint(long tm) { - if (isShowing()) - repaint(tm, 0, 0, width, height); + repaint(tm, 0, 0, width, height); } /** @@ -1915,8 +1919,7 @@ public abstract class Component */ public void repaint(int x, int y, int w, int h) { - if (isShowing()) - repaint(0, x, y, w, h); + repaint(0, x, y, w, h); } /** @@ -2308,6 +2311,10 @@ public abstract class Component */ public final void dispatchEvent(AWTEvent e) { + Event oldEvent = translateEvent(e); + if (oldEvent != null) + postEvent (oldEvent); + // Some subclasses in the AWT package need to override this behavior, // hence the use of dispatchEventImpl(). dispatchEventImpl(e); @@ -3431,6 +3438,8 @@ public abstract class Component { if (peer == null) peer = getToolkit().createComponent(this); + else if (parent != null && parent.isLightweight()) + new HeavyweightInLightweightListener(parent); /* Now that all the children has gotten their peers, we should have the event mask needed for this component and its lightweight subcomponents. */ @@ -4481,6 +4490,109 @@ p *
  • the set of backward traversal keys changeSupport.firePropertyChange(propertyName, oldValue, newValue); } + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, byte oldValue, + byte newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Byte(oldValue), + new Byte(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, char oldValue, + char newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Character(oldValue), + new Character(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, short oldValue, + short newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Short(oldValue), + new Short(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, long oldValue, + long newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Long(oldValue), + new Long(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, float oldValue, + float newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Float(oldValue), + new Float(newValue)); + } + + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, double oldValue, + double newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Double(oldValue), + new Double(newValue)); + } + /** * Sets the text layout orientation of this component. New components default * to UNKNOWN (which behaves like LEFT_TO_RIGHT). This method affects only @@ -4598,7 +4710,7 @@ p *
  • the set of backward traversal keys */ static Event translateEvent (AWTEvent e) { - Component target = (Component) e.getSource (); + Object target = e.getSource (); Event translated = null; if (e instanceof InputEvent) @@ -4771,6 +4883,25 @@ p *
  • the set of backward traversal keys 0, 0, oldKey, oldMods); } } + else if (e instanceof AdjustmentEvent) + { + AdjustmentEvent ae = (AdjustmentEvent) e; + int type = ae.getAdjustmentType(); + int oldType; + if (type == AdjustmentEvent.BLOCK_DECREMENT) + oldType = Event.SCROLL_PAGE_UP; + else if (type == AdjustmentEvent.BLOCK_INCREMENT) + oldType = Event.SCROLL_PAGE_DOWN; + else if (type == AdjustmentEvent.TRACK) + oldType = Event.SCROLL_ABSOLUTE; + else if (type == AdjustmentEvent.UNIT_DECREMENT) + oldType = Event.SCROLL_LINE_UP; + else if (type == AdjustmentEvent.UNIT_INCREMENT) + oldType = Event.SCROLL_LINE_DOWN; + else + oldType = type; + translated = new Event(target, oldType, new Integer(ae.getValue())); + } else if (e instanceof ActionEvent) translated = new Event (target, Event.ACTION_EVENT, ((ActionEvent) e).getActionCommand ()); @@ -4791,16 +4922,12 @@ p *
  • the set of backward traversal keys void dispatchEventImpl(AWTEvent e) { - Event oldEvent = translateEvent (e); // This boolean tells us not to process focus events when the focus // opposite component is the same as the focus component. boolean ignoreFocus = (e instanceof FocusEvent && ((FocusEvent)e).getComponent() == ((FocusEvent)e).getOppositeComponent()); - if (oldEvent != null) - postEvent (oldEvent); - if (eventTypeEnabled (e.id)) { // the trick we use to communicate between dispatch and redispatch @@ -4926,16 +5053,6 @@ p *
  • the set of backward traversal keys Rectangle r1 = queuedEvent.getUpdateRect(); Rectangle r2 = newEvent.getUpdateRect(); Rectangle union = r1.union(r2); - - int r1a = r1.width * r1.height; - int r2a = r2.width * r2.height; - int ua = union.width * union.height; - - if (ua > (r1a+r2a)*2) - return null; - /* The 2 factor should maybe be reconsidered. Perhaps 3/2 - would be better? */ - newEvent.setUpdateRect(union); return newEvent; } @@ -5015,9 +5132,76 @@ p *
  • the set of backward traversal keys s.writeObject(null); } - + // Nested classes. + + /** + * This class fixes the bounds for a Heavyweight component that + * is placed inside a Lightweight container. When the lightweight is + * moved or resized, setBounds for the lightweight peer does nothing. + * Therefore, it was never moved on the screen. This class is + * attached to the lightweight, and it adjusts the position and size + * of the peer when notified. + * This is the same for show and hide. + */ + class HeavyweightInLightweightListener + implements ComponentListener + { + + /** + * Constructor. Adds component listener to lightweight parent. + * + * @param parent - the lightweight container. + */ + public HeavyweightInLightweightListener(Container parent) + { + parent.addComponentListener(this); + } + + /** + * This method is called when the component is resized. + * + * @param event the ComponentEvent indicating the resize + */ + public void componentResized(ComponentEvent event) + { + // Nothing to do here, componentMoved will be called. + } + + /** + * This method is called when the component is moved. + * + * @param event the ComponentEvent indicating the move + */ + public void componentMoved(ComponentEvent event) + { + if (peer != null) + peer.setBounds(x, y, width, height); + } + + /** + * This method is called when the component is made visible. + * + * @param event the ComponentEvent indicating the visibility + */ + public void componentShown(ComponentEvent event) + { + if (isShowing()) + peer.show(); + } + /** + * This method is called when the component is hidden. + * + * @param event the ComponentEvent indicating the visibility + */ + public void componentHidden(ComponentEvent event) + { + if (!isShowing()) + peer.hide(); + } + } + /** * This class provides accessibility support for subclasses of container. * diff --git a/java/awt/Container.java b/java/awt/Container.java index 6d4a34571..dfea3ac12 100644 --- a/java/awt/Container.java +++ b/java/awt/Container.java @@ -1,5 +1,5 @@ /* Container.java -- parent container class in AWT - Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -43,12 +43,10 @@ import java.awt.event.ComponentListener; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; import java.awt.peer.ComponentPeer; import java.awt.peer.ContainerPeer; import java.awt.peer.LightweightPeer; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -63,8 +61,6 @@ import java.util.Set; import javax.accessibility.Accessible; -import gnu.java.awt.AWTUtilities; - /** * A generic window toolkit object that acts as a container for other objects. * Components are tracked in a list, and new elements are at the end of the @@ -90,10 +86,13 @@ public class Container extends Component Component[] component; LayoutManager layoutMgr; - LightweightDispatcher dispatcher; - Dimension maxSize; + /** + * Keeps track if the Container was cleared during a paint/update. + */ + private boolean backCleared; + /** * @since 1.4 */ @@ -103,7 +102,6 @@ public class Container extends Component /* Anything else is non-serializable, and should be declared "transient". */ transient ContainerListener containerListener; - transient PropertyChangeSupport changeSupport; /** The focus traversal policy that determines how focus is transferred between this Container and its children. */ @@ -188,25 +186,6 @@ public class Container extends Component } } - /** - * Swaps the components at position i and j, in the container. - */ - - protected void swapComponents (int i, int j) - { - synchronized (getTreeLock ()) - { - if (i < 0 - || i >= component.length - || j < 0 - || j >= component.length) - throw new ArrayIndexOutOfBoundsException (); - Component tmp = component[i]; - component[i] = component[j]; - component[j] = tmp; - } - } - /** * Returns the insets for this container, which is the space used for * borders, the margin, etc. @@ -387,6 +366,8 @@ public class Container extends Component // Notify the layout manager. if (layoutMgr != null) { + // If we have a LayoutManager2 the constraints are "real", + // otherwise they are the "name" of the Component to add. if (layoutMgr instanceof LayoutManager2) { LayoutManager2 lm2 = (LayoutManager2) layoutMgr; @@ -395,7 +376,7 @@ public class Container extends Component else if (constraints instanceof String) layoutMgr.addLayoutComponent((String) constraints, comp); else - layoutMgr.addLayoutComponent(null, comp); + layoutMgr.addLayoutComponent("", comp); } // We previously only sent an event when this container is showing. @@ -779,16 +760,17 @@ public class Container extends Component * a superclass method so that lightweight components are properly * drawn. * - * @param g The graphics context for this paint job. + * @param g - The graphics context for this paint job. */ public void paint(Graphics g) { if (!isShowing()) return; - // Visit heavyweights as well, in case they were - // erased when we cleared the background for this container. - visitChildren(g, GfxPaintVisitor.INSTANCE, false); + // Visit heavyweights if the background was cleared + // for this container. + visitChildren(g, GfxPaintVisitor.INSTANCE, !backCleared); + backCleared = false; } /** @@ -819,8 +801,11 @@ public class Container extends Component // also not cleared. So we do a check on !(peer instanceof LightweightPeer) // instead. ComponentPeer p = peer; - if (p != null && !(p instanceof LightweightPeer)) - g.clearRect(0, 0, getWidth(), getHeight()); + if (p != null && ! (p instanceof LightweightPeer)) + { + g.clearRect(0, 0, getWidth(), getHeight()); + backCleared = true; + } paint(g); } @@ -1561,28 +1546,105 @@ public class Container extends Component if (orientation == null) throw new NullPointerException (); } - + public void addPropertyChangeListener (PropertyChangeListener listener) { - if (listener == null) - return; - - if (changeSupport == null) - changeSupport = new PropertyChangeSupport (this); - - changeSupport.addPropertyChangeListener (listener); + // TODO: Why is this overridden? + super.addPropertyChangeListener(listener); } - - public void addPropertyChangeListener (String name, + + public void addPropertyChangeListener (String propertyName, PropertyChangeListener listener) { - if (listener == null) - return; - - if (changeSupport == null) - changeSupport = new PropertyChangeSupport (this); + // TODO: Why is this overridden? + super.addPropertyChangeListener(propertyName, listener); + } + + + /** + * Sets the Z ordering for the component comp to + * index. Components with lower Z order paint above components + * with higher Z order. + * + * @param comp the component for which to change the Z ordering + * @param index the index to set + * + * @throws NullPointerException if comp == null + * @throws IllegalArgumentException if comp is an ancestor of this container + * @throws IllegalArgumentException if index is not in + * [0, getComponentCount()] for moving between + * containers or [0, getComponentCount() - 1] for moving + * inside this container + * @throws IllegalArgumentException if comp == this + * @throws IllegalArgumentException if comp is a + * Window + * + * @see #getComponentZOrder(Component) + * + * @since 1.5 + */ + public final void setComponentZOrder(Component comp, int index) + { + if (comp == null) + throw new NullPointerException("comp must not be null"); + if (comp instanceof Container && ((Container) comp).isAncestorOf(this)) + throw new IllegalArgumentException("comp must not be an ancestor of " + + "this"); + if (comp instanceof Window) + throw new IllegalArgumentException("comp must not be a Window"); + + if (comp == this) + throw new IllegalArgumentException("cannot add component to itself"); - changeSupport.addPropertyChangeListener (name, listener); + // FIXME: Implement reparenting. + if ( comp.getParent() != this) + throw new AssertionError("Reparenting is not implemented yet"); + else + { + // Find current component index. + int currentIndex = getComponentZOrder(comp); + if (currentIndex < index) + { + System.arraycopy(component, currentIndex + 1, component, + currentIndex, index - currentIndex); + } + else + { + System.arraycopy(component, index, component, index + 1, + currentIndex - index); + } + component[index] = comp; + } + } + + /** + * Returns the Z ordering index of comp. If comp + * is not a child component of this Container, this returns -1. + * + * @param comp the component for which to query the Z ordering + * + * @return the Z ordering index of comp or -1 if + * comp is not a child of this Container + * + * @see #setComponentZOrder(Component, int) + * + * @since 1.5 + */ + public final int getComponentZOrder(Component comp) + { + int index = -1; + if (component != null) + { + for (int i = 0; i < component.length; i++) + { + if (component[i] == comp) + { + index = i; + break; + } + } + } + return index; } // Hidden helper methods. @@ -1604,17 +1666,17 @@ public class Container extends Component private void visitChildren(Graphics gfx, GfxVisitor visitor, boolean lightweightOnly) { - synchronized (getTreeLock ()) + synchronized (getTreeLock()) { for (int i = ncomponents - 1; i >= 0; --i) { Component comp = component[i]; boolean applicable = comp.isVisible() - && (comp.isLightweight() || !lightweightOnly); - + && (comp.isLightweight() || ! lightweightOnly); + if (applicable) visitChild(gfx, visitor, comp); - } + } } } @@ -1635,10 +1697,9 @@ public class Container extends Component Component comp) { Rectangle bounds = comp.getBounds(); - + if(!gfx.hitClip(bounds.x,bounds.y, bounds.width, bounds.height)) return; - Graphics g2 = gfx.create(bounds.x, bounds.y, bounds.width, bounds.height); try @@ -1653,10 +1714,6 @@ public class Container extends Component void dispatchEventImpl(AWTEvent e) { - // Give lightweight dispatcher a chance to handle it. - if (dispatcher != null && dispatcher.handleEvent (e)) - return; - if ((e.id <= ContainerEvent.CONTAINER_LAST && e.id >= ContainerEvent.CONTAINER_FIRST) && (containerListener != null @@ -1747,15 +1804,6 @@ public class Container extends Component component[i].addNotify(); if (component[i].isLightweight ()) { - - // If we're not lightweight, and we just got a lightweight - // child, we need a lightweight dispatcher to feed it events. - if (!this.isLightweight() && dispatcher == null) - dispatcher = new LightweightDispatcher (this); - - if (dispatcher != null) - dispatcher.enableEvents(component[i].eventMask); - enableEvents(component[i].eventMask); if (peer != null && !isLightweight ()) enableEvents (AWTEvent.PAINT_EVENT_MASK); @@ -2002,229 +2050,3 @@ public class Container extends Component } // class AccessibleContainerHandler } // class AccessibleAWTContainer } // class Container - -/** - * There is a helper class implied from stack traces called - * LightweightDispatcher, but since it is not part of the public API, - * rather than mimic it exactly we write something which does "roughly - * the same thing". - */ -class LightweightDispatcher implements Serializable -{ - private static final long serialVersionUID = 5184291520170872969L; - private Container nativeContainer; - private Cursor nativeCursor; - private long eventMask; - - private transient Component pressedComponent; - private transient Component lastComponentEntered; - private transient int pressCount; - - LightweightDispatcher(Container c) - { - nativeContainer = c; - } - - void enableEvents(long l) - { - eventMask |= l; - } - - /** - * Returns the deepest visible descendent of parent that contains the - * specified location and that is not transparent and MouseListener-less. - * @param parent the root component to begin the search - * @param x the x coordinate - * @param y the y coordinate - * @return null if parent doesn't contain the location, - * parent if parent is not a container or has no child that contains the - * location, otherwise the appropriate component from the conditions - * above. - */ - Component getDeepestComponentForMouseEventAt(Component parent, int x, int y) - { - if (parent == null || (! parent.contains(x, y))) - return null; - - if (! (parent instanceof Container)) - return parent; - - Container c = (Container) parent; - return c.findComponentForMouseEventAt(x, y); - } - - Component acquireComponentForMouseEvent(MouseEvent me) - { - int x = me.getX (); - int y = me.getY (); - - Component mouseEventTarget = null; - // Find the candidate which should receive this event. - Component parent = nativeContainer; - Component candidate = null; - Point p = me.getPoint(); - while (candidate == null && parent != null) - { - candidate = getDeepestComponentForMouseEventAt(parent, p.x, p.y); - if (candidate == null || (candidate.eventMask & me.getID()) == 0) - { - candidate = null; - p = AWTUtilities.convertPoint(parent, p.x, p.y, parent.parent); - parent = parent.parent; - } - } - - // If the only candidate we found was the native container itself, - // don't dispatch any event at all. We only care about the lightweight - // children here. - if (candidate == nativeContainer) - candidate = null; - - // If our candidate is new, inform the old target we're leaving. - if (lastComponentEntered != null - && lastComponentEntered.isShowing() - && lastComponentEntered != candidate) - { - // Old candidate could have been removed from - // the nativeContainer so we check first. - if (AWTUtilities.isDescendingFrom(lastComponentEntered, - nativeContainer)) - { - Point tp = AWTUtilities.convertPoint(nativeContainer, - x, y, lastComponentEntered); - MouseEvent exited = new MouseEvent (lastComponentEntered, - MouseEvent.MOUSE_EXITED, - me.getWhen (), - me.getModifiersEx (), - tp.x, tp.y, - me.getClickCount (), - me.isPopupTrigger (), - me.getButton ()); - lastComponentEntered.dispatchEvent (exited); - } - lastComponentEntered = null; - } - - // If we have a candidate, maybe enter it. - if (candidate != null) - { - mouseEventTarget = candidate; - if (candidate.isLightweight() - && candidate.isShowing() - && candidate != nativeContainer - && candidate != lastComponentEntered) - { - lastComponentEntered = mouseEventTarget; - Point cp = AWTUtilities.convertPoint(nativeContainer, - x, y, lastComponentEntered); - MouseEvent entered = new MouseEvent (lastComponentEntered, - MouseEvent.MOUSE_ENTERED, - me.getWhen (), - me.getModifiersEx (), - cp.x, cp.y, - me.getClickCount (), - me.isPopupTrigger (), - me.getButton ()); - lastComponentEntered.dispatchEvent (entered); - } - } - - // Check which buttons where pressed except the last button that - // changed state. - int modifiers = me.getModifiersEx() & (MouseEvent.BUTTON1_DOWN_MASK - | MouseEvent.BUTTON2_DOWN_MASK - | MouseEvent.BUTTON3_DOWN_MASK); - switch(me.getButton()) - { - case MouseEvent.BUTTON1: - modifiers &= ~MouseEvent.BUTTON1_DOWN_MASK; - break; - case MouseEvent.BUTTON2: - modifiers &= ~MouseEvent.BUTTON2_DOWN_MASK; - break; - case MouseEvent.BUTTON3: - modifiers &= ~MouseEvent.BUTTON3_DOWN_MASK; - break; - } - - if (me.getID() == MouseEvent.MOUSE_RELEASED - || me.getID() == MouseEvent.MOUSE_PRESSED && modifiers > 0 - || me.getID() == MouseEvent.MOUSE_DRAGGED) - { - // If any of the following events occur while a button is held down, - // they should be dispatched to the same component to which the - // original MOUSE_PRESSED event was dispatched: - // - MOUSE_RELEASED: This is important for correct dragging - // behaviour, otherwise the release goes to an arbitrary component - // outside of the dragged component. OTOH, if there is no mouse - // drag while the mouse is pressed, the component under the mouse - // is the same as the previously pressed component anyway. - // - MOUSE_PRESSED: another button pressed while the first is held - // down - // - MOUSE_DRAGGED - if (AWTUtilities.isDescendingFrom(pressedComponent, nativeContainer)) - mouseEventTarget = pressedComponent; - } - else if (me.getID() == MouseEvent.MOUSE_CLICKED) - { - // Don't dispatch CLICKED events whose target is not the same as the - // target for the original PRESSED event. - if (candidate != pressedComponent) - { - mouseEventTarget = null; - pressCount = 0; - } - else if (pressCount == 0) - pressedComponent = null; - } - return mouseEventTarget; - } - - boolean handleEvent(AWTEvent e) - { - if (e instanceof MouseEvent) - { - MouseEvent me = (MouseEvent) e; - - // Make the LightWeightDispatcher reentrant. This is necessary when - // a lightweight component does its own modal event queue. - Component mouseEventTarget = acquireComponentForMouseEvent(me); - - // Avoid dispatching ENTERED and EXITED events twice. - if (mouseEventTarget != null - && mouseEventTarget.isShowing() - && e.getID() != MouseEvent.MOUSE_ENTERED - && e.getID() != MouseEvent.MOUSE_EXITED) - { - switch (e.getID()) - { - case MouseEvent.MOUSE_PRESSED: - if (pressCount++ == 0) - pressedComponent = mouseEventTarget; - break; - case MouseEvent.MOUSE_RELEASED: - // Clear our memory of the original PRESSED event, only if - // we're not expecting a CLICKED event after this. If - // there is a CLICKED event after this, it will do clean up. - if (--pressCount == 0 - && mouseEventTarget != pressedComponent) - { - pressedComponent = null; - pressCount = 0; - } - break; - } - - MouseEvent newEvt = - AWTUtilities.convertMouseEvent(nativeContainer, me, - mouseEventTarget); - mouseEventTarget.dispatchEvent(newEvt); - - if (newEvt.isConsumed()) - e.consume(); - } - } - - return e.isConsumed(); - } -} diff --git a/java/awt/Cursor.java b/java/awt/Cursor.java index 48a63f06f..0ff987cd9 100644 --- a/java/awt/Cursor.java +++ b/java/awt/Cursor.java @@ -219,6 +219,8 @@ public class Cursor implements java.io.Serializable public String toString() { - return (this.getClass() + "[" + getName() + "]"); + return (this.getClass() + + "[type=" + getType() + + ",name=" + getName() + "]"); } } diff --git a/java/awt/EventQueue.java b/java/awt/EventQueue.java index 235ad2ac1..72dcf7046 100644 --- a/java/awt/EventQueue.java +++ b/java/awt/EventQueue.java @@ -38,6 +38,7 @@ exception statement from your version. */ package java.awt; +import java.awt.event.AWTEventListenerProxy; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.InputMethodEvent; @@ -459,6 +460,8 @@ public class EventQueue else if (evt instanceof InvocationEvent) lastWhen = ((InvocationEvent) evt).getWhen(); + globalDispatchEvent(evt); + if (evt instanceof ActiveEvent) { ActiveEvent active_evt = (ActiveEvent) evt; @@ -481,6 +484,25 @@ public class EventQueue } } + /** + * Dispatches events to listeners registered to the current Toolkit. + * + * @param ev the event to dispatch + */ + private void globalDispatchEvent(AWTEvent ev) + { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + // We do not use the accessor methods here because they create new + // arrays each time. We must be very efficient, so we access this directly. + AWTEventListenerProxy[] l = toolkit.awtEventListeners; + for (int i = 0; i < l.length; ++i) + { + AWTEventListenerProxy proxy = l[i]; + if ((proxy.getEventMask() & AWTEvent.eventIdToMask(ev.getID())) != 0) + proxy.eventDispatched(ev); + } + } + /** * Returns the timestamp of the most recent event that had a timestamp, or * the initialization time of the event queue if no events have been fired. diff --git a/java/awt/Frame.java b/java/awt/Frame.java index d6651f83e..7003dac91 100644 --- a/java/awt/Frame.java +++ b/java/awt/Frame.java @@ -1,5 +1,6 @@ /* Frame.java -- AWT toplevel window - Copyright (C) 1999, 2000, 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2002, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -57,143 +58,156 @@ import javax.accessibility.AccessibleStateSet; */ public class Frame extends Window implements MenuContainer { -/** - * Constant for the default cursor. - * @deprecated Replaced by Cursor.DEFAULT_CURSOR instead. - */ -public static final int DEFAULT_CURSOR = Cursor.DEFAULT_CURSOR; -/** - * Constant for a cross-hair cursor. - * @deprecated Use Cursor.CROSSHAIR_CURSOR instead. - */ -public static final int CROSSHAIR_CURSOR = Cursor.CROSSHAIR_CURSOR; + /** + * Constant for the default cursor. + * + * @deprecated Replaced by Cursor.DEFAULT_CURSOR instead. + */ + public static final int DEFAULT_CURSOR = Cursor.DEFAULT_CURSOR; -/** - * Constant for a cursor over a text field. - * @deprecated Use Cursor.TEXT_CURSOR instead. - */ -public static final int TEXT_CURSOR = Cursor.TEXT_CURSOR; + /** + * Constant for a cross-hair cursor. + * + * @deprecated Use Cursor.CROSSHAIR_CURSOR instead. + */ + public static final int CROSSHAIR_CURSOR = Cursor.CROSSHAIR_CURSOR; -/** - * Constant for a cursor to display while waiting for an action to complete. - * @deprecated Use Cursor.WAIT_CURSOR. - */ -public static final int WAIT_CURSOR = Cursor.WAIT_CURSOR; + /** + * Constant for a cursor over a text field. + * + * @deprecated Use Cursor.TEXT_CURSOR instead. + */ + public static final int TEXT_CURSOR = Cursor.TEXT_CURSOR; -/** - * Cursor used over SW corner of window decorations. - * @deprecated Use Cursor.SW_RESIZE_CURSOR instead. - */ -public static final int SW_RESIZE_CURSOR = Cursor.SW_RESIZE_CURSOR; + /** + * Constant for a cursor to display while waiting for an action to complete. + * + * @deprecated Use Cursor.WAIT_CURSOR. + */ + public static final int WAIT_CURSOR = Cursor.WAIT_CURSOR; -/** - * Cursor used over SE corner of window decorations. - * @deprecated Use Cursor.SE_RESIZE_CURSOR instead. - */ -public static final int SE_RESIZE_CURSOR = Cursor.SE_RESIZE_CURSOR; + /** + * Cursor used over SW corner of window decorations. + * + * @deprecated Use Cursor.SW_RESIZE_CURSOR instead. + */ + public static final int SW_RESIZE_CURSOR = Cursor.SW_RESIZE_CURSOR; -/** - * Cursor used over NW corner of window decorations. - * @deprecated Use Cursor.NW_RESIZE_CURSOR instead. - */ -public static final int NW_RESIZE_CURSOR = Cursor.NW_RESIZE_CURSOR; + /** + * Cursor used over SE corner of window decorations. + * @deprecated Use Cursor.SE_RESIZE_CURSOR instead. + */ + public static final int SE_RESIZE_CURSOR = Cursor.SE_RESIZE_CURSOR; -/** - * Cursor used over NE corner of window decorations. - * @deprecated Use Cursor.NE_RESIZE_CURSOR instead. - */ -public static final int NE_RESIZE_CURSOR = Cursor.NE_RESIZE_CURSOR; + /** + * Cursor used over NW corner of window decorations. + * + * @deprecated Use Cursor.NW_RESIZE_CURSOR instead. + */ + public static final int NW_RESIZE_CURSOR = Cursor.NW_RESIZE_CURSOR; -/** - * Cursor used over N edge of window decorations. - * @deprecated Use Cursor.N_RESIZE_CURSOR instead. - */ -public static final int N_RESIZE_CURSOR = Cursor.N_RESIZE_CURSOR; + /** + * Cursor used over NE corner of window decorations. + * + * @deprecated Use Cursor.NE_RESIZE_CURSOR instead. + */ + public static final int NE_RESIZE_CURSOR = Cursor.NE_RESIZE_CURSOR; -/** - * Cursor used over S edge of window decorations. - * @deprecated Use Cursor.S_RESIZE_CURSOR instead. - */ -public static final int S_RESIZE_CURSOR = Cursor.S_RESIZE_CURSOR; + /** + * Cursor used over N edge of window decorations. + * + * @deprecated Use Cursor.N_RESIZE_CURSOR instead. + */ + public static final int N_RESIZE_CURSOR = Cursor.N_RESIZE_CURSOR; -/** - * Cursor used over E edge of window decorations. - * @deprecated Use Cursor.E_RESIZE_CURSOR instead. - */ -public static final int E_RESIZE_CURSOR = Cursor.E_RESIZE_CURSOR; + /** + * Cursor used over S edge of window decorations. + * + * @deprecated Use Cursor.S_RESIZE_CURSOR instead. + */ + public static final int S_RESIZE_CURSOR = Cursor.S_RESIZE_CURSOR; -/** - * Cursor used over W edge of window decorations. - * @deprecated Use Cursor.W_RESIZE_CURSOR instead. - */ -public static final int W_RESIZE_CURSOR = Cursor.W_RESIZE_CURSOR; + /** + * Cursor used over E edge of window decorations. + * + * @deprecated Use Cursor.E_RESIZE_CURSOR instead. + */ + public static final int E_RESIZE_CURSOR = Cursor.E_RESIZE_CURSOR; -/** - * Constant for a hand cursor. - * @deprecated Use Cursor.HAND_CURSOR instead. - */ -public static final int HAND_CURSOR = Cursor.HAND_CURSOR; + /** + * Cursor used over W edge of window decorations. + * + * @deprecated Use Cursor.W_RESIZE_CURSOR instead. + */ + public static final int W_RESIZE_CURSOR = Cursor.W_RESIZE_CURSOR; -/** - * Constant for a cursor used during window move operations. - * @deprecated Use Cursor.MOVE_CURSOR instead. - */ -public static final int MOVE_CURSOR = Cursor.MOVE_CURSOR; + /** + * Constant for a hand cursor. + * + * @deprecated Use Cursor.HAND_CURSOR instead. + */ + public static final int HAND_CURSOR = Cursor.HAND_CURSOR; -public static final int ICONIFIED = 1; -public static final int MAXIMIZED_BOTH = 6; -public static final int MAXIMIZED_HORIZ = 2; -public static final int MAXIMIZED_VERT = 4; -public static final int NORMAL = 0; + /** + * Constant for a cursor used during window move operations. + * + * @deprecated Use Cursor.MOVE_CURSOR instead. + */ + public static final int MOVE_CURSOR = Cursor.MOVE_CURSOR; -// Serialization version constant -private static final long serialVersionUID = 2673458971256075116L; + public static final int ICONIFIED = 1; + public static final int MAXIMIZED_BOTH = 6; + public static final int MAXIMIZED_HORIZ = 2; + public static final int MAXIMIZED_VERT = 4; + public static final int NORMAL = 0; -/** - * @serial The version of the class data being serialized - * // FIXME: what is this value? - */ -private int frameSerializedDataVersion; +//Serialization version constant + private static final long serialVersionUID = 2673458971256075116L; -/** - * @serial Image used as the icon when this frame is minimized. - */ -private Image icon; + /** + * @serial The version of the class data being serialized + * FIXME: what is this value? + */ + private int frameSerializedDataVersion; -/** - * @serial Constant used by the JDK Motif peer set. Not used in - * this implementation. - */ -private boolean mbManagement; + /** + * @serial Image used as the icon when this frame is minimized. + */ + private Image icon; -/** - * @serial The menu bar for this frame. - */ -//private MenuBar menuBar = new MenuBar(); -private MenuBar menuBar; + /** + * @serial Constant used by the JDK Motif peer set. Not used in + * this implementation. + */ + private boolean mbManagement; -/** - * @serial A list of other top-level windows owned by this window. - */ -Vector ownedWindows = new Vector(); + /** + * @serial The menu bar for this frame. + */ + private MenuBar menuBar; -/** - * @serial Indicates whether or not this frame is resizable. - */ -private boolean resizable = true; + /** + * @serial A list of other top-level windows owned by this window. + */ + Vector ownedWindows = new Vector(); -/** - * @serial The state of this frame. - * // FIXME: What are the values here? - * This is package-private to avoid an accessor method. - */ -int state; + /** + * @serial Indicates whether or not this frame is resizable. + */ + private boolean resizable = true; -/** - * @serial The title of the frame. - */ -private String title = ""; + /** + * @serial The state of this frame. + * // FIXME: What are the values here? + * This is package-private to avoid an accessor method. + */ + int state; + + /** + * @serial The title of the frame. + */ + private String title = ""; /** * Maximized bounds for this frame. @@ -210,223 +224,235 @@ private String title = ""; */ private static transient long next_frame_number; -/** - * Initializes a new instance of Frame that is not visible - * and has no title. - */ -public -Frame() -{ - this(""); - noteFrame(this); -} + /** + * Initializes a new instance of Frame that is not visible + * and has no title. + */ + public Frame() + { + this(""); + noteFrame(this); + } -/** - * Initializes a new instance of Frame that is not visible - * and has the specified title. - * - * @param title The title of this frame. - */ -public -Frame(String title) -{ - super(); - this.title = title; - // Top-level frames are initially invisible. - visible = false; - noteFrame(this); -} + /** + * Initializes a new instance of Frame that is not visible + * and has the specified title. + * + * @param title the title of this frame + */ + public Frame(String title) + { + super(); + this.title = title; + // Top-level frames are initially invisible. + visible = false; + noteFrame(this); + } -public -Frame(GraphicsConfiguration gc) -{ - super(gc); - visible = false; - noteFrame(this); -} + public Frame(GraphicsConfiguration gc) + { + super(gc); + visible = false; + noteFrame(this); + } -public -Frame(String title, GraphicsConfiguration gc) -{ - super(gc); - setTitle(title); - visible = false; - noteFrame(this); -} + public Frame(String title, GraphicsConfiguration gc) + { + super(gc); + setTitle(title); + visible = false; + noteFrame(this); + } -/** - * Returns this frame's title string. - * - * @return This frame's title string. - */ -public String -getTitle() -{ - return(title); -} + /** + * Returns this frame's title string. + * + * @return this frame's title string + */ + public String getTitle() + { + return title; + } -/* - * Sets this frame's title to the specified value. - * - * @param title The new frame title. - */ -public synchronized void -setTitle(String title) -{ - this.title = title; - if (peer != null) - ((FramePeer) peer).setTitle(title); -} + /** + * Sets this frame's title to the specified value. + * + * @param title the new frame title + */ + public synchronized void setTitle(String title) + { + this.title = title; + if (peer != null) + ((FramePeer) peer).setTitle(title); + } -/** - * Returns this frame's icon. - * - * @return This frame's icon, or null if this frame does not - * have an icon. - */ -public Image -getIconImage() -{ - return(icon); -} + /** + * Returns this frame's icon. + * + * @return this frame's icon, or null if this frame does not + * have an icon + */ + public Image getIconImage() + { + return icon; + } -/** - * Sets this frame's icon to the specified value. - * - * @icon The new icon for this frame. - */ -public synchronized void -setIconImage(Image icon) -{ - this.icon = icon; - if (peer != null) - ((FramePeer) peer).setIconImage(icon); -} + /** + * Sets this frame's icon to the specified value. + * + * @icon the new icon for this frame + */ + public synchronized void setIconImage(Image icon) + { + this.icon = icon; + if (peer != null) + ((FramePeer) peer).setIconImage(icon); + } -/** - * Returns this frame's menu bar. - * - * @return This frame's menu bar, or null if this frame - * does not have a menu bar. - */ -public MenuBar -getMenuBar() -{ - return(menuBar); -} + /** + * Returns this frame's menu bar. + * + * @return this frame's menu bar, or null if this frame + * does not have a menu bar + */ + public MenuBar getMenuBar() + { + return menuBar; + } -/** - * Sets this frame's menu bar. - * - * @param menuBar The new menu bar for this frame. - */ -public synchronized void -setMenuBar(MenuBar menuBar) -{ - if (peer != null) + /** + * Sets this frame's menu bar. Removes any existing menu bar. If the + * given menu bar is part of another frame it will be removed from + * that frame. + * + * @param menuBar the new menu bar for this frame + */ + public synchronized void setMenuBar(MenuBar menuBar) { if (this.menuBar != null) - this.menuBar.removeNotify(); + remove(this.menuBar); + + this.menuBar = menuBar; if (menuBar != null) - menuBar.addNotify(); - invalidateTree (); - ((FramePeer) peer).setMenuBar(menuBar); + { + MenuContainer parent = menuBar.getParent(); + if (parent != null) + parent.remove(menuBar); + menuBar.setParent(this); + + if (peer != null) + { + if (menuBar != null) + menuBar.addNotify(); + invalidateTree(); + ((FramePeer) peer).setMenuBar(menuBar); + } + } } - this.menuBar = menuBar; -} -/** - * Tests whether or not this frame is resizable. This will be - * true by default. - * - * @return true if this frame is resizable, false - * otherwise. - */ -public boolean -isResizable() -{ - return(resizable); -} + /** + * Tests whether or not this frame is resizable. This will be + * true by default. + * + * @return true if this frame is resizable, false + * otherwise + */ + public boolean isResizable() + { + return resizable; + } -/** - * Sets the resizability of this frame to the specified value. - * - * @param resizable true to make the frame resizable, - * false to make it non-resizable. - */ -public synchronized void -setResizable(boolean resizable) -{ - this.resizable = resizable; - if (peer != null) - ((FramePeer) peer).setResizable(resizable); -} + /** + * Sets the resizability of this frame to the specified value. + * + * @param resizable true to make the frame resizable, + * false to make it non-resizable + */ + public synchronized void setResizable(boolean resizable) + { + this.resizable = resizable; + if (peer != null) + ((FramePeer) peer).setResizable(resizable); + } -/** - * Returns the cursor type of the cursor for this window. This will - * be one of the constants in this class. - * - * @return The cursor type for this frame. - * - * @deprecated Use Component.getCursor() instead. - */ -public int -getCursorType() -{ - return(getCursor().getType()); -} + /** + * Returns the cursor type of the cursor for this window. This will + * be one of the constants in this class. + * + * @return the cursor type for this frame + * + * @deprecated Use Component.getCursor() instead. + */ + public int getCursorType() + { + return getCursor().getType(); + } -/** - * Sets the cursor for this window to the specified type. The specified - * type should be one of the constants in this class. - * - * @param type The cursor type. - * - * @deprecated Use Component.setCursor(Cursor) instead. - */ -public void -setCursor(int type) -{ - setCursor(new Cursor(type)); -} + /** + * Sets the cursor for this window to the specified type. The specified + * type should be one of the constants in this class. + * + * @param type the cursor type + * + * @deprecated Use Component.setCursor(Cursor) instead. + */ + public void setCursor(int type) + { + setCursor(new Cursor(type)); + } -/** - * Removes the specified component from this frame's menu. - * - * @param menu The menu component to remove. - */ -public void -remove(MenuComponent menu) -{ - menuBar.remove(menu); -} + /** + * Removes the specified menu component from this frame. If it is + * the current MenuBar it is removed from the frame. If it is a + * Popup it is removed from this component. If it is any other menu + * component it is ignored. + * + * @param menu the menu component to remove + */ + public void remove(MenuComponent menu) + { + if (menu == menuBar) + { + if (menuBar != null) + { + if (peer != null) + { + ((FramePeer) peer).setMenuBar(null); + menuBar.removeNotify(); + } + menuBar.setParent(null); + } + menuBar = null; + } + else + super.remove(menu); + } -public void -addNotify() -{ - if (menuBar != null) - menuBar.addNotify(); - if (peer == null) - peer = getToolkit ().createFrame (this); + public void addNotify() + { + if (menuBar != null) + menuBar.addNotify(); + if (peer == null) + peer = getToolkit ().createFrame (this); - super.addNotify(); -} + super.addNotify(); + } -public void removeNotify() -{ - if (menuBar != null) - menuBar.removeNotify(); - super.removeNotify(); -} + public void removeNotify() + { + if (menuBar != null) + menuBar.removeNotify(); + super.removeNotify(); + } /** * Returns a debugging string describing this window. * - * @return A debugging string describing this window. + * @return a debugging string describing this window */ - protected String paramString () + protected String paramString() { - String title = getTitle (); + String title = getTitle(); String resizable = ""; if (isResizable ()) @@ -455,17 +481,17 @@ public void removeNotify() return super.paramString () + ",title=" + title + resizable + state; } -private static ArrayList weakFrames = new ArrayList(); + private static ArrayList weakFrames = new ArrayList(); -private static void noteFrame(Frame f) -{ - weakFrames.add(new WeakReference(f)); -} + private static void noteFrame(Frame f) + { + weakFrames.add(new WeakReference(f)); + } -public static Frame[] getFrames() -{ - int n = 0; - synchronized (weakFrames) + public static Frame[] getFrames() + { + int n = 0; + synchronized (weakFrames) { Iterator i = weakFrames.iterator(); while (i.hasNext()) @@ -490,32 +516,31 @@ public static Frame[] getFrames() return frames; } } -} + } - public void setState (int state) + public void setState(int state) { int current_state = getExtendedState (); if (state == NORMAL && (current_state & ICONIFIED) != 0) - setExtendedState (current_state | ICONIFIED); + setExtendedState(current_state | ICONIFIED); if (state == ICONIFIED && (current_state & ~ICONIFIED) == 0) - setExtendedState (current_state & ~ICONIFIED); + setExtendedState(current_state & ~ICONIFIED); } - public int getState () + public int getState() { - /* FIXME: State might have changed in the peer... Must check. */ - + // FIXME: State might have changed in the peer... Must check. return (state & ICONIFIED) != 0 ? ICONIFIED : NORMAL; } /** * @since 1.4 */ - public void setExtendedState (int state) + public void setExtendedState(int state) { this.state = state; } @@ -523,7 +548,7 @@ public static Frame[] getFrames() /** * @since 1.4 */ - public int getExtendedState () + public int getExtendedState() { return state; } @@ -531,7 +556,7 @@ public static Frame[] getFrames() /** * @since 1.4 */ - public void setMaximizedBounds (Rectangle maximizedBounds) + public void setMaximizedBounds(Rectangle maximizedBounds) { this.maximizedBounds = maximizedBounds; } @@ -539,11 +564,11 @@ public static Frame[] getFrames() /** * Returns the maximized bounds of this frame. * - * @return the maximized rectangle, may be null. + * @return the maximized rectangle, may be null * * @since 1.4 */ - public Rectangle getMaximizedBounds () + public Rectangle getMaximizedBounds() { return maximizedBounds; } @@ -553,7 +578,7 @@ public static Frame[] getFrames() * * @since 1.4 */ - public boolean isUndecorated () + public boolean isUndecorated() { return undecorated; } @@ -562,14 +587,14 @@ public static Frame[] getFrames() * Disables or enables decorations for this frame. This method can only be * called while the frame is not displayable. * - * @exception IllegalComponentStateException If this frame is displayable. + * @throws IllegalComponentStateException if this frame is displayable * * @since 1.4 */ - public void setUndecorated (boolean undecorated) + public void setUndecorated(boolean undecorated) { - if (isDisplayable ()) - throw new IllegalComponentStateException (); + if (isDisplayable()) + throw new IllegalComponentStateException(); this.undecorated = undecorated; } @@ -577,14 +602,14 @@ public static Frame[] getFrames() /** * Generate a unique name for this frame. * - * @return A unique name for this frame. + * @return a unique name for this frame */ - String generateName () + String generateName() { - return "frame" + getUniqueLong (); + return "frame" + getUniqueLong(); } - private static synchronized long getUniqueLong () + private static synchronized long getUniqueLong() { return next_frame_number++; } @@ -617,10 +642,9 @@ public static Frame[] getFrames() */ public AccessibleContext getAccessibleContext() { - /* Create the context if this is the first request */ + // Create the context if this is the first request. if (accessibleContext == null) accessibleContext = new AccessibleAWTFrame(); return accessibleContext; } - } diff --git a/java/awt/Graphics.java b/java/awt/Graphics.java index a28ca7e42..09bf7cacf 100644 --- a/java/awt/Graphics.java +++ b/java/awt/Graphics.java @@ -617,6 +617,9 @@ public abstract class Graphics */ public boolean hitClip(int x, int y, int width, int height) { + Shape clip = getClip(); + if (clip == null) + return true; return getClip().intersects(x, y, width, height); } diff --git a/java/awt/LightweightDispatcher.java b/java/awt/LightweightDispatcher.java new file mode 100644 index 000000000..1eccb5d5d --- /dev/null +++ b/java/awt/LightweightDispatcher.java @@ -0,0 +1,154 @@ +/* LightweightDispatcher.java -- Dispatches mouse events to lightweights + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +import gnu.java.awt.AWTUtilities; + +import java.awt.event.AWTEventListener; +import java.awt.event.MouseEvent; + +/** + * Redispatches mouse events to lightweight components. The native peers know + * nothing about the lightweight components and thus mouse events are always + * targetted at Windows or heavyweight components. This class listenes directly + * on the eventqueue and dispatches mouse events to lightweight components. + * + * @author Roman Kennke (kennke@aicas.com) + */ +class LightweightDispatcher + implements AWTEventListener +{ + + /** + * The component that is the start of a mouse dragging. All MOUSE_DRAGGED + * events that follow the initial press must have the source set to this, + * as well as the MOUSE_RELEASED event following the dragging. + */ + private Component dragTarget; + + /** + * The last mouse event target. If the target changes, additional + * MOUSE_ENTERED and MOUSE_EXITED events must be dispatched. + */ + private Component lastTarget; + + /** + * Receives notification if a mouse event passes along the eventqueue. + * + * @param event the event + */ + public void eventDispatched(AWTEvent event) + { + if (event instanceof MouseEvent && event.getSource() instanceof Window) + { + MouseEvent mouseEvent = (MouseEvent) event; + handleMouseEvent(mouseEvent); + } + } + + /** + * Handles all mouse events that are targetted at toplevel containers + * (Window instances) and dispatches them to the correct lightweight child. + * + * @param ev the mouse event + */ + private void handleMouseEvent(MouseEvent ev) + { + Window window = (Window) ev.getSource(); + Component target = window.findComponentAt(ev.getX(), ev.getY()); + if (target != null && target.isLightweight()) + { + // Dispatch additional MOUSE_EXITED and MOUSE_ENTERED if event target + // is different from the last event target. + if (target != lastTarget) + { + if (lastTarget != null) + { + Point p1 = AWTUtilities.convertPoint(window, ev.getX(), + ev.getY(), lastTarget); + MouseEvent mouseExited = + new MouseEvent(lastTarget, MouseEvent.MOUSE_EXITED, + ev.getWhen(), ev.getModifiers(), p1.x, p1.y, + ev.getClickCount(), ev.isPopupTrigger()); + lastTarget.dispatchEvent(mouseExited); + } + Point p = AWTUtilities.convertPoint(window, ev.getX(), ev.getY(), + target); + MouseEvent mouseEntered = + new MouseEvent(target, MouseEvent.MOUSE_ENTERED, ev.getWhen(), + ev.getModifiers(), p.x, p.y, ev.getClickCount(), + ev.isPopupTrigger()); + target.dispatchEvent(mouseEntered); + } + lastTarget = target; + + + switch (ev.getID()) + { + case MouseEvent.MOUSE_PRESSED: + dragTarget = target; + break; + case MouseEvent.MOUSE_RELEASED: + if (dragTarget != null) + target = dragTarget; + dragTarget = null; + break; + case MouseEvent.MOUSE_DRAGGED: + target = dragTarget; + break; + default: + // Do nothing in other cases. + break; + } + + Point targetCoordinates = + AWTUtilities.convertPoint(window, ev.getX(), ev.getY(), target); + int dx = targetCoordinates.x - ev.getX(); + int dy = targetCoordinates.y - ev.getY(); + ev.translatePoint(dx, dy); + ev.setSource(target); + target.dispatchEvent(ev); + + // We reset the event, so that the normal event dispatching is not + // influenced by this modified event. + ev.setSource(window); + ev.translatePoint(-dx, -dy); + } + } +} diff --git a/java/awt/Menu.java b/java/awt/Menu.java index 13ebb5211..6daec72cf 100644 --- a/java/awt/Menu.java +++ b/java/awt/Menu.java @@ -1,5 +1,5 @@ /* Menu.java -- A Java AWT Menu - Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -220,15 +220,16 @@ getItem(int index) public MenuItem add(MenuItem item) { + MenuContainer parent = item.getParent(); + if (parent != null) + parent.remove(item); + items.addElement(item); - if (item.parent != null) - { - item.parent.remove(item); - } - item.parent = this; + item.setParent(this); if (peer != null) { + item.addNotify(); MenuPeer mp = (MenuPeer) peer; mp.addItem(item); } @@ -266,26 +267,33 @@ insert(MenuItem item, int index) if (index < 0) throw new IllegalArgumentException("Index is less than zero"); - MenuPeer peer = (MenuPeer) getPeer(); - if (peer == null) - return; - int count = getItemCount (); if (index >= count) - peer.addItem (item); + add(item); else { + MenuContainer parent = item.getParent(); + if (parent != null) + parent.remove(item); + + items.insertElementAt(item, index); + item.setParent(this); + + MenuPeer peer = (MenuPeer) getPeer(); + if (peer == null) + return; + for (int i = count - 1; i >= index; i--) - peer.delItem (i); + peer.delItem(i); - peer.addItem (item); + item.addNotify(); + peer.addItem(item); for (int i = index; i < count; i++) - peer.addItem ((MenuItem) items.elementAt (i)); + peer.addItem((MenuItem) items.elementAt (i)); } - items.insertElementAt(item, index); } /*************************************************************************/ @@ -344,11 +352,15 @@ insertSeparator(int index) public synchronized void remove(int index) { - items.removeElementAt(index); + MenuItem item = (MenuItem) items.remove(index); - MenuPeer mp = (MenuPeer)getPeer(); + MenuPeer mp = (MenuPeer) getPeer(); if (mp != null) - mp.delItem(index); + { + mp.delItem(index); + item.removeNotify(); + } + item.setParent(null); } /*************************************************************************/ @@ -393,14 +405,21 @@ removeAll() public void addNotify() { + MenuPeer peer = (MenuPeer) getPeer(); if (peer == null) - peer = getToolkit().createMenu(this); + { + peer = getToolkit().createMenu(this); + setPeer(peer); + } + Enumeration e = items.elements(); while (e.hasMoreElements()) { MenuItem mi = (MenuItem)e.nextElement(); mi.addNotify(); - } + peer.addItem(mi); + } + super.addNotify (); } diff --git a/java/awt/MenuBar.java b/java/awt/MenuBar.java index 97156aefe..3c6b91564 100644 --- a/java/awt/MenuBar.java +++ b/java/awt/MenuBar.java @@ -1,5 +1,6 @@ /* MenuBar.java -- An AWT menu bar class - Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,7 +40,6 @@ exception statement from your version. */ package java.awt; import java.awt.peer.MenuBarPeer; -import java.awt.peer.MenuComponentPeer; import java.io.Serializable; import java.util.Enumeration; @@ -60,364 +60,311 @@ public class MenuBar extends MenuComponent implements MenuContainer, Serializable, Accessible { -/* - * Static Variables - */ +//Serialization Constant + private static final long serialVersionUID = -4930327919388951260L; -// Serialization Constant -private static final long serialVersionUID = -4930327919388951260L; - -/*************************************************************************/ - -/* - * Instance Variables - */ - -/** - * @serial The menu used for providing help information - */ -private Menu helpMenu; + /** + * @serial The menu used for providing help information + */ + private Menu helpMenu; -/** - * @serial The menus contained in this menu bar. - */ -private Vector menus = new Vector(); + /** + * @serial The menus contained in this menu bar. + */ + private Vector menus = new Vector(); /** - * The accessible context for this component. + * Initializes a new instance of MenuBar. * - * @see #getAccessibleContext() - * @serial ignored. + * @throws HeadlessException if GraphicsEnvironment.isHeadless() is true */ - private transient AccessibleContext accessibleContext; - -/*************************************************************************/ - -/* - * Constructors - */ - -/** - * Initializes a new instance of MenuBar. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. - */ -public -MenuBar() -{ - if (GraphicsEnvironment.isHeadless()) - throw new HeadlessException (); -} - -/*************************************************************************/ - -/* - * Instance Methods - */ - -/** - * Returns the help menu for this menu bar. This may be null. - * - * @return The help menu for this menu bar. - */ -public Menu -getHelpMenu() -{ - return(helpMenu); -} - -/*************************************************************************/ - -/** - * Sets the help menu for this menu bar. - * - * @param menu The new help menu for this menu bar. - */ -public synchronized void -setHelpMenu(Menu menu) -{ - if (helpMenu != null) - { - helpMenu.removeNotify (); - helpMenu.parent = null; - } - helpMenu = menu; - - if (menu.parent != null) - menu.parent.remove (menu); - menu.parent = this; - - MenuBarPeer peer = (MenuBarPeer) getPeer (); - if (peer != null) - { - menu.addNotify(); - peer.addHelpMenu (menu); - } -} - -/*************************************************************************/ - -/** Add a menu to this MenuBar. If the menu has already has a - * parent, it is first removed from its old parent before being - * added. - * - * @param menu The menu to add. - * - * @return The menu that was added. - */ -public synchronized Menu -add(Menu menu) -{ - if (menu.parent != null) - menu.parent.remove (menu); - - menu.parent = this; - menus.addElement(menu); - - if (peer != null) - { - menu.addNotify(); - } - - return(menu); -} - -/*************************************************************************/ + public MenuBar() + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } -/** - * Removes the menu at the specified index. - * - * @param index The index of the menu to remove from the menu bar. - */ -public synchronized void -remove(int index) -{ - Menu m = (Menu) menus.get (index); - menus.remove (index); - m.removeNotify (); - m.parent = null; + /** + * Returns the help menu for this menu bar. This may be null. + * + * @return the help menu for this menu bar + */ + public Menu getHelpMenu() + { + return helpMenu; + } - if (peer != null) - { - MenuBarPeer mp = (MenuBarPeer) peer; - mp.delMenu (index); - } -} + /** + * Sets the help menu for this menu bar. + * + * @param menu the new help menu for this menu bar + */ + public synchronized void setHelpMenu(Menu menu) + { + MenuBarPeer myPeer = (MenuBarPeer) getPeer (); + + if (helpMenu != null) + { + if (myPeer != null) + helpMenu.removeNotify(); + helpMenu.setParent(null); + } + helpMenu = menu; + + MenuContainer parent = menu.getParent(); + if (parent != null) + parent.remove(menu); + menu.setParent(this); + + if (myPeer != null) + { + menu.addNotify(); + myPeer.addHelpMenu(menu); + } + } -/*************************************************************************/ + /** + * Add a menu to this MenuBar. If the menu has already has a + * parent, it is first removed from its old parent before being + * added. + * + * @param menu the menu to add + * + * @return the menu that was added + */ + public synchronized Menu add(Menu menu) + { + MenuBarPeer myPeer = (MenuBarPeer) getPeer (); -/** - * Removes the specified menu from the menu bar. - * - * @param menu The menu to remove from the menu bar. - */ -public void -remove(MenuComponent menu) -{ - int index = menus.indexOf(menu); - if (index == -1) - return; + MenuContainer parent = menu.getParent(); + if (parent != null) + parent.remove(menu); - remove(index); -} + menus.addElement(menu); + menu.setParent(this); -/*************************************************************************/ + if (myPeer != null) + { + menu.addNotify(); + myPeer.addMenu(menu); + } + return menu; + } -/** - * Returns the number of elements in this menu bar. - * - * @return The number of elements in the menu bar. - */ -public int -getMenuCount() -{ - return countMenus (); -} + /** + * Removes the menu at the specified index. + * + * @param index the index of the menu to remove from the menu bar + */ + public synchronized void remove(int index) + { + Menu m = (Menu) menus.remove(index); + MenuBarPeer mp = (MenuBarPeer) getPeer(); -/*************************************************************************/ + if (mp != null) + m.removeNotify(); -/** - * Returns the number of elements in this menu bar. - * - * @return The number of elements in the menu bar. - * - * @deprecated This method is deprecated in favor of getMenuCount(). - */ -public int -countMenus() -{ - return menus.size () + (getHelpMenu () == null ? 0 : 1); -} + m.setParent(null); -/*************************************************************************/ + if (mp != null) + mp.delMenu(index); + } -/** - * Returns the menu at the specified index. - * - * @param index the index of the menu - * - * @return The requested menu. - * - * @exception ArrayIndexOutOfBoundsException If the index is not valid. - */ -public Menu -getMenu(int index) -{ - return((Menu)menus.elementAt(index)); -} + /** + * Removes the specified menu from the menu bar. + * + * @param menu the menu to remove from the menu bar + */ + public void remove(MenuComponent menu) + { + int index = menus.indexOf(menu); + if (index == -1) + return; -/*************************************************************************/ + remove(index); + } -/** - * Creates this object's native peer. - */ -public void -addNotify() -{ - if (getPeer() == null) - setPeer((MenuComponentPeer)getToolkit().createMenuBar(this)); - Enumeration e = menus.elements(); - while (e.hasMoreElements()) + /** + * Returns the number of elements in this menu bar. + * + * @return the number of elements in the menu bar + */ + public int getMenuCount() { - Menu mi = (Menu)e.nextElement(); - mi.addNotify(); + return countMenus(); } - if (helpMenu != null) + + /** + * Returns the number of elements in this menu bar. + * + * @return the number of elements in the menu bar + * + * @deprecated This method is deprecated in favor of + * getMenuCount(). + */ + public int countMenus() { - helpMenu.addNotify(); - ((MenuBarPeer) peer).addHelpMenu(helpMenu); + return menus.size() + (getHelpMenu() == null ? 0 : 1); } -} -/*************************************************************************/ - -/** - * Destroys this object's native peer. - */ -public void -removeNotify() -{ - Enumeration e = menus.elements(); - while (e.hasMoreElements()) + /** + * Returns the menu at the specified index. + * + * @param index the index of the menu + * + * @return the requested menu + * + * @throws ArrayIndexOutOfBoundsException if the index is not valid + */ + public Menu getMenu(int index) { - Menu mi = (Menu) e.nextElement(); - mi.removeNotify(); + return (Menu) menus.elementAt(index); } - super.removeNotify(); -} - -/*************************************************************************/ - -/** - * Returns a list of all shortcuts for the menus in this menu bar. - * - * @return A list of all shortcuts for the menus in this menu bar. - */ -public synchronized Enumeration -shortcuts() -{ - Vector shortcuts = new Vector(); - Enumeration e = menus.elements(); - - while (e.hasMoreElements()) - { - Menu menu = (Menu)e.nextElement(); - if (menu.getShortcut() != null) - shortcuts.addElement(menu.getShortcut()); - } - return(shortcuts.elements()); -} + /** + * Creates this object's native peer. + */ + public void addNotify() + { + MenuBarPeer peer = (MenuBarPeer) getPeer(); + if (peer == null) + { + peer = getToolkit().createMenuBar(this); + setPeer(peer); + } + + Enumeration e = menus.elements(); + while (e.hasMoreElements()) + { + Menu mi = (Menu)e.nextElement(); + mi.addNotify(); + peer.addMenu(mi); + } + + if (helpMenu != null) + { + helpMenu.addNotify(); + peer.addHelpMenu(helpMenu); + } + } -/*************************************************************************/ + /** + * Destroys this object's native peer. + */ + public void removeNotify() + { + Enumeration e = menus.elements(); + while (e.hasMoreElements()) + { + Menu mi = (Menu) e.nextElement(); + mi.removeNotify(); + } + super.removeNotify(); + } -/** - * Returns the menu item for the specified shortcut, or null - * if no such item exists. - * - * @param shortcut The shortcut to return the menu item for. - * - * @return The menu item for the specified shortcut. - */ -public MenuItem -getShortcutMenuItem(MenuShortcut shortcut) -{ - Enumeration e = menus.elements(); + /** + * Returns a list of all shortcuts for the menus in this menu bar. + * + * @return a list of all shortcuts for the menus in this menu bar + */ + public synchronized Enumeration shortcuts() + { + Vector shortcuts = new Vector(); + Enumeration e = menus.elements(); - while (e.hasMoreElements()) - { - Menu menu = (Menu)e.nextElement(); - MenuShortcut s = menu.getShortcut(); - if ((s != null) && (s.equals(shortcut))) - return(menu); - } + while (e.hasMoreElements()) + { + Menu menu = (Menu)e.nextElement(); + if (menu.getShortcut() != null) + shortcuts.addElement(menu.getShortcut()); + } - return(null); -} + return shortcuts.elements(); + } -/*************************************************************************/ + /** + * Returns the menu item for the specified shortcut, or null + * if no such item exists. + * + * @param shortcut the shortcut to return the menu item for + * + * @return the menu item for the specified shortcut + */ + public MenuItem getShortcutMenuItem(MenuShortcut shortcut) + { + Enumeration e = menus.elements(); -/** - * Deletes the specified menu shortcut. - * - * @param shortcut The shortcut to delete. - */ -public void -deleteShortcut(MenuShortcut shortcut) -{ - MenuItem it; - // This is a slow implementation, but it probably doesn't matter. - while ((it = getShortcutMenuItem (shortcut)) != null) - it.deleteShortcut (); -} + while (e.hasMoreElements()) + { + Menu menu = (Menu) e.nextElement(); + MenuShortcut s = menu.getShortcut(); + if ((s != null) && s.equals(shortcut)) + return menu; + } -/** - * Gets the AccessibleContext associated with this MenuBar. - * The context is created, if necessary. - * - * @return the associated context - */ -public AccessibleContext getAccessibleContext() -{ - /* Create the context if this is the first request */ - if (accessibleContext == null) - accessibleContext = new AccessibleAWTMenuBar(); - return accessibleContext; -} + return null; + } -/** - * This class provides accessibility support for AWT menu bars. - * - * @author Andrew John Hughes (gnu_andrew@member.fsf.org) - */ -protected class AccessibleAWTMenuBar - extends AccessibleAWTMenuComponent -{ - /** - * Compatible with JDK 1.4.2 revision 5 + * Deletes the specified menu shortcut. + * + * @param shortcut the shortcut to delete */ - private static final long serialVersionUID = -8577604491830083815L; + public void deleteShortcut(MenuShortcut shortcut) + { + MenuItem it; + // This is a slow implementation, but it probably doesn't matter. + while ((it = getShortcutMenuItem (shortcut)) != null) + it.deleteShortcut(); + } /** - * This is the default constructor, which simply calls the default - * constructor of the superclass. + * Gets the AccessibleContext associated with this MenuBar. + * The context is created, if necessary. + * + * @return the associated context */ - protected AccessibleAWTMenuBar() + public AccessibleContext getAccessibleContext() { - super(); + // Create the context if this is the first request. + if (accessibleContext == null) + accessibleContext = new AccessibleAWTMenuBar(); + return accessibleContext; } /** - * Returns the accessible role relating to the menu bar. + * This class provides accessibility support for AWT menu bars. * - * @return AccessibleRole.MENU_BAR. + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) */ - public AccessibleRole getAccessibleRole() + protected class AccessibleAWTMenuBar + extends AccessibleAWTMenuComponent { - return AccessibleRole.MENU_BAR; - } + + /** + * Compatible with JDK 1.4.2 revision 5 + */ + private static final long serialVersionUID = -8577604491830083815L; + + /** + * This is the default constructor, which simply calls the default + * constructor of the superclass. + */ + protected AccessibleAWTMenuBar() + { + super(); + } -} // class AccessibleAWTMenuBar + /** + * Returns the accessible role relating to the menu bar. + * + * @return AccessibleRole.MENU_BAR + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.MENU_BAR; + } -} // class MenuBar + } + +} diff --git a/java/awt/MenuComponent.java b/java/awt/MenuComponent.java index 375d08436..9bb875069 100644 --- a/java/awt/MenuComponent.java +++ b/java/awt/MenuComponent.java @@ -1,5 +1,6 @@ /* MenuComponent.java -- Superclass of all AWT menu components - Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -60,26 +61,16 @@ import javax.accessibility.AccessibleStateSet; public abstract class MenuComponent implements Serializable { -/* - * Static Variables - */ +//Serialization Constant + private static final long serialVersionUID = -4536902356223894379L; -// Serialization Constant -private static final long serialVersionUID = -4536902356223894379L; - -/*************************************************************************/ - -/* - * Instance Variables - */ - -/** - * The font for this component. - * - * @see #getFont() - * @see #setFont(java.awt.Font) - * @serial the component's font. - */ + /** + * The font for this component. + * + * @see #getFont() + * @see #setFont(java.awt.Font) + * @serial the component's font. + */ private Font font; /** @@ -165,1160 +156,1133 @@ private static final long serialVersionUID = -4536902356223894379L; */ transient FocusListener focusListener; -/*************************************************************************/ - -/* - * Constructors - */ - -/** - * Default constructor for subclasses. - * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. - */ -public -MenuComponent() -{ - if (GraphicsEnvironment.isHeadless()) - throw new HeadlessException (); -} - -/*************************************************************************/ - -/* - * Instance Methods - */ + /** + * Default constructor for subclasses. + * + * @throws HeadlessException ff GraphicsEnvironment.isHeadless() is true + */ + public MenuComponent() + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } /** * Returns the font in use for this component. * - * @return The font for this component. - */ -public Font -getFont() -{ - if (font != null) - return font; - - if (parent != null) - return parent.getFont (); - - return null; -} - -/*************************************************************************/ - -/** - * Sets the font for this component to the specified font. - * - * @param font The new font for this component. - */ -public void -setFont(Font font) -{ - this.font = font; -} - -/*************************************************************************/ - -/** - * Returns the name of this component. - * - * @return The name of this component. - */ -public String -getName() -{ - return(name); -} - -/*************************************************************************/ - -/** - * Sets the name of this component to the specified name. - * - * @param name The new name of this component. - */ -public void -setName(String name) -{ - this.name = name; - nameExplicitlySet = true; -} - -/*************************************************************************/ - -/** - * Returns the parent of this component. - * - * @return The parent of this component. - */ -public MenuContainer -getParent() -{ - return(parent); -} - -/*************************************************************************/ - -// Sets the parent of this component. -final void -setParent(MenuContainer parent) -{ - this.parent = parent; -} - -/*************************************************************************/ - -/** - * Returns the native windowing system peer for this component. - * - * @return The peer for this component. - * - * @deprecated - */ -public MenuComponentPeer -getPeer() -{ - return(peer); -} - -/*************************************************************************/ - -// Sets the peer for this component. -final void -setPeer(MenuComponentPeer peer) -{ - this.peer = peer; -} - -/*************************************************************************/ - -/** - * Destroys this component's native peer - */ -public void -removeNotify() -{ - if (peer != null) - peer.dispose(); - peer = null; -} - -/*************************************************************************/ - -/** - * Returns the toolkit in use for this component. - * - * @return The toolkit for this component. - */ -final Toolkit -getToolkit() -{ - return(toolkit); -} - -/*************************************************************************/ - -/** - * Returns the object used for synchronization locks on this component - * when performing tree and layout functions. - * - * @return The synchronization lock for this component. - */ -protected final Object -getTreeLock() -{ - return(tree_lock); -} - -/*************************************************************************/ - -// The sync lock object for this component. -final void -setTreeLock(Object tree_lock) -{ - this.tree_lock = tree_lock; -} - -/*************************************************************************/ - -/** - * AWT 1.0 event dispatcher. - * - * @deprecated Deprecated in favor of dispatchEvent(). - * @return true if the event was dispatched, false otherwise. - */ -public boolean -postEvent(Event event) -{ - // This is overridden by subclasses that support events. - return false; -} -/*************************************************************************/ - -/** - * Sends this event to this component or a subcomponent for processing. - * - * @param event The event to dispatch - */ -public final void dispatchEvent(AWTEvent event) -{ - // See comment in Component.dispatchEvent(). - dispatchEventImpl(event); -} - - -/** - * Implementation of dispatchEvent. Allows trusted package classes - * to dispatch additional events first. This implementation first - * translates event to an AWT 1.0 event and sends the - * result to {@link #postEvent}. The event is then - * passed on to {@link #processEvent} for local processing. - * - * @param event the event to dispatch. - */ -void dispatchEventImpl(AWTEvent event) -{ - Event oldStyleEvent; - - // This is overridden by subclasses that support events. - /* Convert AWT 1.1 event to AWT 1.0 event */ - oldStyleEvent = Component.translateEvent(event); - if (oldStyleEvent != null) - { - postEvent(oldStyleEvent); - } - /* Do local processing */ - processEvent(event); -} - -/*************************************************************************/ - -/** - * Processes the specified event. In this class, this method simply - * calls one of the more specific event handlers. - * - * @param event The event to process. - */ -protected void -processEvent(AWTEvent event) -{ - /* - Pass a focus event to the focus listener for - the accessibility context. - */ - if (event instanceof FocusEvent) - { - if (focusListener != null) - { - switch (event.id) - { - case FocusEvent.FOCUS_GAINED: - focusListener.focusGained((FocusEvent) event); - break; - case FocusEvent.FOCUS_LOST: - focusListener.focusLost((FocusEvent) event); - break; - } - } - } -} - -/*************************************************************************/ - -/** - * Returns a string representation of this component. - * - * @return A string representation of this component + * @return the font for this component */ -public String -toString() -{ - return this.getClass().getName() + "[" + paramString() + "]"; -} - -/*************************************************************************/ - -/** - * Returns a debugging string for this component - */ -protected String -paramString() -{ - return "name=" + getName(); -} - -/** - * Gets the AccessibleContext associated with this MenuComponent. - * As an abstract class, we return null. Concrete subclasses should return - * their implementation of the accessibility context. - * - * @return null. - */ - -public AccessibleContext getAccessibleContext() -{ - return null; -} + public Font getFont() + { + if (font != null) + return font; -/** - * This class provides a base for the accessibility support of menu - * components. - * - * @author Andrew John Hughes (gnu_andrew@member.fsf.org) - */ -protected abstract class AccessibleAWTMenuComponent - extends AccessibleContext - implements Serializable, AccessibleComponent, AccessibleSelection -{ + if (parent != null) + return parent.getFont(); - /** - * Compatible with JDK 1.4.2 revision 5 - */ - private static final long serialVersionUID = -4269533416223798698L; - - /** - * This is the default constructor. It should be called by - * concrete subclasses to ensure necessary groundwork is completed. - */ - protected AccessibleAWTMenuComponent() - { + return null; } /** - * Replaces or supplements the component's selection with the - * Accessible child at the supplied index. If - * the component supports multiple selection, the child is - * added to the current selection. Otherwise, the current - * selection becomes the specified child. If the child is - * already selected, nothing happens. - *
    - *
    - * As the existence of children can not be determined from - * this abstract class, the implementation of this method - * is left to subclasses. + * Sets the font for this component to the specified font. * - * @param index the index of the specified child within a - * zero-based list of the component's children. + * @param font the new font for this component */ - public void addAccessibleSelection(int index) + public void setFont(Font font) { - /* Subclasses with children should implement this */ + this.font = font; } /** - * Registers the specified focus listener to receive - * focus events from this component. + * Returns the name of this component. * - * @param listener the new focus listener. + * @return the name of this component */ - public void addFocusListener(FocusListener listener) + public String getName() { - /* - * Chain the new focus listener to the existing chain - * of focus listeners. Each new focus listener is - * coupled via multicasting to the existing chain. - */ - focusListener = AWTEventMulticaster.add(focusListener, listener); + return name; } /** - * Clears the component's current selection. Following - * the calling of this method, no children of the component - * will be selected. - *
    - *
    - * As the existence of children can not be determined from - * this abstract class, the implementation of this method - * is left to subclasses. - */ - public void clearAccessibleSelection() - { - } - - /** - * Returns true if the specified point lies within the - * component. The supplied co-ordinates are assumed to - * be relative to the co-ordinate system of the component - * itself. Thus, the point (0,0) is the upper left corner - * of this component. - *
    - *
    - * Please note that this method depends on a correctly implemented - * version of the getBounds() method. Subclasses - * must provide the bounding rectangle via getBounds() - * in order for this method to work. + * Sets the name of this component to the specified name. * - * @param point the point to check against this component. - * @return true if the point is within this component. - * @see #getBounds() + * @param name the new name of this component */ - public boolean contains(Point point) + public void setName(String name) { - /* - We can simply return the result of a - test for containment in the bounding rectangle - */ - return getBounds().contains(point); + this.name = name; + nameExplicitlySet = true; } /** - * Returns the Accessible child of this component present - * at the specified point. The supplied co-ordinates are - * assumed to be relative to the co-ordinate system of this - * component (the parent of any returned accessible). Thus, - * the point (0,0) is the upper left corner of this menu - * component. - *
    - *
    - * As the existence of children can not be determined from - * this abstract class, the implementation of this method - * is left to subclasses. + * Returns the parent of this component. * - * @param point the point at which the returned accessible - * is located. - * @return null. + * @return the parent of this component */ - public Accessible getAccessibleAt(Point point) + public MenuContainer getParent() { - return null; - } + return parent; + } /** - * Returns the Accessible child at the supplied - * index within the list of children of this component. - *
    - *
    - * As the existence of children can not be determined from - * this abstract class, the implementation of this method - * is left to subclasses. + * Sets the parent of this component. * - * @param index the index of the Accessible child - * to retrieve. - * @return null. + * @param parent the parent to set */ - public Accessible getAccessibleChild(int index) + final void setParent(MenuContainer parent) { - return null; + this.parent = parent; } /** - * Returns the number of children of this component which - * implement the Accessible interface. If - * all children of this component are accessible, then - * the returned value will be the same as the number of - * children. - *
    - *
    + * Returns the native windowing system peer for this component. + * + * @return the peer for this component * - * @return 0. + * @deprecated */ - public int getAccessibleChildrenCount() + public MenuComponentPeer getPeer() { - return 0; + return peer; } /** - * Retrieves the AccessibleComponent associated - * with this accessible context and its component. As the - * context itself implements AccessibleComponent, - * this is the return value. + * Sets the peer for this component. * - * @return the context itself. + * @param peer the peer to set */ - public AccessibleComponent getAccessibleComponent() + final void setPeer(MenuComponentPeer peer) { - return this; + this.peer = peer; } /** - * Returns the accessible name for this menu component. This - * is the name given to the component, which may be null if - * not set using setName(). - *
    - *
    - * The name is not the most appropriate description of this - * object. Subclasses should preferably provide a more - * accurate description. For example, a File menu could - * have the description `Lists commands related to the - * file system'. - * - * @return a description of the component. Currently, - * this is just the contents of the name property. - * @see MenuComponent#setName(String) + * Destroys this component's native peer */ - public String getAccessibleDescription() + public void removeNotify() { - return MenuComponent.this.getName(); + if (peer != null) + peer.dispose(); + peer = null; } /** - * Retrieves the index of this component within its parent. - * If no parent exists, -1 is returned. + * Returns the toolkit in use for this component. * - * @return -1 as the parent, a MenuContainer - * is not Accessible. + * @return the toolkit for this component */ - public int getAccessibleIndexInParent() + final Toolkit getToolkit() { - return -1; + return toolkit; } /** - * Returns the accessible name of this component. This - * is the name given to the component, which may be null if - * not set using setName(). - *
    - *
    - * The name property is not the most suitable string to return - * for this method. The string should be localized, and - * relevant to the operation of the component. For example, - * it could be the text of a menu item. However, this can - * not be used at this level of abstraction, so it is the - * responsibility of subclasses to provide a more appropriate - * name. + * Returns the object used for synchronization locks on this component + * when performing tree and layout functions. * - * @return a localized name for this component. Currently, this - * is just the contents of the name property. - * @see MenuComponent#setName(String) + * @return the synchronization lock for this component */ - public String getAccessibleName() + protected final Object getTreeLock() { - return MenuComponent.this.getName(); + return tree_lock; } /** - * Returns the Accessible parent of this component. - * As the parent of a MenuComponent is a - * MenuContainer, which doesn't implement - * Accessible, this method returns null. + * Sets the sync lock object for this component. * - * @return null. + * @param treeLock the sync lock to set */ - public Accessible getAccessibleParent() + final void setTreeLock(Object treeLock) { - return null; + this.tree_lock = treeLock; } /** - * Returns the accessible role of this component. - *
    - *
    - * The abstract implementation of this method returns - * AccessibleRole.AWT_COMPONENT, - * as the abstract component has no specific role. This - * method should be overridden by concrete subclasses, so - * as to return an appropriate role for the component. + * AWT 1.0 event dispatcher. * - * @return AccessibleRole.AWT_COMPONENT. + * @return true if the event was dispatched, false otherwise + * + * @deprecated Deprecated in favor of dispatchEvent(). */ - public AccessibleRole getAccessibleRole() + public boolean + postEvent(Event event) { - return AccessibleRole.AWT_COMPONENT; + boolean retVal = false; + MenuContainer parent = getParent(); + if (parent != null) + retVal = parent.postEvent(event); + + return retVal; } /** - * Retrieves the AccessibleSelection associated - * with this accessible context and its component. As the - * context itself implements AccessibleSelection, - * this is the return value. + * Sends this event to this component or a subcomponent for processing. * - * @return the context itself. + * @param event The event to dispatch */ - public AccessibleSelection getAccessibleSelection() + public final void dispatchEvent(AWTEvent event) { - return this; + // Convert AWT 1.1 event to AWT 1.0 event. + Event oldStyleEvent = Component.translateEvent(event); + if (oldStyleEvent != null) + { + postEvent(oldStyleEvent); + } + + // See comment in Component.dispatchEvent(). + dispatchEventImpl(event); } /** - * Retrieves the Accessible selected child - * at the specified index. If there are no selected children - * or the index is outside the range of selected children, - * null is returned. Please note that the index refers - * to the index of the child in the list of selected - * children, and not the index of the child in - * the list of all Accessible children. - *
    - *
    - * As the existence of children can not be determined from - * this abstract class, the implementation of this method - * is left to subclasses. + * Implementation of dispatchEvent. Allows trusted package classes + * to dispatch additional events first. This implementation first + * translates event to an AWT 1.0 event and sends the + * result to {@link #postEvent}. The event is then + * passed on to {@link #processEvent} for local processing. * - * @param index the index of the selected Accessible - * child. + * @param event the event to dispatch */ - public Accessible getAccessibleSelection(int index) + void dispatchEventImpl(AWTEvent event) { - return null; + // Do local processing. + processEvent(event); } /** - * Returns a count of the number of Accessible - * children of this component which are currently selected. - * If there are no children currently selected, 0 is returned. - *
    - *
    - * As the existence of children can not be determined from - * this abstract class, the implementation of this method - * is left to subclasses. - * - * @return 0. + * Processes the specified event. In this class, this method simply + * calls one of the more specific event handlers. + * + * @param event the event to process */ - public int getAccessibleSelectionCount() + protected void processEvent(AWTEvent event) { - return 0; + // Pass a focus event to the focus listener for + // the accessibility context. + if (event instanceof FocusEvent) + { + if (focusListener != null) + { + switch (event.id) + { + case FocusEvent.FOCUS_GAINED: + focusListener.focusGained((FocusEvent) event); + break; + case FocusEvent.FOCUS_LOST: + focusListener.focusLost((FocusEvent) event); + break; + } + } + } } /** - * Retrieves the current state of this component - * in an accessible form. For example, a given component - * may be visible, selected, disabled, etc. - *
    - *
    - * As this class tells us virtually nothing about the component, - * except for its name and font, no state information can be - * provided. This implementation thus returns an empty - * state set, and it is left to concrete subclasses to provide - * a more acceptable and relevant state set. Changes to these - * properties also need to be handled using - * PropertyChangeListeners. + * Returns a string representation of this component. * - * @return an empty AccessibleStateSet. + * @return a string representation of this component */ - public AccessibleStateSet getAccessibleStateSet() + public String toString() { - return new AccessibleStateSet(); + return getClass().getName() + "[" + paramString() + "]"; } /** - * Returns the background color of the component, or null - * if this property is unsupported. - *
    - *
    - * This abstract class knows nothing about how the component - * is drawn on screen, so this method simply returns the - * default system background color used for rendering menus. - * Concrete subclasses which handle the drawing of an onscreen - * menu component should override this method and provide - * the appropriate information. - * - * @return the default system background color for menus. - * @see #setBackground(java.awt.Color) + * Returns a debugging string for this component */ - public Color getBackground() + protected String paramString() { - return SystemColor.menu; + return "name=" + getName(); } /** - * Returns a Rectangle which represents the - * bounds of this component. The returned rectangle has the - * height and width of the component's bounds, and is positioned - * at a location relative to this component's parent, the - * MenuContainer. null is returned if bounds - * are not supported by the component. - *
    - *
    - * This abstract class knows nothing about how the component - * is drawn on screen, so this method simply returns null. - * Concrete subclasses which handle the drawing of an onscreen - * menu component should override this method and provide - * the appropriate information. + * Gets the AccessibleContext associated with this MenuComponent. + * As an abstract class, we return null. Concrete subclasses should return + * their implementation of the accessibility context. * - * @return null. - * @see #setBounds(java.awt.Rectangle) + * @return null */ - public Rectangle getBounds() + public AccessibleContext getAccessibleContext() { return null; } /** - * Returns the Cursor displayed when the pointer - * is positioned over this component. Alternatively, null - * is returned if the component doesn't support the cursor - * property. - *
    - *
    - * This abstract class knows nothing about how the component - * is drawn on screen, so this method simply returns the default - * system cursor. Concrete subclasses which handle the drawing - * of an onscreen menu component may override this method and provide - * the appropriate information. + * This class provides a base for the accessibility support of menu + * components. * - * @return the default system cursor. - * @see #setCursor(java.awt.Cursor) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) */ - public Cursor getCursor() + protected abstract class AccessibleAWTMenuComponent + extends AccessibleContext + implements Serializable, AccessibleComponent, AccessibleSelection { - return Cursor.getDefaultCursor(); - } - /** - * Returns the Font used for text created by this component. - * - * @return the current font. - * @see #setFont(java.awt.Font) - */ - public Font getFont() - { - return MenuComponent.this.getFont(); - } + /** + * Compatible with JDK 1.4.2 revision 5 + */ + private static final long serialVersionUID = -4269533416223798698L; - /** - * Retrieves information on the rendering and metrics of the supplied - * font. If font metrics are not supported by this component, null - * is returned. - *
    - *
    - * The abstract implementation of this method simply uses the toolkit - * to obtain the FontMetrics. Concrete subclasses may - * find it more efficient to invoke their peer class directly, if one - * is available. - * - * @param font the font about which to retrieve rendering and metric - * information. - * @return the metrics of the given font, as provided by the system - * toolkit. - * @throws NullPointerException if the supplied font was null. - */ - public FontMetrics getFontMetrics(Font font) - { - return MenuComponent.this.getToolkit().getFontMetrics(font); - } + /** + * This is the default constructor. It should be called by + * concrete subclasses to ensure necessary groundwork is completed. + */ + protected AccessibleAWTMenuComponent() + { + // Nothing to do here. + } - /** - * Returns the foreground color of the component, or null - * if this property is unsupported. - *
    - *
    - * This abstract class knows nothing about how the component - * is drawn on screen, so this method simply returns the - * default system text color used for rendering menus. - * Concrete subclasses which handle the drawing of an onscreen - * menu component should override this method and provide - * the appropriate information. - * - * @return the default system text color for menus. - * @see #setForeground(java.awt.Color) - */ - public Color getForeground() - { - return SystemColor.menuText; - } + /** + * Replaces or supplements the component's selection with the + * Accessible child at the supplied index. If + * the component supports multiple selection, the child is + * added to the current selection. Otherwise, the current + * selection becomes the specified child. If the child is + * already selected, nothing happens. + *
    + *
    + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the specified child within a + * zero-based list of the component's children + */ + public void addAccessibleSelection(int index) + { + // Subclasses with children should implement this. + } - /** - * Returns the locale currently in use by this component. - *
    - *
    - * This abstract class has no property relating to the - * locale used by the component, so this method simply - * returns the default locale for the current instance - * of the Java Virtual Machine (JVM). Concrete subclasses - * which maintain such a property should override this method - * and provide the locale information more accurately. - * - * @return the default locale for this JVM instance. - */ - public Locale getLocale() - { - return Locale.getDefault(); - } + /** + * Registers the specified focus listener to receive + * focus events from this component. + * + * @param listener the new focus listener + */ + public void addFocusListener(FocusListener listener) + { + // Chain the new focus listener to the existing chain + // of focus listeners. Each new focus listener is + // coupled via multicasting to the existing chain. + focusListener = AWTEventMulticaster.add(focusListener, listener); + } - /** - * Returns the location of the component, with co-ordinates - * relative to the parent component and using the co-ordinate - * space of the screen. Thus, the point (0,0) is the upper - * left corner of the parent component. - *
    - *
    - * Please note that this method depends on a correctly implemented - * version of the getBounds() method. Subclasses - * must provide the bounding rectangle via getBounds() - * in order for this method to work. - * - * @return the location of the component, relative to its parent. - * @see #setLocation(java.awt.Point) - */ - public Point getLocation() - { - /* Simply return the location of the bounding rectangle */ - return getBounds().getLocation(); - } + /** + * Clears the component's current selection. Following + * the calling of this method, no children of the component + * will be selected. + *
    + *
    + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + */ + public void clearAccessibleSelection() + { + // Nothing to do here. + } - /** - * Returns the location of the component, with co-ordinates - * relative to the screen. Thus, the point (0,0) is the upper - * left corner of the screen. null is returned if the component - * is either not on screen or if this property is unsupported. - *
    - *
    - * This abstract class knows nothing about how the component - * is drawn on screen, so this method simply returns null. - * Concrete subclasses which handle the drawing of an onscreen - * menu component should override this method and provide - * the appropriate information. - * - * @return the location of the component, relative to the screen. - */ - public Point getLocationOnScreen() - { - return null; - } + /** + * Returns true if the specified point lies within the + * component. The supplied co-ordinates are assumed to + * be relative to the co-ordinate system of the component + * itself. Thus, the point (0,0) is the upper left corner + * of this component. + *
    + *
    + * Please note that this method depends on a correctly implemented + * version of the getBounds() method. Subclasses + * must provide the bounding rectangle via getBounds() + * in order for this method to work. + * + * @param point the point to check against this component + * @return true if the point is within this component + * @see #getBounds() + */ + public boolean contains(Point point) + { + // We can simply return the result of a + // test for containment in the bounding rectangle. + return getBounds().contains(point); + } - /** - * Returns the size of the component. - *
    - *
    - * Please note that this method depends on a correctly implemented - * version of the getBounds() method. Subclasses - * must provide the bounding rectangle via getBounds() - * in order for this method to work. - * - * @return the size of the component. - * @see #setSize(java.awt.Dimension) - */ - public Dimension getSize() - { - /* Simply return the size of the bounding rectangle */ - return getBounds().getSize(); - } + /** + * Returns the Accessible child of this component present + * at the specified point. The supplied co-ordinates are + * assumed to be relative to the co-ordinate system of this + * component (the parent of any returned accessible). Thus, + * the point (0,0) is the upper left corner of this menu + * component. + *
    + *
    + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param point the point at which the returned accessible + * is located + * @return null + */ + public Accessible getAccessibleAt(Point point) + { + return null; + } - /** - * Returns true if the accessible child specified by the supplied index - * is currently selected. - *
    - *
    - * As the existence of children can not be determined from - * this abstract class, the implementation of this method - * is left to subclasses. - * - * @param index the index of the accessible child to check for selection. - * @return false. - */ - public boolean isAccessibleChildSelected(int index) - { - return false; - } + /** + * Returns the Accessible child at the supplied + * index within the list of children of this component. + *
    + *
    + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the Accessible child + * to retrieve + * + * @return null + */ + public Accessible getAccessibleChild(int index) + { + return null; + } - /** - * Returns true if this component is currently enabled. - *
    - *
    - * As this abstract component has no properties related to - * its enabled or disabled state, the implementation of this - * method is left to subclasses. - * - * @return false. - * @see #setEnabled(boolean) - */ - public boolean isEnabled() - { - return false; - } + /** + * Returns the number of children of this component which + * implement the Accessible interface. If + * all children of this component are accessible, then + * the returned value will be the same as the number of + * children. + *
    + *
    + * + * @return 0 + */ + public int getAccessibleChildrenCount() + { + return 0; + } - /** - * Returns true if this component is included in the traversal - * of the current focus from one component to the other. - *
    - *
    - * As this abstract component has no properties related to - * its ability to accept the focus, the implementation of this - * method is left to subclasses. - * - * @return false. - */ - public boolean isFocusTraversable() - { - return false; - } + /** + * Retrieves the AccessibleComponent associated + * with this accessible context and its component. As the + * context itself implements AccessibleComponent, + * this is the return value. + * + * @return the context itself + */ + public AccessibleComponent getAccessibleComponent() + { + return this; + } - /** - * Returns true if the component is being shown on screen. - * A component is determined to be shown if it is visible, - * and each parent component is also visible. Please note - * that, even when a component is showing, it may still be - * obscured by other components in front. This method only - * determines if the component is being drawn on the screen. - *
    - *
    - * As this abstract component and its parent have no properties - * relating to visibility, the implementation of this method is - * left to subclasses. - * - * @return false. - * @see #isVisible() - */ - public boolean isShowing() - { - return false; - } + /** + * Returns the accessible name for this menu component. This + * is the name given to the component, which may be null if + * not set using setName(). + *
    + *
    + * The name is not the most appropriate description of this + * object. Subclasses should preferably provide a more + * accurate description. For example, a File menu could + * have the description `Lists commands related to the + * file system'. + * + * @return a description of the component. Currently, + * this is just the contents of the name property + * + * @see MenuComponent#setName(String) + */ + public String getAccessibleDescription() + { + return MenuComponent.this.getName(); + } - /** - * Returns true if the component is visible. A component may - * be visible but not drawn on the screen if one of its parent - * components is not visible. To determine if the component is - * actually drawn on screen, isShowing() should be - * used. - *
    - *
    - * As this abstract component has no properties relating to its - * visibility, the implementation of this method is left to subclasses. - * - * @return false. - * @see #isShowing() - * @see #setVisible(boolean) - */ - public boolean isVisible() - { - return false; - } + /** + * Retrieves the index of this component within its parent. + * If no parent exists, -1 is returned. + * + * @return -1 as the parent, a MenuContainer + * is not Accessible + */ + public int getAccessibleIndexInParent() + { + return -1; + } - /** - * Removes the accessible child specified by the supplied index from - * the list of currently selected children. If the child specified - * is not selected, nothing happens. - *
    - *
    - * As the existence of children can not be determined from - * this abstract class, the implementation of this method - * is left to subclasses. - * - * @param index the index of the Accessible child. - */ - public void removeAccessibleSelection(int index) - { - /* Subclasses with children should implement this */ - } + /** + * Returns the accessible name of this component. This + * is the name given to the component, which may be null if + * not set using setName(). + *
    + *
    + * The name property is not the most suitable string to return + * for this method. The string should be localized, and + * relevant to the operation of the component. For example, + * it could be the text of a menu item. However, this can + * not be used at this level of abstraction, so it is the + * responsibility of subclasses to provide a more appropriate + * name. + * + * @return a localized name for this component. Currently, this + * is just the contents of the name property + * + * @see MenuComponent#setName(String) + */ + public String getAccessibleName() + { + return MenuComponent.this.getName(); + } - /** - * Removes the specified focus listener from the list of registered - * focus listeners for this component. - * - * @param listener the listener to remove. - */ - public void removeFocusListener(FocusListener listener) - { - /* Remove the focus listener from the chain */ - focusListener = AWTEventMulticaster.remove(focusListener, listener); - } + /** + * Returns the Accessible parent of this component. + * As the parent of a MenuComponent is a + * MenuContainer, which doesn't implement + * Accessible, this method returns null. + * + * @return null + */ + public Accessible getAccessibleParent() + { + return null; + } - /** - * Requests that this component gains focus. This depends on the - * component being focus traversable. - *
    - *
    - * As this abstract component has no properties relating to its - * focus traversability, or access to a peer with request focusing - * abilities, the implementation of this method is left to subclasses. - */ - public void requestFocus() - { - /* Ignored */ - } + /** + * Returns the accessible role of this component. + *
    + *
    + * The abstract implementation of this method returns + * AccessibleRole.AWT_COMPONENT, + * as the abstract component has no specific role. This + * method should be overridden by concrete subclasses, so + * as to return an appropriate role for the component. + * + * @return AccessibleRole.AWT_COMPONENT + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.AWT_COMPONENT; + } - /** - * Selects all Accessible children of this component which - * it is possible to select. The component needs to support multiple - * selections. - *
    - *
    - * This abstract component provides a simplistic implementation of this - * method, which ignores the ability of the component to support multiple - * selections and simply uses addAccessibleSelection to - * add each Accessible child to the selection. The last - * Accessible component is thus selected for components - * which don't support multiple selections. Concrete implementations should - * override this with a more appopriate and efficient implementation, which - * properly takes into account the ability of the component to support multiple - * selections. - */ - public void selectAllAccessibleSelection() - { - /* Simply call addAccessibleSelection() on all accessible children */ - for (int a = 0; a < getAccessibleChildrenCount(); ++a) - { - addAccessibleSelection(a); - } - } + /** + * Retrieves the AccessibleSelection associated + * with this accessible context and its component. As the + * context itself implements AccessibleSelection, + * this is the return value. + * + * @return the context itself + */ + public AccessibleSelection getAccessibleSelection() + { + return this; + } - /** - * Sets the background color of the component to that specified. - * Unspecified behaviour occurs when null is given as the new - * background color. - *
    - *
    - * This abstract class knows nothing about how the component - * is drawn on screen, so this method simply ignores the supplied - * color and continues to use the default system color. - * Concrete subclasses which handle the drawing of an onscreen - * menu component should override this method and provide - * the appropriate information. - * - * @param color the new color to use for the background. - * @see #getBackground() - */ - public void setBackground(Color color) - { - /* Ignored */ - } + /** + * Retrieves the Accessible selected child + * at the specified index. If there are no selected children + * or the index is outside the range of selected children, + * null is returned. Please note that the index refers + * to the index of the child in the list of selected + * children, and not the index of the child in + * the list of all Accessible children. + *
    + *
    + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the selected Accessible + * child + */ + public Accessible getAccessibleSelection(int index) + { + return null; + } - /** - * Sets the height and width of the component, and its position - * relative to this component's parent, to the values specified - * by the supplied rectangle. Unspecified behaviour occurs when - * null is given as the new bounds. - *
    - *
    - * This abstract class knows nothing about how the component - * is drawn on screen, so this method simply ignores the new - * rectangle and continues to return null from getBounds(). - * Concrete subclasses which handle the drawing of an onscreen - * menu component should override this method and provide - * the appropriate information. - * - * @param rectangle a rectangle which specifies the new bounds of - * the component. - * @see #getBounds() - */ - public void setBounds(Rectangle rectangle) - { - /* Ignored */ - } + /** + * Returns a count of the number of Accessible + * children of this component which are currently selected. + * If there are no children currently selected, 0 is returned. + *
    + *
    + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @return 0 + */ + public int getAccessibleSelectionCount() + { + return 0; + } - /** - * Sets the Cursor used when the pointer is positioned over the - * component. Unspecified behaviour occurs when null is given as the new - * cursor. - *
    - *
    - * This abstract class knows nothing about how the component - * is drawn on screen, so this method simply ignores the new cursor - * and continues to return the default system cursor. Concrete - * subclasses which handle the drawing of an onscreen menu component - * may override this method and provide the appropriate information. - * - * @param cursor the new cursor to use. - * @see #getCursor() - */ - public void setCursor(Cursor cursor) - { - /* Ignored */ - } + /** + * Retrieves the current state of this component + * in an accessible form. For example, a given component + * may be visible, selected, disabled, etc. + *
    + *
    + * As this class tells us virtually nothing about the component, + * except for its name and font, no state information can be + * provided. This implementation thus returns an empty + * state set, and it is left to concrete subclasses to provide + * a more acceptable and relevant state set. Changes to these + * properties also need to be handled using + * PropertyChangeListeners. + * + * @return an empty AccessibleStateSet + */ + public AccessibleStateSet getAccessibleStateSet() + { + return new AccessibleStateSet(); + } - /** - * Sets the enabled/disabled state of this component. - *
    - *
    - * As this abstract component has no properties related to - * its enabled or disabled state, the implementation of this - * method is left to subclasses. - * - * @param enabled true if the component should be enabled, - * false otherwise. - * @see #isEnabled() - */ - public void setEnabled(boolean enabled) - { - /* Ignored */ - } + /** + * Returns the background color of the component, or null + * if this property is unsupported. + *
    + *
    + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns the + * default system background color used for rendering menus. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return the default system background color for menus + * + * @see #setBackground(java.awt.Color) + */ + public Color getBackground() + { + return SystemColor.menu; + } - /** - * Sets the Font used for text created by this component. - * Unspecified behaviour occurs when null is given as the new - * font. - * - * @param font the new font to use for text. - * @see #getFont() - */ - public void setFont(Font font) - { - /* Call the method of the enclosing component */ - MenuComponent.this.setFont(font); - } + /** + * Returns a Rectangle which represents the + * bounds of this component. The returned rectangle has the + * height and width of the component's bounds, and is positioned + * at a location relative to this component's parent, the + * MenuContainer. null is returned if bounds + * are not supported by the component. + *
    + *
    + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns null. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return null + * + * @see #setBounds(java.awt.Rectangle) + */ + public Rectangle getBounds() + { + return null; + } - /** - * Sets the foreground color of the component to that specified. - * Unspecified behaviour occurs when null is given as the new - * background color. - *
    - *
    - * This abstract class knows nothing about how the component - * is drawn on screen, so this method simply ignores the supplied - * color and continues to return the default system text color used - * for rendering menus. - * Concrete subclasses which handle the drawing of an onscreen - * menu component should override this method and provide - * the appropriate information. - * - * @param color the new foreground color. - * @see #getForeground() - */ - public void setForeground(Color color) - { - /* Ignored */ - } + /** + * Returns the Cursor displayed when the pointer + * is positioned over this component. Alternatively, null + * is returned if the component doesn't support the cursor + * property. + *
    + *
    + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns the default + * system cursor. Concrete subclasses which handle the drawing + * of an onscreen menu component may override this method and provide + * the appropriate information. + * + * @return the default system cursor + * + * @see #setCursor(java.awt.Cursor) + */ + public Cursor getCursor() + { + return Cursor.getDefaultCursor(); + } - /** - * Sets the location of the component, with co-ordinates - * relative to the parent component and using the co-ordinate - * space of the screen. Thus, the point (0,0) is the upper - * left corner of the parent component. - *
    - *
    - * Please note that this method depends on a correctly implemented - * version of the getBounds() method. Subclasses - * must provide the bounding rectangle via getBounds() - * in order for this method to work. - * - * @param point the location of the component, relative to its parent. - * @see #getLocation() - */ - public void setLocation(Point point) - { - getBounds().setLocation(point); - } + /** + * Returns the Font used for text created by this component. + * + * @return the current font + * + * @see #setFont(java.awt.Font) + */ + public Font getFont() + { + return MenuComponent.this.getFont(); + } - /** - * Sets the size of the component. - *
    - *
    - * Please note that this method depends on a correctly implemented - * version of the getBounds() method. Subclasses - * must provide the bounding rectangle via getBounds() - * in order for this method to work. - * - * @param size the new size of the component. - * @see #getSize() - */ - public void setSize(Dimension size) - { - getBounds().setSize(size); - } + /** + * Retrieves information on the rendering and metrics of the supplied + * font. If font metrics are not supported by this component, null + * is returned. + *
    + *
    + * The abstract implementation of this method simply uses the toolkit + * to obtain the FontMetrics. Concrete subclasses may + * find it more efficient to invoke their peer class directly, if one + * is available. + * + * @param font the font about which to retrieve rendering and metric + * information + * + * @return the metrics of the given font, as provided by the system + * toolkit + * + * @throws NullPointerException if the supplied font was null + */ + public FontMetrics getFontMetrics(Font font) + { + return MenuComponent.this.getToolkit().getFontMetrics(font); + } - /** - * Sets the visibility state of the component. A component may - * be visible but not drawn on the screen if one of its parent - * components is not visible. To determine if the component is - * actually drawn on screen, isShowing() should be - * used. - *
    - *
    - * As this abstract component has no properties relating to its - * visibility, the implementation of this method is left to subclasses. - * - * @param visibility the new visibility of the component -- true if - * the component is visible, false if not. - * @see #isShowing() - * @see #isVisible() - */ - public void setVisible(boolean visibility) - { - /* Ignored */ - } + /** + * Returns the foreground color of the component, or null + * if this property is unsupported. + *
    + *
    + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns the + * default system text color used for rendering menus. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return the default system text color for menus + * + * @see #setForeground(java.awt.Color) + */ + public Color getForeground() + { + return SystemColor.menuText; + } -} /* class AccessibleAWTMenuComponent */ - + /** + * Returns the locale currently in use by this component. + *
    + *
    + * This abstract class has no property relating to the + * locale used by the component, so this method simply + * returns the default locale for the current instance + * of the Java Virtual Machine (JVM). Concrete subclasses + * which maintain such a property should override this method + * and provide the locale information more accurately. + * + * @return the default locale for this JVM instance + */ + public Locale getLocale() + { + return Locale.getDefault(); + } + + /** + * Returns the location of the component, with co-ordinates + * relative to the parent component and using the co-ordinate + * space of the screen. Thus, the point (0,0) is the upper + * left corner of the parent component. + *
    + *
    + * Please note that this method depends on a correctly implemented + * version of the getBounds() method. Subclasses + * must provide the bounding rectangle via getBounds() + * in order for this method to work. + * + * @return the location of the component, relative to its parent + * + * @see #setLocation(java.awt.Point) + */ + public Point getLocation() + { + // Simply return the location of the bounding rectangle. + return getBounds().getLocation(); + } + + /** + * Returns the location of the component, with co-ordinates + * relative to the screen. Thus, the point (0,0) is the upper + * left corner of the screen. null is returned if the component + * is either not on screen or if this property is unsupported. + *
    + *
    + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply returns null. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @return the location of the component, relative to the screen + */ + public Point getLocationOnScreen() + { + return null; + } + + /** + * Returns the size of the component. + *
    + *
    + * Please note that this method depends on a correctly implemented + * version of the getBounds() method. Subclasses + * must provide the bounding rectangle via getBounds() + * in order for this method to work. + * + * @return the size of the component + * + * @see #setSize(java.awt.Dimension) + */ + public Dimension getSize() + { + // Simply return the size of the bounding rectangle. + return getBounds().getSize(); + } + + /** + * Returns true if the accessible child specified by the supplied index + * is currently selected. + *
    + *
    + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the accessible child to check for selection + * + * @return false + */ + public boolean isAccessibleChildSelected(int index) + { + return false; + } + + /** + * Returns true if this component is currently enabled. + *
    + *
    + * As this abstract component has no properties related to + * its enabled or disabled state, the implementation of this + * method is left to subclasses. + * + * @return false + * + * @see #setEnabled(boolean) + */ + public boolean isEnabled() + { + return false; + } -} // class MenuComponent + /** + * Returns true if this component is included in the traversal + * of the current focus from one component to the other. + *
    + *
    + * As this abstract component has no properties related to + * its ability to accept the focus, the implementation of this + * method is left to subclasses. + * + * @return false + */ + public boolean isFocusTraversable() + { + return false; + } + + /** + * Returns true if the component is being shown on screen. + * A component is determined to be shown if it is visible, + * and each parent component is also visible. Please note + * that, even when a component is showing, it may still be + * obscured by other components in front. This method only + * determines if the component is being drawn on the screen. + *
    + *
    + * As this abstract component and its parent have no properties + * relating to visibility, the implementation of this method is + * left to subclasses. + * + * @return false + * + * @see #isVisible() + */ + public boolean isShowing() + { + return false; + } + + /** + * Returns true if the component is visible. A component may + * be visible but not drawn on the screen if one of its parent + * components is not visible. To determine if the component is + * actually drawn on screen, isShowing() should be + * used. + *
    + *
    + * As this abstract component has no properties relating to its + * visibility, the implementation of this method is left to subclasses. + * + * @return false + * + * @see #isShowing() + * @see #setVisible(boolean) + */ + public boolean isVisible() + { + return false; + } + + /** + * Removes the accessible child specified by the supplied index from + * the list of currently selected children. If the child specified + * is not selected, nothing happens. + *
    + *
    + * As the existence of children can not be determined from + * this abstract class, the implementation of this method + * is left to subclasses. + * + * @param index the index of the Accessible child + */ + public void removeAccessibleSelection(int index) + { + // Subclasses with children should implement this. + } + + /** + * Removes the specified focus listener from the list of registered + * focus listeners for this component. + * + * @param listener the listener to remove + */ + public void removeFocusListener(FocusListener listener) + { + // Remove the focus listener from the chain. + focusListener = AWTEventMulticaster.remove(focusListener, listener); + } + + /** + * Requests that this component gains focus. This depends on the + * component being focus traversable. + *
    + *
    + * As this abstract component has no properties relating to its + * focus traversability, or access to a peer with request focusing + * abilities, the implementation of this method is left to subclasses. + */ + public void requestFocus() + { + // Ignored. + } + + /** + * Selects all Accessible children of this component which + * it is possible to select. The component needs to support multiple + * selections. + *
    + *
    + * This abstract component provides a simplistic implementation of this + * method, which ignores the ability of the component to support multiple + * selections and simply uses addAccessibleSelection to + * add each Accessible child to the selection. The last + * Accessible component is thus selected for components + * which don't support multiple selections. Concrete implementations should + * override this with a more appopriate and efficient implementation, which + * properly takes into account the ability of the component to support multiple + * selections. + */ + public void selectAllAccessibleSelection() + { + // Simply call addAccessibleSelection() on all accessible children. + for (int a = 0; a < getAccessibleChildrenCount(); ++a) + { + addAccessibleSelection(a); + } + } + + /** + * Sets the background color of the component to that specified. + * Unspecified behaviour occurs when null is given as the new + * background color. + *
    + *
    + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the supplied + * color and continues to use the default system color. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @param color the new color to use for the background + * + * @see #getBackground() + */ + public void setBackground(Color color) + { + // Ignored. + } + + /** + * Sets the height and width of the component, and its position + * relative to this component's parent, to the values specified + * by the supplied rectangle. Unspecified behaviour occurs when + * null is given as the new bounds. + *
    + *
    + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the new + * rectangle and continues to return null from getBounds(). + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @param rectangle a rectangle which specifies the new bounds of + * the component + * + * @see #getBounds() + */ + public void setBounds(Rectangle rectangle) + { + // Ignored. + } + + /** + * Sets the Cursor used when the pointer is positioned over the + * component. Unspecified behaviour occurs when null is given as the new + * cursor. + *
    + *
    + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the new cursor + * and continues to return the default system cursor. Concrete + * subclasses which handle the drawing of an onscreen menu component + * may override this method and provide the appropriate information. + * + * @param cursor the new cursor to use + * + * @see #getCursor() + */ + public void setCursor(Cursor cursor) + { + // Ignored. + } + + /** + * Sets the enabled/disabled state of this component. + *
    + *
    + * As this abstract component has no properties related to + * its enabled or disabled state, the implementation of this + * method is left to subclasses. + * + * @param enabled true if the component should be enabled, + * false otherwise + * + * @see #isEnabled() + */ + public void setEnabled(boolean enabled) + { + // Ignored. + } + + /** + * Sets the Font used for text created by this component. + * Unspecified behaviour occurs when null is given as the new + * font. + * + * @param font the new font to use for text. + * @see #getFont() + */ + public void setFont(Font font) + { + // Call the method of the enclosing component. + MenuComponent.this.setFont(font); + } + + /** + * Sets the foreground color of the component to that specified. + * Unspecified behaviour occurs when null is given as the new + * background color. + *
    + *
    + * This abstract class knows nothing about how the component + * is drawn on screen, so this method simply ignores the supplied + * color and continues to return the default system text color used + * for rendering menus. + * Concrete subclasses which handle the drawing of an onscreen + * menu component should override this method and provide + * the appropriate information. + * + * @param color the new foreground color + * + * @see #getForeground() + */ + public void setForeground(Color color) + { + // Ignored. + } + + /** + * Sets the location of the component, with co-ordinates + * relative to the parent component and using the co-ordinate + * space of the screen. Thus, the point (0,0) is the upper + * left corner of the parent component. + *
    + *
    + * Please note that this method depends on a correctly implemented + * version of the getBounds() method. Subclasses + * must provide the bounding rectangle via getBounds() + * in order for this method to work. + * + * @param point the location of the component, relative to its parent + * + * @see #getLocation() + */ + public void setLocation(Point point) + { + getBounds().setLocation(point); + } + + /** + * Sets the size of the component. + *
    + *
    + * Please note that this method depends on a correctly implemented + * version of the getBounds() method. Subclasses + * must provide the bounding rectangle via getBounds() + * in order for this method to work. + * + * @param size the new size of the component + * + * @see #getSize() + */ + public void setSize(Dimension size) + { + getBounds().setSize(size); + } + + /** + * Sets the visibility state of the component. A component may + * be visible but not drawn on the screen if one of its parent + * components is not visible. To determine if the component is + * actually drawn on screen, isShowing() should be + * used. + *
    + *
    + * As this abstract component has no properties relating to its + * visibility, the implementation of this method is left to subclasses. + * + * @param visibility the new visibility of the component -- true if + * the component is visible, false if not + * + * @see #isShowing() + * @see #isVisible() + */ + public void setVisible(boolean visibility) + { + // Ignored. + } + + } + +} diff --git a/java/awt/Scrollbar.java b/java/awt/Scrollbar.java index ef173f111..ef8d6d59e 100644 --- a/java/awt/Scrollbar.java +++ b/java/awt/Scrollbar.java @@ -1,5 +1,5 @@ /* Scrollbar.java -- AWT Scrollbar widget - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -593,13 +593,33 @@ public class Scrollbar extends Component implements Accessible, Adjustable adjustment_listeners.adjustmentValueChanged(event); } + /** + * Package private method to determine whether to call + * processEvent() or not. Will handle events from peer and update + * the current value. + */ void dispatchEventImpl(AWTEvent e) { if (e.id <= AdjustmentEvent.ADJUSTMENT_LAST - && e.id >= AdjustmentEvent.ADJUSTMENT_FIRST - && (adjustment_listeners != null - || (eventMask & AWTEvent.ADJUSTMENT_EVENT_MASK) != 0)) - processEvent(e); + && e.id >= AdjustmentEvent.ADJUSTMENT_FIRST) + { + AdjustmentEvent ae = (AdjustmentEvent) e; + boolean adjusting = ae.getValueIsAdjusting(); + if (adjusting) + setValueIsAdjusting(true); + try + { + setValue(((AdjustmentEvent) e).getValue()); + if (adjustment_listeners != null + || (eventMask & AWTEvent.ADJUSTMENT_EVENT_MASK) != 0) + processEvent(e); + } + finally + { + if (adjusting) + setValueIsAdjusting(false); + } + } else super.dispatchEventImpl(e); } diff --git a/java/awt/TextField.java b/java/awt/TextField.java index 0125b25f8..ff32afa88 100644 --- a/java/awt/TextField.java +++ b/java/awt/TextField.java @@ -397,6 +397,7 @@ addNotify() return; setPeer((ComponentPeer)getToolkit().createTextField(this)); + super.addNotify(); } /*************************************************************************/ diff --git a/java/awt/Toolkit.java b/java/awt/Toolkit.java index 14282f666..ed2433be0 100644 --- a/java/awt/Toolkit.java +++ b/java/awt/Toolkit.java @@ -39,6 +39,8 @@ exception statement from your version. */ package java.awt; +import gnu.java.awt.peer.GLightweightPeer; + import java.awt.datatransfer.Clipboard; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; @@ -46,6 +48,7 @@ import java.awt.dnd.DragGestureRecognizer; import java.awt.dnd.DragSource; import java.awt.dnd.peer.DragSourceContextPeer; import java.awt.event.AWTEventListener; +import java.awt.event.AWTEventListenerProxy; import java.awt.event.KeyEvent; import java.awt.font.TextAttribute; import java.awt.im.InputMethodHighlight; @@ -77,6 +80,7 @@ import java.awt.peer.WindowPeer; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.net.URL; +import java.util.ArrayList; import java.util.Hashtable; import java.util.Map; import java.util.Properties; @@ -116,11 +120,22 @@ public abstract class Toolkit protected final PropertyChangeSupport desktopPropsSupport = new PropertyChangeSupport(this); + /** + * All registered AWTEventListener objects. This is package private, so the + * event queue can efficiently access this list. + */ + AWTEventListenerProxy[] awtEventListeners; + /** * Default constructor for subclasses. */ public Toolkit() { + awtEventListeners = new AWTEventListenerProxy[1]; + awtEventListeners[0] = + new AWTEventListenerProxy(AWTEvent.MOUSE_EVENT_MASK + | AWTEvent.MOUSE_MOTION_EVENT_MASK, + new LightweightDispatcher()); } /** @@ -352,7 +367,7 @@ public abstract class Toolkit */ protected LightweightPeer createComponent(Component target) { - return new gnu.java.awt.peer.GLightweightPeer (target); + return new GLightweightPeer(target); } /** @@ -968,33 +983,210 @@ public abstract class Toolkit return desktopPropsSupport.getPropertyChangeListeners(name); } + /** + * Adds an AWTEventListener to this toolkit. This listener is informed about + * all events that pass the eventqueue that match the specified + * evenMask. The eventMask is an ORed combination + * of event masks as defined in {@link AWTEvent}. + * + * If a security manager is installed, it is asked first if an + * AWTPermission("listenToAllAWTEvents") is allowed. + * This may result in a SecurityException beeing thrown. + * + * It is not recommended to use this kind of notification for normal + * applications. It is intended solely for the purpose of debugging and to + * support special facilities. + * + * @param listener the listener to add + * @param eventMask the event mask of event types which the listener is + * interested in + * + * @since 1.2 + * + * @throws SecurityException if there is a SecurityManager that + * doesn't grant + * AWTPermission("listenToAllAWTEvents") + * + * @see #getAWTEventListeners() + * @see #getAWTEventListeners(long) + * @see #removeAWTEventListener(AWTEventListener) + */ public void addAWTEventListener(AWTEventListener listener, long eventMask) { - // SecurityManager s = System.getSecurityManager(); - // if (s != null) - // s.checkPermission(AWTPermission("listenToAllAWTEvents")); - // FIXME + // First we must check the security permissions. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new AWTPermission("listenToAllAWTEvents")); + + // Go through the list and check if the requested listener is already + // registered. + boolean found = false; + for (int i = 0; i < awtEventListeners.length; ++i) + { + AWTEventListenerProxy proxy = awtEventListeners[i]; + if (proxy.getListener() == listener) + { + found = true; + // Modify the proxies event mask to include the new event mask. + AWTEventListenerProxy newProxy = + new AWTEventListenerProxy(proxy.getEventMask() | eventMask, + listener); + awtEventListeners[i] = newProxy; + break; + } + } + + // If that listener was not found, then add it. + if (! found) + { + AWTEventListenerProxy proxy = + new AWTEventListenerProxy(eventMask, listener); + AWTEventListenerProxy[] newArray = + new AWTEventListenerProxy[awtEventListeners.length + 1]; + System.arraycopy(awtEventListeners, 0, newArray, 0, + awtEventListeners.length); + newArray[newArray.length - 1] = proxy; + awtEventListeners = newArray; + } } + /** + * Removes an AWT event listener from this toolkit. This listener is no + * longer informed of any event types it was registered in. + * + * If a security manager is installed, it is asked first if an + * AWTPermission("listenToAllAWTEvents") is allowed. + * This may result in a SecurityException beeing thrown. + * + * It is not recommended to use this kind of notification for normal + * applications. It is intended solely for the purpose of debugging and to + * support special facilities. + * + * @param listener the listener to remove + * + * @throws SecurityException if there is a SecurityManager that + * doesn't grant + * AWTPermission("listenToAllAWTEvents") + * + * @since 1.2 + * + * @see #addAWTEventListener(AWTEventListener, long) + * @see #getAWTEventListeners() + * @see #getAWTEventListeners(long) + */ public void removeAWTEventListener(AWTEventListener listener) { - // FIXME + // First we must check the security permissions. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new AWTPermission("listenToAllAWTEvents")); + + + // Find the index of the listener. + int index = -1; + for (int i = 0; i < awtEventListeners.length; ++i) + { + AWTEventListenerProxy proxy = awtEventListeners[i]; + if (proxy.getListener() == listener) + { + index = i; + break; + } + } + + // Copy over the arrays and leave out the removed element. + if (index != -1) + { + AWTEventListenerProxy[] newArray = + new AWTEventListenerProxy[awtEventListeners.length - 1]; + if (index > 0) + System.arraycopy(awtEventListeners, 0, newArray, 0, index); + if (index < awtEventListeners.length - 1) + System.arraycopy(awtEventListeners, index + 1, newArray, index, + awtEventListeners.length - index - 1); + awtEventListeners = newArray; + } } /** + * Returns all registered AWT event listeners. This method returns a copy of + * the listener array, so that application cannot trash the listener list. + * + * If a security manager is installed, it is asked first if an + * AWTPermission("listenToAllAWTEvents") is allowed. + * This may result in a SecurityException beeing thrown. + * + * It is not recommended to use this kind of notification for normal + * applications. It is intended solely for the purpose of debugging and to + * support special facilities. + * + * @return all registered AWT event listeners + * + * @throws SecurityException if there is a SecurityManager that + * doesn't grant + * AWTPermission("listenToAllAWTEvents") + * * @since 1.4 + * + * @see #addAWTEventListener(AWTEventListener, long) + * @see #removeAWTEventListener(AWTEventListener) + * @see #getAWTEventListeners(long) */ public AWTEventListener[] getAWTEventListeners() { - return null; + // First we must check the security permissions. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new AWTPermission("listenToAllAWTEvents")); + + // Create a copy of the array. + AWTEventListener[] copy = new AWTEventListener[awtEventListeners.length]; + System.arraycopy(awtEventListeners, 0, copy, 0, awtEventListeners.length); + return copy; } /** + * Returns all registered AWT event listeners that listen for events with + * the specified eventMask. This method returns a copy of + * the listener array, so that application cannot trash the listener list. + * + * If a security manager is installed, it is asked first if an + * AWTPermission("listenToAllAWTEvents") is allowed. + * This may result in a SecurityException beeing thrown. + * + * It is not recommended to use this kind of notification for normal + * applications. It is intended solely for the purpose of debugging and to + * support special facilities. + * + * @param mask the event mask + * + * @throws SecurityException if there is a SecurityManager that + * doesn't grant + * AWTPermission("listenToAllAWTEvents") + * + * * @since 1.4 + * + * @see #addAWTEventListener(AWTEventListener, long) + * @see #removeAWTEventListener(AWTEventListener) + * @see #getAWTEventListeners() */ public AWTEventListener[] getAWTEventListeners(long mask) { - return null; + // First we must check the security permissions. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new AWTPermission("listenToAllAWTEvents")); + + // Create a copy of the array with only the requested listeners in it. + ArrayList l = new ArrayList(awtEventListeners.length); + for (int i = 0; i < awtEventListeners.length; ++i) + { + if ((awtEventListeners[i].getEventMask() & mask) != 0) + l.add(awtEventListeners[i]); + } + + return (AWTEventListener[] ) l.toArray(new AWTEventListener[l.size()]); } /** diff --git a/java/awt/Window.java b/java/awt/Window.java index 61b380edf..66d9324af 100644 --- a/java/awt/Window.java +++ b/java/awt/Window.java @@ -282,51 +282,54 @@ public class Window extends Container implements Accessible @Deprecated public void show() { - if (parent != null && !parent.isDisplayable()) - parent.addNotify(); - if (peer == null) - addNotify(); - - // Show visible owned windows. synchronized (getTreeLock()) - { - Iterator e = ownedWindows.iterator(); - while(e.hasNext()) - { - Window w = (Window)(((Reference) e.next()).get()); - if (w != null) - { - if (w.isVisible()) - w.getPeer().setVisible(true); - } - else - // Remove null weak reference from ownedWindows. - // Unfortunately this can't be done in the Window's - // finalize method because there is no way to guarantee - // synchronous access to ownedWindows there. - e.remove(); - } - validate(); - super.show(); - toFront(); - - KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); - manager.setGlobalFocusedWindow (this); - - if (!shown) { - FocusTraversalPolicy policy = getFocusTraversalPolicy (); - Component initialFocusOwner = null; + if (parent != null && ! parent.isDisplayable()) + parent.addNotify(); + if (peer == null) + addNotify(); + + validate(); + if (visible) + toFront(); + else + { + super.show(); + // Show visible owned windows. + Iterator e = ownedWindows.iterator(); + while (e.hasNext()) + { + Window w = (Window) (((Reference) e.next()).get()); + if (w != null) + { + if (w.isVisible()) + w.getPeer().setVisible(true); + } + else + // Remove null weak reference from ownedWindows. + // Unfortunately this can't be done in the Window's + // finalize method because there is no way to guarantee + // synchronous access to ownedWindows there. + e.remove(); + } + } + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + manager.setGlobalFocusedWindow(this); - if (policy != null) - initialFocusOwner = policy.getInitialComponent (this); + if (! shown) + { + FocusTraversalPolicy policy = getFocusTraversalPolicy(); + Component initialFocusOwner = null; - if (initialFocusOwner != null) - initialFocusOwner.requestFocusInWindow (); + if (policy != null) + initialFocusOwner = policy.getInitialComponent(this); - shown = true; + if (initialFocusOwner != null) + initialFocusOwner.requestFocusInWindow(); + + shown = true; + } } - } } /** diff --git a/java/awt/datatransfer/DataFlavor.java b/java/awt/datatransfer/DataFlavor.java index 606cfe035..f7c103c72 100644 --- a/java/awt/datatransfer/DataFlavor.java +++ b/java/awt/datatransfer/DataFlavor.java @@ -161,38 +161,42 @@ private String humanPresentableName; ClassLoader classLoader) throws ClassNotFoundException { + // Bootstrap try { - return(Class.forName(className)); + return Class.forName(className); } - catch(Exception e) { ; } - // Commented out for Java 1.1 - /* - try + catch(ClassNotFoundException cnfe) { - return(className.getClass().getClassLoader().findClass(className)); + // Ignored. } - catch(Exception e) { ; } + // System try { - return(ClassLoader.getSystemClassLoader().findClass(className)); + ClassLoader loader = ClassLoader.getSystemClassLoader(); + return Class.forName(className, true, loader); } - catch(Exception e) { ; } - */ - - // FIXME: What is the context class loader? - /* + catch(ClassNotFoundException cnfe) + { + // Ignored. + } + + // Context try { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + return Class.forName(className, true, loader); } - catch(Exception e) { ; } - */ - + catch(ClassNotFoundException cnfe) + { + // Ignored. + } + if (classLoader != null) - return(classLoader.loadClass(className)); - else - throw new ClassNotFoundException(className); + return Class.forName(className, true, classLoader); + + throw new ClassNotFoundException(className); } private static Class getRepresentationClassFromMime(String mimeString, @@ -207,7 +211,13 @@ private String humanPresentableName; } catch(Exception e) { - throw new IllegalArgumentException("classname: " + e.getMessage()); + IllegalArgumentException iae; + iae = new IllegalArgumentException("mimeString: " + + mimeString + + " classLoader: " + + classLoader); + iae.initCause(e); + throw iae; } } else diff --git a/java/awt/dnd/DragSource.java b/java/awt/dnd/DragSource.java index 09c9fc48e..014998913 100644 --- a/java/awt/dnd/DragSource.java +++ b/java/awt/dnd/DragSource.java @@ -90,7 +90,7 @@ public class DragSource implements Serializable */ public static DragSource getDefaultDragSource() { - return null; + return new DragSource(); } public static boolean isDragImageSupported() @@ -172,13 +172,34 @@ public class DragSource implements Serializable return flavorMap; } + /** + * Dummy DragGestureRecognizer when Toolkit doesn't support drag and drop. + */ + static class NoDragGestureRecognizer extends DragGestureRecognizer + { + NoDragGestureRecognizer(DragSource ds, Component c, int actions, + DragGestureListener dgl) + { + super(ds, c, actions, dgl); + } + + protected void registerListeners() { } + protected void unregisterListeners() { } + } + public T createDragGestureRecognizer(Class recognizer, Component c, int actions, DragGestureListener dgl) { - return Toolkit.getDefaultToolkit () + DragGestureRecognizer dgr; + dgr = Toolkit.getDefaultToolkit () .createDragGestureRecognizer (recognizer, this, c, actions, dgl); + + if (dgr == null) + dgr = new NoDragGestureRecognizer(this, c, actions, dgl); + + return (T) dgr; } public DragGestureRecognizer diff --git a/java/awt/event/AWTEventListenerProxy.java b/java/awt/event/AWTEventListenerProxy.java index 3d9958b1a..55a4bfe37 100644 --- a/java/awt/event/AWTEventListenerProxy.java +++ b/java/awt/event/AWTEventListenerProxy.java @@ -72,75 +72,15 @@ public class AWTEventListenerProxy extends EventListenerProxy } /** - * Forwards events on to the delegate if they meet the event mask. + * Forwards events on to the delegate. + * + * @param event the to forward to the delagate listener * - * @param event the property change event to filter * @throws NullPointerException if the delegate this was created with is null */ public void eventDispatched(AWTEvent event) { - int id = event == null ? 0 : event.getID(); - if (((mask & AWTEvent.ACTION_EVENT_MASK) != 0 - && event instanceof ActionEvent) - || ((mask & AWTEvent.ADJUSTMENT_EVENT_MASK) != 0 - && event instanceof AdjustmentEvent) - || ((mask & AWTEvent.COMPONENT_EVENT_MASK) != 0 - && event instanceof ComponentEvent - && (id >= ComponentEvent.COMPONENT_FIRST - && id <= ComponentEvent.COMPONENT_LAST)) - || ((mask & AWTEvent.CONTAINER_EVENT_MASK) != 0 - && event instanceof ContainerEvent) - || ((mask & AWTEvent.FOCUS_EVENT_MASK) != 0 - && event instanceof FocusEvent) - || ((mask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 - && event instanceof HierarchyEvent - && (id == HierarchyEvent.ANCESTOR_MOVED - || id == HierarchyEvent.ANCESTOR_RESIZED)) - || ((mask & AWTEvent.HIERARCHY_EVENT_MASK) != 0 - && event instanceof HierarchyEvent - && id == HierarchyEvent.HIERARCHY_CHANGED) - || ((mask & AWTEvent.INPUT_METHOD_EVENT_MASK) != 0 - && event instanceof InputMethodEvent) - || ((mask & AWTEvent.INVOCATION_EVENT_MASK) != 0 - && event instanceof InvocationEvent) - || ((mask & AWTEvent.ITEM_EVENT_MASK) != 0 - && event instanceof ItemEvent) - || ((mask & AWTEvent.KEY_EVENT_MASK) != 0 - && event instanceof KeyEvent) - || ((mask & AWTEvent.MOUSE_EVENT_MASK) != 0 - && event instanceof MouseEvent - && (id == MouseEvent.MOUSE_PRESSED - || id == MouseEvent.MOUSE_RELEASED - || id == MouseEvent.MOUSE_CLICKED - || id == MouseEvent.MOUSE_ENTERED - || id == MouseEvent.MOUSE_EXITED)) - || ((mask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0 - && event instanceof MouseEvent - && (id == MouseEvent.MOUSE_MOVED - || id == MouseEvent.MOUSE_DRAGGED)) - || ((mask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 - && event instanceof MouseWheelEvent) - || ((mask & AWTEvent.PAINT_EVENT_MASK) != 0 - && event instanceof PaintEvent) - || ((mask & AWTEvent.TEXT_EVENT_MASK) != 0 - && event instanceof TextEvent) - || ((mask & AWTEvent.WINDOW_EVENT_MASK) != 0 - && event instanceof WindowEvent - && (id == WindowEvent.WINDOW_OPENED - || id == WindowEvent.WINDOW_CLOSING - || id == WindowEvent.WINDOW_CLOSED - || id == WindowEvent.WINDOW_ICONIFIED - || id == WindowEvent.WINDOW_DEICONIFIED - || id == WindowEvent.WINDOW_ACTIVATED - || id == WindowEvent.WINDOW_DEACTIVATED)) - || ((mask & AWTEvent.WINDOW_FOCUS_EVENT_MASK) != 0 - && event instanceof WindowEvent - && (id == WindowEvent.WINDOW_GAINED_FOCUS - || id == WindowEvent.WINDOW_LOST_FOCUS)) - || ((mask & AWTEvent.WINDOW_STATE_EVENT_MASK) != 0 - && event instanceof WindowEvent - && id == WindowEvent.WINDOW_STATE_CHANGED)) - ((AWTEventListener) getListener()).eventDispatched(event); + ((AWTEventListener) getListener()).eventDispatched(event); } /** diff --git a/java/awt/peer/ComponentPeer.java b/java/awt/peer/ComponentPeer.java index 1ba169232..97b96f49c 100644 --- a/java/awt/peer/ComponentPeer.java +++ b/java/awt/peer/ComponentPeer.java @@ -59,76 +59,344 @@ import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; import java.awt.image.VolatileImage; +/** + * Defines the methods that a component peer is required to implement. + */ public interface ComponentPeer { + /** + * Returns the construction status of the specified image. This is called + * by {@link Component#checkImage(Image, int, int, ImageObserver)}. + * + * @param img the image + * @param width the width of the image + * @param height the height of the image + * @param ob the image observer to be notified of updates of the status + * + * @return a bitwise ORed set of ImageObserver flags + */ int checkImage(Image img, int width, int height, - ImageObserver ob); + ImageObserver ob); + + /** + * Creates an image by starting the specified image producer. This is called + * by {@link Component#createImage(ImageProducer)}. + * + * @param prod the image producer to be used to create the image + * + * @return the created image + */ Image createImage(ImageProducer prod); + + /** + * Creates an empty image with the specified width and + * height. + * + * @param width the width of the image to be created + * @param height the height of the image to be created + * + * @return the created image + */ Image createImage(int width, int height); + + /** + * Disables the component. This is called by {@link Component#disable()}. + */ void disable(); + + /** + * Disposes the component peer. This should release all resources held by the + * peer. This is called when the component is no longer in use. + */ void dispose(); + + /** + * Enables the component. This is called by {@link Component#enable()}. + */ void enable(); + + /** + * Returns the color model of the component. This is currently not used. + * + * @return the color model of the component + */ ColorModel getColorModel(); + + /** + * Returns the font metrics for the specified font. This is called by + * {@link Component#getFontMetrics(Font)}. + * + * @param f the font for which to query the font metrics + * + * @return the font metrics for the specified font + */ FontMetrics getFontMetrics(Font f); + + /** + * Returns a {@link Graphics} object suitable for drawing on this component. + * This is called by {@link Component#getGraphics()}. + * + * @return a graphics object suitable for drawing on this component + */ Graphics getGraphics(); + + /** + * Returns the location of this component in screen coordinates. This is + * called by {@link Component#getLocationOnScreen()}. + * + * @return the location of this component in screen coordinates + */ Point getLocationOnScreen(); + + /** + * Returns the minimum size for the component. This is called by + * {@link Component#getMinimumSize()}. + * + * @return the minimum size for the component + */ Dimension getMinimumSize(); + + /** + * Returns the preferred size for the component. This is called by + * {@link Component#getPreferredSize()}. + * + * @return the preferred size for the component + */ Dimension getPreferredSize(); + + /** + * Returns the toolkit that created this peer. + * + * @return the toolkit that created this peer + */ Toolkit getToolkit(); + + /** + * Handles the given event. This is called from + * {@link Component#dispatchEvent(AWTEvent)} to give the peer a chance to + * react to events for the component. + * + * @param e the event + */ void handleEvent(AWTEvent e); + + /** + * Makes the component invisible. This is called from + * {@link Component#hide()}. + */ void hide(); /** - * Part of the earlier 1.1 API, replaced by isFocusable(). + * Returns true if the component can receive keyboard input + * focus. This is called from {@link Component#isFocusTraversable()}. + * + * @specnote Part of the earlier 1.1 API, replaced by isFocusable(). */ boolean isFocusTraversable(); + + /** + * Returns true if the component can receive keyboard input + * focus. This is called from {@link Component#isFocusable()}. + */ boolean isFocusable(); + + /** + * Returns the minimum size for the component. This is called by + * {@link Component#minimumSize()}. + * + * @return the minimum size for the component + */ Dimension minimumSize(); + + /** + * Returns the preferred size for the component. This is called by + * {@link Component#getPreferredSize()}. + * + * @return the preferred size for the component + */ Dimension preferredSize(); + void paint(Graphics graphics); + + /** + * Prepares an image for rendering on this component. This is called by + * {@link Component#prepareImage(Image, int, int, ImageObserver)}. + * + * @param img the image to prepare + * @param width the desired width of the rendered image + * @param height the desired height of the rendered image + * @param ob the image observer to be notified of updates in the preparation + * process + * + * @return true if the image has been fully prepared, + * false otherwise (in which case the image observer + * receives updates) + */ boolean prepareImage(Image img, int width, int height, ImageObserver ob); + void print(Graphics graphics); + + /** + * Repaints the specified rectangle of this component. This is called from + * {@link Component#repaint(long, int, int, int, int)}. + * + * @param tm number of milliseconds to wait with repainting + * @param x the X coordinate of the upper left corner of the damaged rectangle + * @param y the Y coordinate of the upper left corner of the damaged rectangle + * @param width the width of the damaged rectangle + * @param height the height of the damaged rectangle + */ void repaint(long tm, int x, int y, int width, int height); /** - * Part of the earlier 1.1 API, apparently replaced by argument - * form of the same method. + * Requests that this component receives the focus. This is called from + * {@link Component#requestFocus()}. + * + * @specnote Part of the earlier 1.1 API, apparently replaced by argument + * form of the same method. */ void requestFocus(); - boolean requestFocus (Component source, boolean bool1, boolean bool2, long x); + /** + * Requests that this component receives the focus. This is called from + * {@link Component#requestFocus()}. + * + * @param source TODO + * @param bool1 TODO + * @param bool2 TODO + * @param x TODO + */ + boolean requestFocus(Component source, boolean bool1, boolean bool2, long x); + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#reshape(int, int, int, int)}. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ void reshape(int x, int y, int width, int height); + + /** + * Sets the background color of the component. This is called by + * {@link Component#setBackground(Color)}. + * + * @param color the background color to set + */ void setBackground(Color color); + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#setBounds(int, int, int, int)}. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ void setBounds(int x, int y, int width, int height); /** - * Part of the earlier 1.1 API, apparently no longer needed. + * Sets the cursor of the component. This is called by + * {@link Component#setCursor(Cursor)}. + * + * @specnote Part of the earlier 1.1 API, apparently no longer needed. */ void setCursor(Cursor cursor); + /** + * Sets the enabled/disabled state of this component. This is called by + * {@link Component#setEnabled(boolean)}. + * + * @param enabled true to enable the component, + * false to disable it + */ void setEnabled(boolean enabled); + + /** + * Sets the font of the component. This is called by + * {@link Component#setFont(Font)}. + * + * @param font the font to set + */ void setFont(Font font); + + /** + * Sets the foreground color of the component. This is called by + * {@link Component#setForeground(Color)}. + * + * @param color the foreground color to set + */ void setForeground(Color color); + + /** + * Sets the visibility state of the component. This is called by + * {@link Component#setVisible(boolean)}. + * + * @param visible true to make the component visible, + * false to make it invisible + */ void setVisible(boolean visible); + + /** + * Makes the component visible. This is called by {@link Component#show()}. + */ void show(); /** * Get the graphics configuration of the component. The color model * of the component can be derived from the configuration. + * + * @return the graphics configuration of the component */ GraphicsConfiguration getGraphicsConfiguration(); /** * Part of an older API, no longer needed. */ - void setEventMask (long mask); + void setEventMask(long mask); - // Methods below are introduced since 1.1 + /** + * Returns true if this component has been obscured, + * false otherwise. This will only work if + * {@link #canDetermineObscurity()} also returns true. + * + * @return true if this component has been obscured, + * false otherwise. + */ boolean isObscured(); + + /** + * Returns true if this component peer can determine if the + * component has been obscured, false otherwise. + * + * @return true if this component peer can determine if the + * component has been obscured, false otherwise + */ boolean canDetermineObscurity(); + + /** + * Coalesces the specified paint event. + * + * @param e the paint event + */ void coalescePaintEvent(PaintEvent e); + + /** + * Updates the cursor. + */ void updateCursorImmediately(); + + /** + * Returns true, if this component can handle wheel scrolling, + * false otherwise. + * + * @return true, if this component can handle wheel scrolling, + * false otherwise + */ boolean handlesWheelScrolling(); /** diff --git a/java/awt/print/NoPrinterJob.java b/java/awt/print/NoPrinterJob.java new file mode 100644 index 000000000..e9659a147 --- /dev/null +++ b/java/awt/print/NoPrinterJob.java @@ -0,0 +1,124 @@ +/* NoPrinterJob.java -- Fake PrinterJob that just signals no print service. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt.print; + +/** + * Fake PrinterJob that just signals no print service. This is only + * here so applications can call + * PrintJob.getPrinterJob().getPrinterJob() and check + * that it returns null which indicates no actual + * printing support is available. + */ +class NoPrinterJob extends PrinterJob +{ + public int getCopies() + { + return 0; + } + + public void setCopies(int copies) + { + // Do nothing. + } + + public String getJobName() + { + return "NoPrinterJob"; + } + + public void setJobName(String job_name) + { + // Do nothing. + } + + public String getUserName() + { + return "NoUser"; + } + + public void cancel() + { + // Do nothing. + } + + public boolean isCancelled() + { + return true; + } + + public PageFormat defaultPage(PageFormat page_format) + { + return page_format; + } + + public PageFormat pageDialog(PageFormat page_format) + { + return page_format; + } + + public void print() throws PrinterException + { + throw new PrinterException("No printer"); + } + + public boolean printDialog() + { + return false; + } + + public void setPageable(Pageable pageable) + { + // Do nothing. + } + + public void setPrintable(Printable printable) + { + // Do nothing. + } + + public void setPrintable(Printable printable, PageFormat page_format) + { + // Do nothing. + } + + public PageFormat validatePage(PageFormat page_format) + { + return page_format; + } +} diff --git a/java/awt/print/PageFormat.java b/java/awt/print/PageFormat.java index 6399552de..0a8aa3ed0 100644 --- a/java/awt/print/PageFormat.java +++ b/java/awt/print/PageFormat.java @@ -1,5 +1,5 @@ /* PageFormat.java -- Information about the page format - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,254 +39,195 @@ exception statement from your version. */ package java.awt.print; /** - * This class contains information about the desired page format to - * use for printing a particular set of pages. - * - * @author Aaron M. Renn (arenn@urbanophile.com) - */ -public class PageFormat implements Cloneable -{ - -/* - * Static Variables - */ - -/** - * A constant for a landscaped page orientation. Used by - * getOrientation and setOrientation. - */ -public static final int LANDSCAPE = 0; - -/** - * A constant for a portrait page orientation. Used by - * getOrientation and setOrientation. - */ -public static final int PORTRAIT = 1; - -/** - * A constant for a reversed landscaped page orientation. This is - * the orientation used by Macintosh's for landscape. The origin is - * in the upper right hand corner instead of the upper left. The - * X and Y axes are reversed. Used by getOrientation and - * setOrientation. - */ -public static final int REVERSE_LANDSCAPE = 2; - -/*************************************************************************/ - -/* - * Instance Variables + * This class contains information about the desired page format to use for + * printing a particular set of pages. + * + * @author Aaron M. Renn (arenn@urbanophile.com) */ - -// The page orientation -private int orientation; - -// The paper type -private Paper paper; - -/*************************************************************************/ - -/* - * Constructors - */ - -/** - * This method creates a default page layout, which will be in portrait - * format. - */ -public -PageFormat() -{ - this.paper = new Paper(); - this.orientation = PORTRAIT; -} - -/*************************************************************************/ - -/* - * Instance Methods - */ - -/** - * This method returns the width of the page, in 1/72nd's of an inch. The - * "width" measured depends on orientation. - * - * @return The width of the page. - */ -public double -getWidth() -{ - return(paper.getWidth()); -} - -/*************************************************************************/ - -/** - * This method returns the height of the page, in 1/72nd's of an inch. - * The "height" measured depends on the orientation. - * - * @return The height of the page. - */ -public double -getHeight() -{ - return(paper.getHeight()); -} - -/*************************************************************************/ - -/** - * This method returns the X coordinate value of the upper leftmost - * drawable area of the paper. - * - * @return The upper leftmost imageable X coordinate. - */ -public double -getImageableX() -{ - return(paper.getImageableX()); -} - -/*************************************************************************/ - -/** - * This method returns the Y coordinate value of the upper leftmost - * drawable area of the paper. - * - * @return The upper leftmost imageable Y coordinate. - */ -public double -getImageableY() -{ - return(paper.getImageableY()); -} - -/*************************************************************************/ - -/** - * This method returns the imageable width of the paper, in 1/72nd's of - * an inch. - * - * @return The imageable width of the paper. - */ -public double -getImageableWidth() +public class PageFormat + implements Cloneable { - return(paper.getImageableWidth()); -} - -/*************************************************************************/ + /** + * A constant for a landscaped page orientation. Used by + * getOrientation and setOrientation. + */ + public static final int LANDSCAPE = 0; + + /** + * A constant for a portrait page orientation. Used by + * getOrientation and setOrientation. + */ + public static final int PORTRAIT = 1; + + /** + * A constant for a reversed landscaped page orientation. This is the + * orientation used by Macintosh's for landscape. The origin is in the + * upper right hand corner instead of the upper left. The X and Y axes + * are reversed. Used by getOrientation and + * setOrientation. + */ + public static final int REVERSE_LANDSCAPE = 2; + + // The page orientation + private int orientation; + + // The paper type + private Paper paper; + + /** + * This method creates a default page layout, which will be in portrait + * format. + */ + public PageFormat() + { + this.paper = new Paper(); + this.orientation = PORTRAIT; + } + + /** + * This method returns the width of the page, in 1/72nd's of an inch. The + * "width" measured depends on orientation. + * + * @return The width of the page. + */ + public double getWidth() + { + return paper.getWidth(); + } + + /** + * This method returns the height of the page, in 1/72nd's of an inch. The + * "height" measured depends on the orientation. + * + * @return The height of the page. + */ + public double getHeight() + { + return paper.getHeight(); + } + + /** + * This method returns the X coordinate value of the upper leftmost drawable + * area of the paper. + * + * @return The upper leftmost imageable X coordinate. + */ + public double getImageableX() + { + return paper.getImageableX(); + } + + /** + * This method returns the Y coordinate value of the upper leftmost drawable + * area of the paper. + * + * @return The upper leftmost imageable Y coordinate. + */ + public double getImageableY() + { + return paper.getImageableY(); + } + + /** + * This method returns the imageable width of the paper, in 1/72nd's of an + * inch. + * + * @return The imageable width of the paper. + */ + public double getImageableWidth() + { + return paper.getImageableWidth(); + } + + /** + * This method returns the imageable height of the paper, in 1/72nd's of an + * inch. + * + * @return The imageable height of the paper. + */ + public double getImageableHeight() + { + return paper.getImageableHeight(); + } + + /** + * Returns a copy of the paper object being used for this page + * format. + * + * @return A copy of the Paper object for this format. + */ + public Paper getPaper() + { + return (Paper) paper.clone(); + } + + /** + * Sets the Paper object to be used by this page format. + * + * @param paper The new Paper object for this page format. + */ + public void setPaper(Paper paper) + { + this.paper = paper; + } + + /** + * This method returns the current page orientation. The value returned will + * be one of the page orientation constants from this class. + * + * @return The current page orientation. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method sets the page orientation for this format to the specified + * value. It must be one of the page orientation constants from this class + * or an exception will be thrown. + * + * @param orientation The new page orientation. + * @exception IllegalArgumentException If the specified page orientation + * value is not one of the constants from this class. + */ + public void setOrientation(int orientation) throws IllegalArgumentException + { + if ((orientation != PORTRAIT) && (orientation != LANDSCAPE) + && (orientation != REVERSE_LANDSCAPE)) + throw new IllegalArgumentException("Bad page orientation value: " + + orientation); + + this.orientation = orientation; + } + + /** + * This method returns a matrix used for transforming user space coordinates + * to page coordinates. The value returned will be six doubles as described + * in java.awt.geom.AffineTransform. + * + * @return The transformation matrix for this page format. + */ + public double[] getMatrix() + { + throw new RuntimeException("Not implemented since I don't know what to do"); + } + + /** + * This method returns a copy of this object. + * + * @return A copy of this object. + */ + public Object clone() + { + try + { + return (super.clone()); + } + catch (CloneNotSupportedException e) + { + return (null); + } + } -/** - * This method returns the imageable height of the paper, in 1/72nd's of - * an inch. - * - * @return The imageable height of the paper. - */ -public double getImageableHeight() -{ - return(paper.getImageableHeight()); } - -/*************************************************************************/ - -/** - * Returns a copy of the paper object being used for this - * page format. - * - * @return A copy of the Paper object for this format. - */ -public Paper -getPaper() -{ - return((Paper)paper.clone()); -} - -/*************************************************************************/ - -/** - * Sets the Paper object to be used by this page format. - * - * @param paper The new Paper object for this page format. - */ -public void -setPaper(Paper paper) -{ - this.paper = paper; -} - -/*************************************************************************/ - -/** - * This method returns the current page orientation. The value returned - * will be one of the page orientation constants from this class. - * - * @return The current page orientation. - */ -public int -getOrientation() -{ - return(orientation); -} - -/*************************************************************************/ - -/** - * This method sets the page orientation for this format to the - * specified value. It must be one of the page orientation constants - * from this class or an exception will be thrown. - * - * @param orientation The new page orientation. - * - * @exception IllegalArgumentException If the specified page orientation - * value is not one of the constants from this class. - */ -public void -setOrientation(int orientation) throws IllegalArgumentException -{ - if ((orientation != PORTRAIT) && - (orientation != LANDSCAPE) && - (orientation != REVERSE_LANDSCAPE)) - throw new IllegalArgumentException("Bad page orientation value: " + - orientation); - - this.orientation = orientation; -} - -/*************************************************************************/ - -/** - * This method returns a matrix used for transforming user space - * coordinates to page coordinates. The value returned will be six - * doubles as described in java.awt.geom.AffineTransform. - * - * @return The transformation matrix for this page format. - */ -public double[] -getMatrix() -{ - throw new RuntimeException("Not implemented since I don't know what to do"); -} - -/*************************************************************************/ - -/** - * This method returns a copy of this object. - * - * @return A copy of this object. - */ -public Object -clone() -{ - try - { - return(super.clone()); - } - catch(CloneNotSupportedException e) - { - return(null); - } -} - -} // class PageFormat - diff --git a/java/awt/print/Pageable.java b/java/awt/print/Pageable.java index 12fa542a8..d61195a92 100644 --- a/java/awt/print/Pageable.java +++ b/java/awt/print/Pageable.java @@ -1,5 +1,5 @@ /* Pageable.java -- Pages to be printed - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,75 +39,52 @@ exception statement from your version. */ package java.awt.print; /** - * This interface represents pages that are to be printed. - * - * @author Aaron M. Renn (arenn@urbanophile.com) - */ + * This interface represents pages that are to be printed. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ public interface Pageable { - -/* - * Static Variables - */ - -/** - * This constant is returned when getNumberOfPages() - * cannot determine the number of pages available for printing. - */ -int UNKNOWN_NUMBER_OF_PAGES = -1; - -/*************************************************************************/ - -/* - * Instance Methods - */ - -/** - * This method returns the number of pages this object contains, or - * UNKNOWN_NUMBER_OF_PAGES if it cannot determine the number - * of pages to be printed. - * - * @return The number of pages to be printed, or - * UNKNOWN_NUMBER_OF_PAGES if this is unknown. - */ -int -getNumberOfPages(); - -/*************************************************************************/ - -/** - * This method returns the PageFormat instance for the - * specified page. Page numbers start at zero. An exception is thrown if - * the requested page does not exist. - * - * @param pageIndex The index of the page to return the - * PageFormat for. - * - * @return The PageFormat for the requested page. - * - * @exception IndexOutOfBoundsException If the requested page number does - * not exist. - */ -PageFormat -getPageFormat(int pageIndex) throws IndexOutOfBoundsException; - -/*************************************************************************/ - -/** - * This method returns the Printable instance for the - * specified page. Page numbers start at zero. An exception is thrown if - * the requested page does not exist. - * - * @param pageIndex The index of the page to return the - * Printable for. - * - * @return The Printable for the requested page. - * - * @exception IndexOutOfBoundsException If the requested page number does - * not exist. - */ -Printable -getPrintable(int pageIndex) throws IndexOutOfBoundsException; - -} // interface Pageable - + /** + * This constant is returned when getNumberOfPages() cannot + * determine the number of pages available for printing. + */ + int UNKNOWN_NUMBER_OF_PAGES = - 1; + + /** + * This method returns the number of pages this object contains, or + * UNKNOWN_NUMBER_OF_PAGES if it cannot determine the number + * of pages to be printed. + * + * @return The number of pages to be printed, or + * UNKNOWN_NUMBER_OF_PAGES if this is unknown. + */ + int getNumberOfPages(); + + /** + * This method returns the PageFormat instance for the + * specified page. Page numbers start at zero. An exception is thrown if the + * requested page does not exist. + * + * @param pageIndex The index of the page to return the + * PageFormat for. + * @return The PageFormat for the requested page. + * @exception IndexOutOfBoundsException If the requested page number does + * not exist. + */ + PageFormat getPageFormat(int pageIndex) throws IndexOutOfBoundsException; + + /** + * This method returns the Printable instance for the specified + * page. Page numbers start at zero. An exception is thrown if the requested + * page does not exist. + * + * @param pageIndex The index of the page to return the + * Printable for. + * @return The Printable for the requested page. + * @exception IndexOutOfBoundsException If the requested page number does + * not exist. + */ + Printable getPrintable(int pageIndex) throws IndexOutOfBoundsException; + +} diff --git a/java/awt/print/Paper.java b/java/awt/print/Paper.java index 4579da3ea..fb7ba9115 100644 --- a/java/awt/print/Paper.java +++ b/java/awt/print/Paper.java @@ -1,5 +1,5 @@ /* Paper.java -- Information about a paper type. - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,198 +39,159 @@ exception statement from your version. */ package java.awt.print; /** - * This class describes a particular type of paper. - * - * @author Aaron M. Renn (arenn@urbanophile.com) - */ -public class Paper implements Cloneable -{ - -/* - * Instance Variables + * This class describes a particular type of paper. + * + * @author Aaron M. Renn (arenn@urbanophile.com) */ - -// Height of the paper -private double height; - -// Width of the paper -private double width; - -// Upper left imageable X coordinate -private double imageableX; - -// Upper left imageable Y coordinate -private double imageableY; - -// Imageable width of the page -private double imageableWidth; - -// Imageable height of the page -private double imageableHeight; - -/*************************************************************************/ - -/* - * Constructor - */ - -/** - * This method creates a letter sized paper with one inch margins - */ -public -Paper() -{ - width = 8.5 * 72; - height = 11 * 72; - imageableX = 72; - imageableY = 72; - imageableWidth = width - (2 * 72); - imageableHeight = height - (2 * 72); -} - -/*************************************************************************/ - -/** - * This method returns the height of the paper in 1/72nds of an inch. - * - * @return The height of the paper in 1/72nds of an inch. - */ -public double -getHeight() +public class Paper + implements Cloneable { - return(height); -} + // Height of the paper + private double height; + + // Width of the paper + private double width; + + // Upper left imageable X coordinate + private double imageableX; + + // Upper left imageable Y coordinate + private double imageableY; + + // Imageable width of the page + private double imageableWidth; + + // Imageable height of the page + private double imageableHeight; + + /** + * This method creates a letter sized paper with one inch margins + */ + public Paper() + { + width = 8.5 * 72; + height = 11 * 72; + imageableX = 72; + imageableY = 72; + imageableWidth = width - (2 * 72); + imageableHeight = height - (2 * 72); + } + + /** + * This method returns the height of the paper in 1/72nds of an inch. + * + * @return The height of the paper in 1/72nds of an inch. + */ + public double getHeight() + { + return height; + } + + /** + * Returns the width of the paper in 1/72nds of an inch. + * + * @return The width of the paper in 1/72nds of an inch. + */ + public double getWidth() + { + return width; + } + + /** + * This method returns the X coordinate of the upper left hand corner of the + * imageable area of the paper. + * + * @return The X coordinate of the upper left hand corner of the imageable + * area of the paper. + */ + public double getImageableX() + { + return imageableX; + } + + /** + * This method returns the Y coordinate of the upper left hand corner of the + * imageable area of the paper. + * + * @return The Y coordinate of the upper left hand corner of the imageable + * area of the paper. + */ + public double getImageableY() + { + return imageableY; + } + + /** + * Returns the width of the imageable area of the paper. + * + * @return The width of the imageable area of the paper. + */ + public double getImageableWidth() + { + return imageableWidth; + } + + /** + * Returns the height of the imageable area of the paper. + * + * @return The height of the imageable area of the paper. + */ + public double getImageableHeight() + { + return imageableHeight; + } + + /** + * This method sets the size of the paper to the specified width and height, + * which are specified in 1/72nds of an inch. + * + * @param width The width of the paper in 1/72nds of an inch. + * @param height The height of the paper in 1/72nds of an inch. + */ + public void setSize(double width, double height) + { + this.width = width; + this.height = height; + } + + /** + * This method sets the imageable area of the paper by specifying the + * coordinates of the upper left hand corner of that area, and its length + * and height. All values are in 1/72nds of an inch. + * + * @param imageableX The X coordinate of the upper left hand corner of the + * imageable area, in 1/72nds of an inch. + * @param imageableY The Y coordinate of the upper left hand corner of the + * imageable area, in 1/72nds of an inch. + * @param imageableWidth The width of the imageable area of the paper, in + * 1/72nds of an inch. + * @param imageableHeight The heigth of the imageable area of the paper, in + * 1/72nds of an inch. + */ + public void setImageableArea(double imageableX, double imageableY, + double imageableWidth, double imageableHeight) + { + this.imageableX = imageableX; + this.imageableY = imageableY; + this.imageableWidth = imageableWidth; + this.imageableHeight = imageableHeight; + } + + /** + * This method creates a copy of this object. + * + * @return A copy of this object. + */ + public Object clone() + { + try + { + return (super.clone()); + } + catch (CloneNotSupportedException e) + { + return (null); + } + } -/*************************************************************************/ - -/** - * Returns the width of the paper in 1/72nds of an inch. - * - * @return The width of the paper in 1/72nds of an inch. - */ -public double -getWidth() -{ - return(width); } - -/*************************************************************************/ - -/** - * This method returns the X coordinate of the upper left hand corner - * of the imageable area of the paper. - * - * @return The X coordinate of the upper left hand corner of the imageable - * area of the paper. - */ -public double -getImageableX() -{ - return(imageableX); -} - -/*************************************************************************/ - -/** - * This method returns the Y coordinate of the upper left hand corner - * of the imageable area of the paper. - * - * @return The Y coordinate of the upper left hand corner of the imageable - * area of the paper. - */ -public double -getImageableY() -{ - return(imageableY); -} - -/*************************************************************************/ - -/** - * Returns the width of the imageable area of the paper. - * - * @return The width of the imageable area of the paper. - */ -public double -getImageableWidth() -{ - return(imageableWidth); -} - -/*************************************************************************/ - -/** - * Returns the height of the imageable area of the paper. - * - * @return The height of the imageable area of the paper. - */ -public double -getImageableHeight() -{ - return(imageableHeight); -} - -/*************************************************************************/ - -/** - * This method sets the size of the paper to the specified width and - * height, which are specified in 1/72nds of an inch. - * - * @param width The width of the paper in 1/72nds of an inch. - * @param height The height of the paper in 1/72nds of an inch. - */ -public void -setSize(double width, double height) -{ - this.width = width; - this.height = height; -} - -/*************************************************************************/ - -/** - * This method sets the imageable area of the paper by specifying the - * coordinates of the upper left hand corner of that area, and its - * length and height. All values are in 1/72nds of an inch. - * - * @param imageableX The X coordinate of the upper left hand corner of - * the imageable area, in 1/72nds of an inch. - * @param imageableY The Y coordinate of the upper left hand corner of - * the imageable area, in 1/72nds of an inch. - * @param imageableWidth The width of the imageable area of the paper, - * in 1/72nds of an inch. - * @param imageableHeight The heigth of the imageable area of the paper, - * in 1/72nds of an inch. - */ -public void -setImageableArea(double imageableX, double imageableY, - double imageableWidth, double imageableHeight) -{ - this.imageableX = imageableX; - this.imageableY = imageableY; - this.imageableWidth = imageableWidth; - this.imageableHeight = imageableHeight; -} - -/*************************************************************************/ - -/** - * This method creates a copy of this object. - * - * @return A copy of this object. - */ -public Object -clone() -{ - try - { - return(super.clone()); - } - catch(CloneNotSupportedException e) - { - return(null); - } -} - -} // class Paper - diff --git a/java/awt/print/PrinterGraphics.java b/java/awt/print/PrinterGraphics.java index 5ca641904..62fde8406 100644 --- a/java/awt/print/PrinterGraphics.java +++ b/java/awt/print/PrinterGraphics.java @@ -1,5 +1,5 @@ /* PrinterGraphics.java -- Hook to return print job controller. - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,23 +39,20 @@ exception statement from your version. */ package java.awt.print; /** - * This interface is implemented by the Graphics instance - * that is used for rendering pages. It provides a hook to return the - * object that is controlling the print job. - * - * @author Aaron M. Renn (arenn@urbanophile.com) - */ + * This interface is implemented by the Graphics instance that is + * used for rendering pages. It provides a hook to return the object that is + * controlling the print job. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ public interface PrinterGraphics { - -/** - * This method returns the instance of PrinterJob that is - * controlling this print job. - * - * @return The PrinterJob that is controlling this print job. - */ -PrinterJob -getPrinterJob(); - -} // interface PrinterGraphics - + /** + * This method returns the instance of PrinterJob that is + * controlling this print job. + * + * @return The PrinterJob that is controlling this print job. + */ + PrinterJob getPrinterJob(); + +} diff --git a/java/awt/print/PrinterJob.java b/java/awt/print/PrinterJob.java index e1aeabc3e..7f67a6b04 100644 --- a/java/awt/print/PrinterJob.java +++ b/java/awt/print/PrinterJob.java @@ -1,5 +1,5 @@ /* PrinterJob.java -- This job is the printer control class - Copyright (C) 1999, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1999, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -61,7 +61,7 @@ public abstract class PrinterJob public static PrinterJob getPrinterJob() { // FIXME: Need to fix this to load a default implementation instance. - return null; + return new NoPrinterJob(); } /** diff --git a/java/beans/DefaultPersistenceDelegate.java b/java/beans/DefaultPersistenceDelegate.java index 9dd1ae564..ca1041fef 100644 --- a/java/beans/DefaultPersistenceDelegate.java +++ b/java/beans/DefaultPersistenceDelegate.java @@ -157,6 +157,23 @@ public class DefaultPersistenceDelegate extends PersistenceDelegate protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) { + // Calling the supertype's implementation of initialize makes it + // possible that descendants of classes like AbstractHashMap + // or Hashtable are serialized correctly. This mechanism grounds on + // two other facts: + // * Each class which has not registered a special purpose + // PersistenceDelegate is handled by a DefaultPersistenceDelegate + // instance. + // * PersistenceDelegate.initialize() is implemented in a way that it + // calls the initialize method of the superclass' persistence delegate. + super.initialize(type, oldInstance, newInstance, out); + + // Suppresses the writing of property setting statements when this delegate + // is not used for the exact instance type. By doing so the following code + // is called only once per object. + if (type != oldInstance.getClass()) + return; + try { PropertyDescriptor[] propertyDescs = Introspector.getBeanInfo( diff --git a/java/beans/Encoder.java b/java/beans/Encoder.java index e7b53d786..cde1735f4 100644 --- a/java/beans/Encoder.java +++ b/java/beans/Encoder.java @@ -1,5 +1,5 @@ /* Encoder.java - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,21 +38,16 @@ package java.beans; +import gnu.java.beans.DefaultExceptionListener; import gnu.java.beans.encoder.ArrayPersistenceDelegate; import gnu.java.beans.encoder.ClassPersistenceDelegate; import gnu.java.beans.encoder.CollectionPersistenceDelegate; import gnu.java.beans.encoder.MapPersistenceDelegate; import gnu.java.beans.encoder.PrimitivePersistenceDelegate; -import java.util.ArrayList; +import java.util.AbstractCollection; import java.util.HashMap; -import java.util.HashSet; import java.util.IdentityHashMap; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.Vector; /** * @author Robert Schuster (robertschuster@fsfe.org) @@ -123,31 +118,11 @@ public class Encoder delegates.put(Object[].class, new ArrayPersistenceDelegate()); pd = new CollectionPersistenceDelegate(); - delegates.put(ArrayList.class, pd); - delegates.put(LinkedList.class, pd); - delegates.put(Vector.class, pd); - delegates.put(HashSet.class, pd); - delegates.put(LinkedHashSet.class, pd); - delegates.put(TreeSet.class, pd); + delegates.put(AbstractCollection.class, pd); pd = new MapPersistenceDelegate(); - delegates.put(HashMap.class, pd); - delegates.put(TreeMap.class, pd); + delegates.put(java.util.AbstractMap.class, pd); delegates.put(java.util.Hashtable.class, pd); - delegates.put(java.util.IdentityHashMap.class, pd); - - delegates.put(java.util.LinkedHashMap.class, pd); - delegates.put(java.util.Properties.class, pd); - - delegates.put(java.awt.RenderingHints.class, pd); - delegates.put(java.util.WeakHashMap.class, pd); - delegates.put(javax.swing.UIDefaults.class, pd); - - // TODO: These classes need to be implemented first - //delegates.put(java.security.AuthProvider.class, pd); - //delegates.put(java.util.concurrent.ConcurrentHashMap.class, pd); - //delegates.put(java.util.EnumMap.class, pd); - //delegates.put(javax.management.openmbean.TabularDataSupport.class, pd); defaultPersistenceDelegate = new DefaultPersistenceDelegate(); delegates.put(Object.class, defaultPersistenceDelegate); @@ -194,14 +169,8 @@ public class Encoder */ public void setExceptionListener(ExceptionListener listener) { - exceptionListener = (listener != null) ? listener : new ExceptionListener() - { - public void exceptionThrown(Exception e) - { - System.err.println("exception thrown: " + e); - e.printStackTrace(); - } - }; + exceptionListener = (listener != null) + ? listener : DefaultExceptionListener.INSTANCE; } /** diff --git a/java/beans/EventSetDescriptor.java b/java/beans/EventSetDescriptor.java index e687b8a30..381a45303 100644 --- a/java/beans/EventSetDescriptor.java +++ b/java/beans/EventSetDescriptor.java @@ -45,398 +45,719 @@ import java.lang.reflect.Modifier; import java.util.Vector; /** - ** EventSetDescriptor describes the hookup between an event source - ** class and an event listener class. - ** - ** EventSets have several attributes: the listener class, the events - ** that can be fired to the listener (methods in the listener class), and - ** an add and remove listener method from the event firer's class.

    - ** - ** The methods have these constraints on them:

    - **

      - **
    • event firing methods: must have void return value. Any - ** parameters and exceptions are allowed. May be public, protected or - ** package-protected. (Don't ask me why that is, I'm just following the spec. - ** The only place it is even mentioned is in the Java Beans white paper, and - ** there it is only implied.)
    • - **
    • add listener method: must have void return value. Must - ** take exactly one argument, of the listener class's type. May fire either - ** zero exceptions, or one exception of type java.util.TooManyListenersException. - ** Must be public.
    • - **
    • remove listener method: must have void return value. - ** Must take exactly one argument, of the listener class's type. May not - ** fire any exceptions. Must be public.
    • - **
    - ** - ** A final constraint is that event listener classes must extend from EventListener.

    - ** - ** There are also various design patterns associated with some of the methods - ** of construction. Those are explained in more detail in the appropriate - ** constructors.

    - ** - ** Documentation Convention: for proper - ** Internalization of Beans inside an RAD tool, sometimes there - ** are two names for a property or method: a programmatic, or - ** locale-independent name, which can be used anywhere, and a - ** localized, display name, for ease of use. In the - ** documentation I will specify different String values as - ** either programmatic or localized to - ** make this distinction clear. - ** - ** @author John Keiser - ** @since JDK1.1 - ** @version 1.1.0, 31 May 1998 - **/ - -public class EventSetDescriptor extends FeatureDescriptor { - private Method addListenerMethod; - private Method removeListenerMethod; - private Class listenerType; - private MethodDescriptor[] listenerMethodDescriptors; - private Method[] listenerMethods; - - private boolean unicast; - private boolean inDefaultEventSet = true; - - /** Create a new EventSetDescriptor. - ** This version of the constructor enforces the rules imposed on the methods - ** described at the top of this class, as well as searching for:

    - **

      - **
    1. The event-firing method must be non-private with signature - ** void <listenerMethodName>(<eventSetName>Event) - ** (where <eventSetName> has its first character capitalized - ** by the constructor and the Event is a descendant of - ** java.util.EventObject) in class listenerType - ** (any exceptions may be thrown). - ** Implementation note: Note that there could conceivably be multiple - ** methods with this type of signature (example: java.util.MouseEvent vs. - ** my.very.own.MouseEvent). In this implementation, all methods fitting the - ** description will be put into the EventSetDescriptor, even - ** though the spec says only one should be chosen (they probably weren't thinking as - ** pathologically as I was). I don't like arbitrarily choosing things. - ** If your class has only one such signature, as most do, you'll have no problems.
    2. - **
    3. The add and remove methods must be public and named - ** void add<eventSetName>Listener(<listenerType>) and - ** void remove<eventSetName>Listener(<listenerType>) in - ** in class eventSourceClass, where - ** <eventSetName> will have its first letter capitalized. - ** Standard exception rules (see class description) apply.
    4. - **
    - ** @param eventSourceClass the class containing the add/remove listener methods. - ** @param eventSetName the programmatic name of the event set, generally starting - ** with a lowercase letter (i.e. fooManChu instead of FooManChu). This will be used - ** to generate the name of the event object as well as the names of the add and - ** remove methods. - ** @param listenerType the class containing the event firing method. - ** @param listenerMethodName the name of the event firing method. - ** @exception IntrospectionException if listenerType is not an EventListener, - ** or if methods are not found or are invalid. - **/ - public EventSetDescriptor(Class eventSourceClass, - String eventSetName, - Class listenerType, - String listenerMethodName) throws IntrospectionException { - setName(eventSetName); - if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { - throw new IntrospectionException("Listener type is not an EventListener."); - } - - String[] names = new String[1]; - names[0] = listenerMethodName; - - try { - eventSetName = Character.toUpperCase(eventSetName.charAt(0)) + eventSetName.substring(1); - } catch(StringIndexOutOfBoundsException e) { - eventSetName = ""; - } - - findMethods(eventSourceClass,listenerType,names,"add"+eventSetName+"Listener","remove"+eventSetName+"Listener",eventSetName+"Event"); - this.listenerType = listenerType; - checkAddListenerUnicast(); - if(this.removeListenerMethod.getExceptionTypes().length > 0) { - throw new IntrospectionException("Listener remove method throws exceptions."); - } - } - - /** Create a new EventSetDescriptor. - ** This form of the constructor allows you to specify the names of the methods and adds - ** no new constraints on top of the rules already described at the top of the class.

    - ** - ** @param eventSourceClass the class containing the add and remove listener methods. - ** @param eventSetName the programmatic name of the event set, generally starting - ** with a lowercase letter (i.e. fooManChu instead of FooManChu). - ** @param listenerType the class containing the event firing methods. - ** @param listenerMethodNames the names of the even firing methods. - ** @param addListenerMethodName the name of the add listener method. - ** @param removeListenerMethodName the name of the remove listener method. - ** @exception IntrospectionException if listenerType is not an EventListener - ** or if methods are not found or are invalid. - **/ - public EventSetDescriptor(Class eventSourceClass, - String eventSetName, - Class listenerType, - String[] listenerMethodNames, - String addListenerMethodName, - String removeListenerMethodName) throws IntrospectionException { - setName(eventSetName); - if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { - throw new IntrospectionException("Listener type is not an EventListener."); - } - - findMethods(eventSourceClass,listenerType,listenerMethodNames,addListenerMethodName,removeListenerMethodName,null); - this.listenerType = listenerType; - checkAddListenerUnicast(); - if(this.removeListenerMethod.getExceptionTypes().length > 0) { - throw new IntrospectionException("Listener remove method throws exceptions."); - } - } - - /** Create a new EventSetDescriptor. - ** This form of constructor allows you to explicitly say which methods do what, and - ** no reflection is done by the EventSetDescriptor. The methods are, however, - ** checked to ensure that they follow the rules set forth at the top of the class. - ** @param eventSetName the programmatic name of the event set, generally starting - ** with a lowercase letter (i.e. fooManChu instead of FooManChu). - ** @param listenerType the class containing the listenerMethods. - ** @param listenerMethods the event firing methods. - ** @param addListenerMethod the add listener method. - ** @param removeListenerMethod the remove listener method. - ** @exception IntrospectionException if the listenerType is not an EventListener, - ** or any of the methods are invalid. - **/ - public EventSetDescriptor(String eventSetName, - Class listenerType, - Method[] listenerMethods, - Method addListenerMethod, - Method removeListenerMethod) throws IntrospectionException { - setName(eventSetName); - if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { - throw new IntrospectionException("Listener type is not an EventListener."); - } - - this.listenerMethods = listenerMethods; - this.addListenerMethod = addListenerMethod; - this.removeListenerMethod = removeListenerMethod; - this.listenerType = listenerType; - checkMethods(); - checkAddListenerUnicast(); - if(this.removeListenerMethod.getExceptionTypes().length > 0) { - throw new IntrospectionException("Listener remove method throws exceptions."); - } - } - - /** Create a new EventSetDescriptor. - ** This form of constructor allows you to explicitly say which methods do what, and - ** no reflection is done by the EventSetDescriptor. The methods are, however, - ** checked to ensure that they follow the rules set forth at the top of the class. - ** @param eventSetName the programmatic name of the event set, generally starting - ** with a lowercase letter (i.e. fooManChu instead of FooManChu). - ** @param listenerType the class containing the listenerMethods. - ** @param listenerMethodDescriptors the event firing methods. - ** @param addListenerMethod the add listener method. - ** @param removeListenerMethod the remove listener method. - ** @exception IntrospectionException if the listenerType is not an EventListener, - ** or any of the methods are invalid. - **/ - public EventSetDescriptor(String eventSetName, - Class listenerType, - MethodDescriptor[] listenerMethodDescriptors, - Method addListenerMethod, - Method removeListenerMethod) throws IntrospectionException { - setName(eventSetName); - if(!java.util.EventListener.class.isAssignableFrom(listenerType)) { - throw new IntrospectionException("Listener type is not an EventListener."); - } - - this.listenerMethodDescriptors = listenerMethodDescriptors; - this.listenerMethods = new Method[listenerMethodDescriptors.length]; - for(int i=0;i 0) { - throw new IntrospectionException("Listener remove method throws exceptions."); - } - } - - /** Get the class that contains the event firing methods. **/ - public Class getListenerType() { - return listenerType; - } - - /** Get the event firing methods. **/ - public Method[] getListenerMethods() { - return listenerMethods; - } - - /** Get the event firing methods as MethodDescriptors. **/ - public MethodDescriptor[] getListenerMethodDescriptors() { - if(listenerMethodDescriptors == null) { - listenerMethodDescriptors = new MethodDescriptor[listenerMethods.length]; - for(int i=0;i 1) { - throw new IntrospectionException("Listener add method throws too many exceptions."); - } else if(addListenerExceptions.length == 1 - && !java.util.TooManyListenersException.class.isAssignableFrom(addListenerExceptions[0])) { - throw new IntrospectionException("Listener add method throws too many exceptions."); - } - } - - private void checkMethods() throws IntrospectionException { - if(!addListenerMethod.getDeclaringClass().isAssignableFrom(removeListenerMethod.getDeclaringClass()) - && !removeListenerMethod.getDeclaringClass().isAssignableFrom(addListenerMethod.getDeclaringClass())) { - throw new IntrospectionException("add and remove listener methods do not come from the same class. This is bad."); - } - if(!addListenerMethod.getReturnType().equals(java.lang.Void.TYPE) - || addListenerMethod.getParameterTypes().length != 1 - || !listenerType.equals(addListenerMethod.getParameterTypes()[0]) - || !Modifier.isPublic(addListenerMethod.getModifiers())) { - throw new IntrospectionException("Add Listener Method invalid."); - } - if(!removeListenerMethod.getReturnType().equals(java.lang.Void.TYPE) - || removeListenerMethod.getParameterTypes().length != 1 - || !listenerType.equals(removeListenerMethod.getParameterTypes()[0]) - || removeListenerMethod.getExceptionTypes().length > 0 - || !Modifier.isPublic(removeListenerMethod.getModifiers())) { - throw new IntrospectionException("Remove Listener Method invalid."); - } - - for(int i=0;iEventSets have several attributes: the listener class, + * the events that can be fired to the listener (methods in the listener + * class), and an add and remove listener method from the event firer's + * class. + *

    + * + *

    + * The methods have these constraints on them: + *

      + *
    • event firing methods: must have void return value. Any + * parameters and exceptions are allowed. May be public, protected or + * package-protected. (Don't ask me why that is, I'm just following the spec. + * The only place it is even mentioned is in the Java Beans white paper, and + * there it is only implied.)
    • + * + *
    • add listener method: must have void return value. Must + * take exactly one argument, of the listener class's type. May fire either + * zero exceptions, or one exception of type + * java.util.TooManyListenersException. + * Must be public.
    • + * + *
    • remove listener method: must have void return value. Must + * take exactly one argument, of the listener class's type. May not fire any + * exceptions. Must be public.
    • + *
    + * + *

    + * A final constraint is that event listener classes must extend from + * EventListener. + *

    + * + *

    + * There are also various design patterns associated with some of the methods + * of construction. Those are explained in more detail in the appropriate + * constructors. + *

    + * + *

    + * Documentation Convention: for proper Internalization of + * Beans inside an RAD tool, sometimes there are two names for a property or + * method: a programmatic, or locale-independent name, which can be used + * anywhere, and a localized, display name, for ease of use. In the + * documentation I will specify different String values as either + * programmatic or localized to make this distinction clear. + * + * @author John Keiser + * @author Robert Schuster (robertschuster@fsfe.org) + * @since 1.1 + */ + +public class EventSetDescriptor extends FeatureDescriptor +{ + private Method addListenerMethod; + + private Method removeListenerMethod; + + private Class listenerType; + + private MethodDescriptor[] listenerMethodDescriptors; + + private Method[] listenerMethods; + + private Method getListenerMethod; + + private boolean unicast; + + private boolean inDefaultEventSet = true; + + /** + * Creates a new EventSetDescriptor + * This version of the constructor enforces the rules imposed on the methods + * described at the top of this class, as well as searching for: + *

    + * + *
      + *
    1. + * The event-firing method must be non-private with signature void + * <listenerMethodName>(<eventSetName>Event) (where + * <eventSetName> has its first character capitalized + * by the constructor and the Event is a descendant of + * {@link java.util.EventObject}) in class listenerType + * (any exceptions may be thrown). Implementation note: Note that + * there could conceivably be multiple methods with this type of signature + * (example: java.util.MouseEvent vs. + * my.very.own.MouseEvent). In this implementation, all + * methods fitting the description will be put into the + * EventSetDescriptor, even though the spec says only one + * should be chosen (they probably weren't thinking as pathologically as I + * was). I don't like arbitrarily choosing things. If your class has only one + * such signature, as most do, you'll have no problems.
    2. + * + *
    3. The add and remove methods must be public and named void + * add<eventSetName>Listener(<listenerType>) and + * void remove<eventSetName>Listener(<listenerType>) + * in in class eventSourceClass, where + * <eventSetName> will have its first letter capitalized. + * Standard exception rules (see class description) apply.
    4. + *
    + * + * @param eventSourceClass + * the class containing the add/remove listener methods. + * @param eventSetName + * the programmatic name of the event set, generally starting with a + * lowercase letter (i.e. fooManChu instead of FooManChu). This will + * be used to generate the name of the event object as well as the + * names of the add and remove methods. + * @param listenerType + * the class containing the event firing method. + * @param listenerMethodName + * the name of the event firing method. + * @exception IntrospectionException + * if listenerType is not an EventListener, or if methods are not + * found or are invalid. + */ + public EventSetDescriptor(Class eventSourceClass, String eventSetName, + Class listenerType, String listenerMethodName) + throws IntrospectionException + { + setName(eventSetName); + if (!java.util.EventListener.class.isAssignableFrom(listenerType)) + { + throw new IntrospectionException( + "Listener type is not an EventListener."); + } + + String[] names = new String[1]; + names[0] = listenerMethodName; + + try + { + eventSetName = Character.toUpperCase(eventSetName.charAt(0)) + + eventSetName.substring(1); + } + catch (StringIndexOutOfBoundsException e) + { + eventSetName = ""; + } + + findMethods(eventSourceClass, listenerType, names, + "add" + eventSetName + "Listener", + "remove" + eventSetName + "Listener", eventSetName + "Event"); + this.listenerType = listenerType; + checkAddListenerUnicast(); + if (this.removeListenerMethod.getExceptionTypes().length > 0) + { + throw new IntrospectionException( + "Listener remove method throws exceptions."); + } + } + + /** + * Creates a new EventSetDescriptor. + * + *

    This form of the constructor allows you to specify the names of the + * methods and adds no new constraints on top of the rules already described + * at the top of the class. + *

    + * + * @param eventSourceClass + * the class containing the add and remove listener methods. + * @param eventSetName + * the programmatic name of the event set, generally starting with a + * lowercase letter (i.e. fooManChu instead of FooManChu). + * @param listenerType + * the class containing the event firing methods. + * @param listenerMethodNames + * the names of the even firing methods. + * @param addListenerMethodName + * the name of the add listener method. + * @param removeListenerMethodName + * the name of the remove listener method. + * @exception IntrospectionException + * if listenerType is not an EventListener or if methods are not + * found or are invalid. + */ + public EventSetDescriptor(Class eventSourceClass, String eventSetName, + Class listenerType, String[] listenerMethodNames, + String addListenerMethodName, + String removeListenerMethodName) + throws IntrospectionException + { + setName(eventSetName); + if (!java.util.EventListener.class.isAssignableFrom(listenerType)) + { + throw new IntrospectionException( + "Listener type is not an EventListener."); + } + + findMethods(eventSourceClass, listenerType, listenerMethodNames, + addListenerMethodName, removeListenerMethodName, null); + this.listenerType = listenerType; + checkAddListenerUnicast(); + if (this.removeListenerMethod.getExceptionTypes().length > 0) + { + throw new IntrospectionException( + "Listener remove method throws exceptions."); + } + } + + /** + * Creates a new EventSetDescriptor. + * + *

    + * This variant of the constructor allows you to specify the names of the + * methods and adds no new constraints on top of the rules already described + * at the top of the class. + *

    + *

    + * A valid GetListener method is public, flags no exceptions and has one + * argument which is of type Class + * {@link java.awt.Component#getListeners(Class)} is such a method. + *

    + *

    + * Note: The validity of the return value of the GetListener method is not + * checked. + *

    + * + * @param eventSourceClass + * the class containing the add and remove listener methods. + * @param eventSetName + * the programmatic name of the event set, generally starting with a + * lowercase letter (i.e. fooManChu instead of FooManChu). + * @param listenerType + * the class containing the event firing methods. + * @param listenerMethodNames + * the names of the even firing methods. + * @param addListenerMethodName + * the name of the add listener method. + * @param removeListenerMethodName + * the name of the remove listener method. + * @param getListenerMethodName + * Name of a method which returns the array of listeners. + * @exception IntrospectionException + * if listenerType is not an EventListener or if methods are not + * found or are invalid. + * @since 1.4 + */ + public EventSetDescriptor(Class eventSourceClass, String eventSetName, + Class listenerType, String[] listenerMethodNames, + String addListenerMethodName, + String removeListenerMethodName, + String getListenerMethodName) + throws IntrospectionException + { + this(eventSourceClass, eventSetName, listenerType, listenerMethodNames, + addListenerMethodName, removeListenerMethodName); + + Method newGetListenerMethod = null; + + try + { + newGetListenerMethod + = eventSourceClass.getMethod(getListenerMethodName, + new Class[] { Class.class }); + } + catch (NoSuchMethodException nsme) + { + throw (IntrospectionException) + new IntrospectionException("No method named " + getListenerMethodName + + " in class " + listenerType + + " which can be used as" + + " getListenerMethod.").initCause(nsme); + } + + // Note: This does not check the return value (which + // should be EventListener[]) but the JDK does not either. + + getListenerMethod = newGetListenerMethod; + + } + + /** + * Creates a new EventSetDescriptor. + * + *

    + * This variant of the constructor allows you to specify the names of the + * methods and adds no new constraints on top of the rules already described + * at the top of the class. + *

    + *

    + * A valid GetListener method is public, flags no exceptions and has one + * argument which is of type Class + * {@link java.awt.Component#getListeners(Class)} is such a method. + *

    + *

    + * Note: The validity of the return value of the GetListener method is not + * checked. + *

    + * + * @param eventSetName + * the programmatic name of the event set, generally starting with a + * lowercase letter (i.e. fooManChu instead of FooManChu). + * @param listenerType + * the class containing the listenerMethods. + * @param listenerMethods + * the event firing methods. + * @param addListenerMethod + * the add listener method. + * @param removeListenerMethod + * the remove listener method. + * @param getListenerMethod + * The method which returns an array of the listeners. + * @exception IntrospectionException + * if the listenerType is not an EventListener, or any of the + * methods are invalid. + * @since 1.4 + */ + public EventSetDescriptor(String eventSetName, Class listenerType, + Method[] listenerMethods, Method addListenerMethod, + Method removeListenerMethod, + Method getListenerMethod) + throws IntrospectionException + { + this(eventSetName, listenerType, listenerMethods, addListenerMethod, + removeListenerMethod); + + // Do no checks if the getListenerMethod is null. + if (getListenerMethod.getParameterTypes().length != 1 + || getListenerMethod.getParameterTypes()[0] != Class.class + || getListenerMethod.getExceptionTypes().length > 0 + || !Modifier.isPublic(getListenerMethod.getModifiers())) + throw new IntrospectionException("GetListener method is invalid."); + + // Note: This does not check the return value (which + // should be EventListener[]) but the JDK does not either. + + this.getListenerMethod = getListenerMethod; + } + + /** + * Creates a new EventSetDescriptor. + * + *

    This form of constructor allows you to explicitly say which methods + * do what, and no reflection is done by the EventSetDescriptor. + * The methods are, however, checked to ensure that they follow the rules + * set forth at the top of the class. + * + * @param eventSetName + * the programmatic name of the event set, generally starting with a + * lowercase letter (i.e. fooManChu instead of FooManChu). + * @param listenerType + * the class containing the listenerMethods. + * @param listenerMethods + * the event firing methods. + * @param addListenerMethod + * the add listener method. + * @param removeListenerMethod + * the remove listener method. + * @exception IntrospectionException + * if the listenerType is not an EventListener, or any of the + * methods are invalid. + */ + public EventSetDescriptor(String eventSetName, Class listenerType, + Method[] listenerMethods, Method addListenerMethod, + Method removeListenerMethod) + throws IntrospectionException + { + setName(eventSetName); + if (!java.util.EventListener.class.isAssignableFrom(listenerType)) + { + throw new IntrospectionException( + "Listener type is not an EventListener."); + } + + this.listenerMethods = listenerMethods; + this.addListenerMethod = addListenerMethod; + this.removeListenerMethod = removeListenerMethod; + this.listenerType = listenerType; + checkMethods(); + checkAddListenerUnicast(); + if (this.removeListenerMethod.getExceptionTypes().length > 0) + { + throw new IntrospectionException( + "Listener remove method throws exceptions."); + } + } + + /** Creates a new EventSetDescriptor. + * + *

    This form of constructor allows you to explicitly say which methods do + * what, and no reflection is done by the EventSetDescriptor. + * The methods are, however, checked to ensure that they follow the rules + * set forth at the top of the class. + * + * @param eventSetName + * the programmatic name of the event set, generally starting with a + * lowercase letter (i.e. fooManChu instead of FooManChu). + * @param listenerType + * the class containing the listenerMethods. + * @param listenerMethodDescriptors + * the event firing methods. + * @param addListenerMethod + * the add listener method. + * @param removeListenerMethod + * the remove listener method. + * @exception IntrospectionException + * if the listenerType is not an EventListener, or any of the + * methods are invalid. + */ + public EventSetDescriptor(String eventSetName, Class listenerType, + MethodDescriptor[] listenerMethodDescriptors, + Method addListenerMethod, + Method removeListenerMethod) + throws IntrospectionException + { + setName(eventSetName); + if (!java.util.EventListener.class.isAssignableFrom(listenerType)) + { + throw new IntrospectionException( + "Listener type is not an EventListener."); + } + + this.listenerMethodDescriptors = listenerMethodDescriptors; + this.listenerMethods = new Method[listenerMethodDescriptors.length]; + for (int i = 0; i < this.listenerMethodDescriptors.length; i++) + { + this.listenerMethods[i] + = this.listenerMethodDescriptors[i].getMethod(); + } + + this.addListenerMethod = addListenerMethod; + this.removeListenerMethod = removeListenerMethod; + this.listenerType = listenerType; + checkMethods(); + checkAddListenerUnicast(); + if (this.removeListenerMethod.getExceptionTypes().length > 0) + { + throw new IntrospectionException( + "Listener remove method throws exceptions."); + } + } + + /** Returns the class that contains the event firing methods. + */ + public Class getListenerType() + { + return listenerType; + } + + /** Returns the event firing methods. + */ + public Method[] getListenerMethods() + { + return listenerMethods; + } + + /** Returns the event firing methods as {@link MethodDescriptor}. + */ + public MethodDescriptor[] getListenerMethodDescriptors() + { + if (listenerMethodDescriptors == null) + { + listenerMethodDescriptors + = new MethodDescriptor[listenerMethods.length]; + + for (int i = 0; i < listenerMethods.length; i++) + { + listenerMethodDescriptors[i] + = new MethodDescriptor(listenerMethods[i]); + } + } + + return listenerMethodDescriptors; + } + + /** Returns the add listener method. + */ + public Method getAddListenerMethod() + { + return addListenerMethod; + } + + /* Returns the remove listener method. + */ + public Method getRemoveListenerMethod() + { + return removeListenerMethod; + } + + /** + * Returns the method that retrieves the listeners or null if + * it does not exist. + */ + public Method getGetListenerMethod() + { + return getListenerMethod; + } + + /** Sets whether or not multiple listeners may be added. + * + * @param unicast + * whether or not multiple listeners may be added. + */ + public void setUnicast(boolean unicast) + { + this.unicast = unicast; + } + + /** Returns whether or not multiple listeners may be added. + * (Defaults to false.) + */ + public boolean isUnicast() + { + return unicast; + } + + /** Sets whether or not this is in the default event set. + * + * @param inDefaultEventSet + * whether this is in the default event set. + */ + public void setInDefaultEventSet(boolean inDefaultEventSet) + { + this.inDefaultEventSet = inDefaultEventSet; + } + + /** Returns whether or not this is in the default event set. + * (Defaults to true.) + */ + public boolean isInDefaultEventSet() + { + return inDefaultEventSet; + } + + private void checkAddListenerUnicast() throws IntrospectionException + { + Class[] addListenerExceptions = this.addListenerMethod.getExceptionTypes(); + if (addListenerExceptions.length > 1) + { + throw new IntrospectionException( + "Listener add method throws too many exceptions."); + } + else if (addListenerExceptions.length == 1 + && !java.util.TooManyListenersException.class + .isAssignableFrom(addListenerExceptions[0])) + { + throw new IntrospectionException( + "Listener add method throws too many exceptions."); + } + } + + private void checkMethods() throws IntrospectionException + { + if (!addListenerMethod.getDeclaringClass() + .isAssignableFrom(removeListenerMethod.getDeclaringClass()) + && !removeListenerMethod.getDeclaringClass() + .isAssignableFrom(addListenerMethod.getDeclaringClass())) + { + throw new IntrospectionException( + "add and remove listener methods do not come from the" + + " same class. This is bad."); + } + if (!addListenerMethod.getReturnType().equals(java.lang.Void.TYPE) + || addListenerMethod.getParameterTypes().length != 1 + || !listenerType.equals(addListenerMethod.getParameterTypes()[0]) + || !Modifier.isPublic(addListenerMethod.getModifiers())) + { + throw new IntrospectionException("Add Listener Method invalid."); + } + if (!removeListenerMethod.getReturnType().equals(java.lang.Void.TYPE) + || removeListenerMethod.getParameterTypes().length != 1 + || !listenerType.equals(removeListenerMethod.getParameterTypes()[0]) + || removeListenerMethod.getExceptionTypes().length > 0 + || !Modifier.isPublic(removeListenerMethod.getModifiers())) + { + throw new IntrospectionException("Remove Listener Method invalid."); + } + + for (int i = 0; i < listenerMethods.length; i++) + { + if (!listenerMethods[i].getReturnType().equals(java.lang.Void.TYPE) + || Modifier.isPrivate(listenerMethods[i].getModifiers())) + { + throw new IntrospectionException("Event Method " + + listenerMethods[i].getName() + + " non-void or private."); + } + if (!listenerMethods[i].getDeclaringClass() + .isAssignableFrom(listenerType)) + { + throw new IntrospectionException("Event Method " + + listenerMethods[i].getName() + + " not from class " + + listenerType.getName()); + } + } + } + + private void findMethods(Class eventSourceClass, Class listenerType, + String listenerMethodNames[], + String addListenerMethodName, + String removeListenerMethodName, + String absurdEventClassCheckName) + throws IntrospectionException + { + + /* Find add listener method and remove listener method. */ + Class[] listenerArgList = new Class[1]; + listenerArgList[0] = listenerType; + try + { + this.addListenerMethod + = eventSourceClass.getMethod(addListenerMethodName, + listenerArgList); + } + catch (SecurityException E) + { + throw new IntrospectionException( + "SecurityException trying to access method " + + addListenerMethodName + "."); + } + catch (NoSuchMethodException E) + { + throw new IntrospectionException("Could not find method " + + addListenerMethodName + "."); + } + + if (this.addListenerMethod == null + || !this.addListenerMethod.getReturnType().equals(java.lang.Void.TYPE)) + { + throw new IntrospectionException( + "Add listener method does not exist, is not public," + + " or is not void."); + } + + try + { + this.removeListenerMethod + = eventSourceClass.getMethod(removeListenerMethodName, + listenerArgList); + } + catch (SecurityException E) + { + throw new IntrospectionException( + "SecurityException trying to access method " + + removeListenerMethodName + "."); + } + catch (NoSuchMethodException E) + { + throw new IntrospectionException("Could not find method " + + removeListenerMethodName + "."); + } + if (this.removeListenerMethod == null + || !this.removeListenerMethod.getReturnType() + .equals(java.lang.Void.TYPE)) + { + throw new IntrospectionException( + "Remove listener method does not exist, is not public," + + " or is not void."); + } + + /* Find the listener methods. */ + Method[] methods; + try + { + methods = ClassHelper.getAllMethods(listenerType); + } + catch (SecurityException E) + { + throw new IntrospectionException( + "Security: You cannot access fields in this class."); + } + + Vector chosenMethods = new Vector(); + boolean[] listenerMethodFound = new boolean[listenerMethodNames.length]; + for (int i = 0; i < methods.length; i++) + { + if (Modifier.isPrivate(methods[i].getModifiers())) + { + continue; + } + Method currentMethod = methods[i]; + Class retval = currentMethod.getReturnType(); + if (retval.equals(java.lang.Void.TYPE)) + { + for (int j = 0; j < listenerMethodNames.length; j++) + { + if (currentMethod.getName().equals(listenerMethodNames[j]) + && (absurdEventClassCheckName == null + || (currentMethod.getParameterTypes().length == 1 + && ((currentMethod.getParameterTypes()[0]) + .getName().equals(absurdEventClassCheckName) + || (currentMethod.getParameterTypes()[0]) + .getName().endsWith("." + absurdEventClassCheckName))))) + { + chosenMethods.addElement(currentMethod); + listenerMethodFound[j] = true; + } + } + } + } + + /* Make sure we found all the methods we were looking for. */ + for (int i = 0; i < listenerMethodFound.length; i++) + { + if (!listenerMethodFound[i]) + { + throw new IntrospectionException("Could not find event method " + + listenerMethodNames[i]); + } + } + + /* Now that we've chosen the listener methods we want, store them. */ + this.listenerMethods = new Method[chosenMethods.size()]; + for (int i = 0; i < chosenMethods.size(); i++) + { + this.listenerMethods[i] = (Method) chosenMethods.elementAt(i); + } + } + } diff --git a/java/beans/PersistenceDelegate.java b/java/beans/PersistenceDelegate.java index 91c02d2b8..a6f715763 100644 --- a/java/beans/PersistenceDelegate.java +++ b/java/beans/PersistenceDelegate.java @@ -59,9 +59,8 @@ public abstract class PersistenceDelegate { type = type.getSuperclass(); - PersistenceDelegate pd = out.getPersistenceDelegate( - oldInstance.getClass().getSuperclass()); - + PersistenceDelegate pd = out.getPersistenceDelegate(type); + pd.initialize(type, oldInstance, newInstance, out); } } diff --git a/java/beans/PropertyChangeSupport.java b/java/beans/PropertyChangeSupport.java index 991390b56..e944e1512 100644 --- a/java/beans/PropertyChangeSupport.java +++ b/java/beans/PropertyChangeSupport.java @@ -1,5 +1,6 @@ /* PropertyChangeSupport.java -- support to manage property change listeners - Copyright (C) 1998, 1999, 2000, 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2002, 2005, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -120,14 +121,17 @@ public class PropertyChangeSupport implements Serializable * property change events will be sent to this listener. The listener add * is not unique: that is, n adds with the same listener will * result in n events being sent to that listener for every - * property change. Adding a null listener may cause a NullPointerException - * down the road. This method will unwrap a PropertyChangeListenerProxy, + * property change. Adding a null listener is silently ignored. + * This method will unwrap a PropertyChangeListenerProxy, * registering the underlying delegate to the named property list. * * @param l the listener to add */ public synchronized void addPropertyChangeListener(PropertyChangeListener l) { + if (l == null) + return; + if (l instanceof PropertyChangeListenerProxy) { PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l; @@ -216,8 +220,8 @@ public class PropertyChangeSupport implements Serializable * cumulative, too; if you are registered to listen to receive events on * all property changes, and then you register on a particular property, * you will receive change events for that property twice. Adding a null - * listener may cause a NullPointerException down the road. This method - * will unwrap a PropertyChangeListenerProxy, registering the underlying + * listener is silently ignored. This method will unwrap a + * PropertyChangeListenerProxy, registering the underlying * delegate to the named property list if the names match, and discarding * it otherwise. * @@ -228,6 +232,9 @@ public class PropertyChangeSupport implements Serializable public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener l) { + if (l == null) + return; + while (l instanceof PropertyChangeListenerProxy) { PropertyChangeListenerProxy p = (PropertyChangeListenerProxy) l; @@ -290,17 +297,16 @@ public class PropertyChangeSupport implements Serializable /** * Returns an array of all property change listeners registered under the - * given property name. If there are no registered listeners, this returns - * an empty array. + * given property name. If there are no registered listeners, or + * propertyName is null, this returns an empty array. * * @return the array of registered listeners - * @throws NullPointerException if propertyName is null * @since 1.4 */ public synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { - if (children == null) + if (children == null || propertyName == null) return new PropertyChangeListener[0]; PropertyChangeSupport s = (PropertyChangeSupport) children.get(propertyName); @@ -455,7 +461,6 @@ public class PropertyChangeSupport implements Serializable * * @param propertyName the property that may be listened on * @return whether the property is being listened on - * @throws NullPointerException if propertyName is null */ public synchronized boolean hasListeners(String propertyName) { diff --git a/java/beans/XMLDecoder.java b/java/beans/XMLDecoder.java index 238fd6bed..7618bb8cb 100644 --- a/java/beans/XMLDecoder.java +++ b/java/beans/XMLDecoder.java @@ -1,5 +1,5 @@ /* java.beans.XMLDecoder -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,7 +38,7 @@ exception statement from your version. */ package java.beans; -import gnu.java.beans.decoder.DefaultExceptionListener; +import gnu.java.beans.DefaultExceptionListener; import gnu.java.beans.decoder.PersistenceParser; import java.io.IOException; @@ -289,7 +289,7 @@ public class XMLDecoder // uses a default implementation when null if (listener == null) { - listener = new DefaultExceptionListener(); + listener = DefaultExceptionListener.INSTANCE; } exceptionListener = listener; } diff --git a/java/beans/XMLEncoder.java b/java/beans/XMLEncoder.java index f9cbe6396..feff68bd3 100644 --- a/java/beans/XMLEncoder.java +++ b/java/beans/XMLEncoder.java @@ -168,6 +168,8 @@ public class XMLEncoder extends Encoder // an erroneous state to the ScanEngine without behaving different // to the JDK. scanEngine.revoke(); + + return; } writeObject(value); diff --git a/java/io/InputStream.java b/java/io/InputStream.java index 03f5d3c48..2934f0034 100644 --- a/java/io/InputStream.java +++ b/java/io/InputStream.java @@ -193,10 +193,8 @@ public abstract class InputStream implements Closeable */ public int read(byte[] b, int off, int len) throws IOException { - if (off < 0 || len < 0 || off + len > b.length) + if (off < 0 || len < 0 || b.length - off < len) throw new IndexOutOfBoundsException(); - if (b.length == 0) - return 0; int i, ch; diff --git a/java/io/InputStreamReader.java b/java/io/InputStreamReader.java index ef8fd4542..936a03c95 100644 --- a/java/io/InputStreamReader.java +++ b/java/io/InputStreamReader.java @@ -1,5 +1,6 @@ /* InputStreamReader.java -- Reader than transforms bytes to chars - Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +39,7 @@ exception statement from your version. */ package java.io; +import gnu.classpath.SystemProperties; import gnu.java.nio.charset.EncodingHelper; import java.nio.ByteBuffer; @@ -145,7 +147,7 @@ public class InputStreamReader extends Reader this.in = in; try { - encoding = System.getProperty("file.encoding"); + encoding = SystemProperties.getProperty("file.encoding"); // Don't use NIO if avoidable if(EncodingHelper.isISOLatin1(encoding)) { @@ -231,12 +233,20 @@ public class InputStreamReader extends Reader * charset to decode the bytes in the InputStream into * characters. * - * @since 1.5 + * @since 1.4 */ public InputStreamReader(InputStream in, Charset charset) { + if (in == null) + throw new NullPointerException(); this.in = in; decoder = charset.newDecoder(); + try { + maxBytesPerChar = charset.newEncoder().maxBytesPerChar(); + } catch(UnsupportedOperationException _){ + maxBytesPerChar = 1f; + } + decoder.onMalformedInput(CodingErrorAction.REPLACE); decoder.onUnmappableCharacter(CodingErrorAction.REPLACE); decoder.reset(); @@ -247,9 +257,11 @@ public class InputStreamReader extends Reader * Creates an InputStreamReader that uses the given charset decoder * to decode the bytes in the InputStream into characters. * - * @since 1.5 + * @since 1.4 */ public InputStreamReader(InputStream in, CharsetDecoder decoder) { + if (in == null) + throw new NullPointerException(); this.in = in; this.decoder = decoder; diff --git a/java/io/ObjectInputStream.java b/java/io/ObjectInputStream.java index 3fff967b4..771222ad5 100644 --- a/java/io/ObjectInputStream.java +++ b/java/io/ObjectInputStream.java @@ -1,5 +1,5 @@ /* ObjectInputStream.java -- Class used to read serialized objects - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -563,8 +563,7 @@ public class ObjectInputStream extends InputStream classLookupTable.put(clazz, osc); setBlockDataMode(oldmode); - // find the first non-serializable, non-abstract - // class in clazz's inheritance hierarchy + // find the first non-serializable class in clazz's inheritance hierarchy Class first_nonserial = clazz.getSuperclass(); // Maybe it is a primitive class, those don't have a super class, // or Object itself. Otherwise we can keep getting the superclass @@ -573,9 +572,8 @@ public class ObjectInputStream extends InputStream if (first_nonserial == null) first_nonserial = clazz; else - while (Serializable.class.isAssignableFrom(first_nonserial) - || Modifier.isAbstract(first_nonserial.getModifiers())) - first_nonserial = first_nonserial.getSuperclass(); + while (Serializable.class.isAssignableFrom(first_nonserial)) + first_nonserial = first_nonserial.getSuperclass(); final Class local_constructor_class = first_nonserial; @@ -1604,7 +1602,14 @@ public class ObjectInputStream extends InputStream private void readNextBlock() throws IOException { - readNextBlock(this.realInputStream.readByte()); + byte marker = this.realInputStream.readByte(); + while (marker == TC_RESET) + { + if(dump) dumpElementln("RESET"); + clearHandles(); + marker = this.realInputStream.readByte(); + } + readNextBlock(marker); } private void readNextBlock(byte marker) throws IOException diff --git a/java/io/ObjectOutputStream.java b/java/io/ObjectOutputStream.java index 628d0e2b4..063433941 100644 --- a/java/io/ObjectOutputStream.java +++ b/java/io/ObjectOutputStream.java @@ -1,5 +1,5 @@ /* ObjectOutputStream.java -- Class used to write serialized objects - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -427,6 +427,8 @@ public class ObjectOutputStream extends OutputStream for (int i = 0; i < intfs.length; i++) realOutput.writeUTF(intfs[i].getName()); + assignNewHandle(osc); + boolean oldmode = setBlockDataMode(true); annotateProxyClass(osc.forClass()); setBlockDataMode(oldmode); diff --git a/java/lang/Character.java b/java/lang/Character.java index b0535e8b6..35a700d63 100644 --- a/java/lang/Character.java +++ b/java/lang/Character.java @@ -1642,6 +1642,290 @@ public final class Character implements Serializable, Comparable }; } // class UnicodeBlock + /** + * A class to encompass all the properties of characters in the + * private use blocks in the Unicode standard. This class extends + * UnassignedCharacters because the return type from getType() is + * different. + * @author Anthony Balkissoon abalkiss at redhat dot com + * + */ + private static class PrivateUseCharacters extends UnassignedCharacters + { + /** + * Returns the type of the character cp. + */ + static int getType(int cp) + { + // The upper 2 code points in any plane are considered unassigned, + // even in the private-use planes. + if ((cp & 0xffff) >= 0xfffe) + return UnassignedCharacters.getType(cp); + return PRIVATE_USE; + } + + /** + * Returns true if the character cp is defined. + */ + static boolean isDefined(int cp) + { + // The upper 2 code points in any plane are considered unassigned, + // even in the private-use planes. + if ((cp & 0xffff) >= 0xfffe) + return UnassignedCharacters.isDefined(cp); + return true; + } + + /** + * Gets the directionality for the character cp. + */ + static byte getDirectionality(int cp) + { + if ((cp & 0xffff) >= 0xfffe) + return UnassignedCharacters.getDirectionality(cp); + return DIRECTIONALITY_LEFT_TO_RIGHT; + } + } + + /** + * A class to encompass all the properties of code points that are + * currently undefined in the Unicode standard. + * @author Anthony Balkissoon abalkiss at redhat dot com + * + */ + private static class UnassignedCharacters + { + /** + * Returns the numeric value for the unassigned characters. + * @param cp the character + * @param radix the radix (not used) + * @return the numeric value of this character in this radix + */ + static int digit(int cp, int radix) + { + return -1; + } + + /** + * Returns the Unicode directionality property for unassigned + * characters. + * @param cp the character + * @return DIRECTIONALITY_UNDEFINED + */ + static byte getDirectionality(int cp) + { + return DIRECTIONALITY_UNDEFINED; + } + + /** + * Returns -1, the numeric value for unassigned Unicode characters. + * @param cp the character + * @return -1 + */ + static int getNumericValue(int cp) + { + return -1; + } + + /** + * Returns UNASSIGNED, the type of unassigned Unicode characters. + * @param cp the character + * @return UNASSIGNED + */ + static int getType(int cp) + { + return UNASSIGNED; + } + + /** + * Returns false to indiciate that the character is not defined in the + * Unicode standard. + * @param cp the character + * @return false + */ + static boolean isDefined(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not a digit. + * @param cp the character + * @return false + */ + static boolean isDigit(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot be ignored + * within an identifier + * @param cp the character + * @return false + */ + static boolean isIdentifierIgnorable(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot be part of a + * Java identifier. + * @param cp the character + * @return false + */ + static boolean isJavaIdentifierPart(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot be start a + * Java identifier. + * @param cp the character + * @return false + */ + static boolean isJavaIdentiferStart(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not a letter. + * @param cp the character + * @return false + */ + static boolean isLetter(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot is neither a letter + * nor a digit. + * @param cp the character + * @return false + */ + static boolean isLetterOrDigit(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not a lowercase letter. + * @param cp the character + * @return false + */ + static boolean isLowerCase(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot is not mirrored. + * @param cp the character + * @return false + */ + static boolean isMirrored(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not a space character. + * @param cp the character + * @return false + */ + static boolean isSpaceChar(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character it not a titlecase letter. + * @param cp the character + * @return false + */ + static boolean isTitleCase(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot be part of a + * Unicode identifier. + * @param cp the character + * @return false + */ + static boolean isUnicodeIdentifierPart(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character cannot start a + * Unicode identifier. + * @param cp the character + * @return false + */ + static boolean isUnicodeIdentifierStart(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not an uppercase letter. + * @param cp the character + * @return false + */ + static boolean isUpperCase(int cp) + { + return false; + } + + /** + * Returns false to indicate that the character is not a whitespace + * character. + * @param cp the character + * @return false + */ + static boolean isWhiteSpace(int cp) + { + return false; + } + + /** + * Returns cp to indicate this character has no lowercase conversion. + * @param cp the character + * @return cp + */ + static int toLowerCase(int cp) + { + return cp; + } + + /** + * Returns cp to indicate this character has no titlecase conversion. + * @param cp the character + * @return cp + */ + static int toTitleCase(int cp) + { + return cp; + } + + /** + * Returns cp to indicate this character has no uppercase conversion. + * @param cp the character + * @return cp + */ + static int toUpperCase(int cp) + { + return cp; + } + } + /** * The immutable value of this Character. * @@ -2126,39 +2410,128 @@ public final class Character implements Serializable, Comparable /** * Stores unicode block offset lookup table. Exploit package visibility of * String.value to avoid copying the array. - * @see #readChar(char) + * @see #readCodePoint(int) * @see CharData#BLOCKS */ - private static final char[] blocks = String.zeroBasedStringValue(CharData.BLOCKS); + private static final char[][] blocks = + new char[][]{ + String.zeroBasedStringValue(CharData.BLOCKS[0]), + String.zeroBasedStringValue(CharData.BLOCKS[1]), + String.zeroBasedStringValue(CharData.BLOCKS[2]), + String.zeroBasedStringValue(CharData.BLOCKS[3]), + String.zeroBasedStringValue(CharData.BLOCKS[4]), + String.zeroBasedStringValue(CharData.BLOCKS[5]), + String.zeroBasedStringValue(CharData.BLOCKS[6]), + String.zeroBasedStringValue(CharData.BLOCKS[7]), + String.zeroBasedStringValue(CharData.BLOCKS[8]), + String.zeroBasedStringValue(CharData.BLOCKS[9]), + String.zeroBasedStringValue(CharData.BLOCKS[10]), + String.zeroBasedStringValue(CharData.BLOCKS[11]), + String.zeroBasedStringValue(CharData.BLOCKS[12]), + String.zeroBasedStringValue(CharData.BLOCKS[13]), + String.zeroBasedStringValue(CharData.BLOCKS[14]), + String.zeroBasedStringValue(CharData.BLOCKS[15]), + String.zeroBasedStringValue(CharData.BLOCKS[16])}; /** * Stores unicode attribute offset lookup table. Exploit package visibility * of String.value to avoid copying the array. * @see CharData#DATA */ - private static final char[] data = String.zeroBasedStringValue(CharData.DATA); + private static final char[][] data = + new char[][]{ + String.zeroBasedStringValue(CharData.DATA[0]), + String.zeroBasedStringValue(CharData.DATA[1]), + String.zeroBasedStringValue(CharData.DATA[2]), + String.zeroBasedStringValue(CharData.DATA[3]), + String.zeroBasedStringValue(CharData.DATA[4]), + String.zeroBasedStringValue(CharData.DATA[5]), + String.zeroBasedStringValue(CharData.DATA[6]), + String.zeroBasedStringValue(CharData.DATA[7]), + String.zeroBasedStringValue(CharData.DATA[8]), + String.zeroBasedStringValue(CharData.DATA[9]), + String.zeroBasedStringValue(CharData.DATA[10]), + String.zeroBasedStringValue(CharData.DATA[11]), + String.zeroBasedStringValue(CharData.DATA[12]), + String.zeroBasedStringValue(CharData.DATA[13]), + String.zeroBasedStringValue(CharData.DATA[14]), + String.zeroBasedStringValue(CharData.DATA[15]), + String.zeroBasedStringValue(CharData.DATA[16])}; /** * Stores unicode numeric value attribute table. Exploit package visibility * of String.value to avoid copying the array. * @see CharData#NUM_VALUE */ - private static final char[] numValue - = String.zeroBasedStringValue(CharData.NUM_VALUE); + private static final char[][] numValue = + new char[][]{ + String.zeroBasedStringValue(CharData.NUM_VALUE[0]), + String.zeroBasedStringValue(CharData.NUM_VALUE[1]), + String.zeroBasedStringValue(CharData.NUM_VALUE[2]), + String.zeroBasedStringValue(CharData.NUM_VALUE[3]), + String.zeroBasedStringValue(CharData.NUM_VALUE[4]), + String.zeroBasedStringValue(CharData.NUM_VALUE[5]), + String.zeroBasedStringValue(CharData.NUM_VALUE[6]), + String.zeroBasedStringValue(CharData.NUM_VALUE[7]), + String.zeroBasedStringValue(CharData.NUM_VALUE[8]), + String.zeroBasedStringValue(CharData.NUM_VALUE[9]), + String.zeroBasedStringValue(CharData.NUM_VALUE[10]), + String.zeroBasedStringValue(CharData.NUM_VALUE[11]), + String.zeroBasedStringValue(CharData.NUM_VALUE[12]), + String.zeroBasedStringValue(CharData.NUM_VALUE[13]), + String.zeroBasedStringValue(CharData.NUM_VALUE[14]), + String.zeroBasedStringValue(CharData.NUM_VALUE[15]), + String.zeroBasedStringValue(CharData.NUM_VALUE[16])}; /** * Stores unicode uppercase attribute table. Exploit package visibility * of String.value to avoid copying the array. * @see CharData#UPPER - */ - private static final char[] upper = String.zeroBasedStringValue(CharData.UPPER); + */ + private static final char[][] upper = + new char[][]{ + String.zeroBasedStringValue(CharData.UPPER[0]), + String.zeroBasedStringValue(CharData.UPPER[1]), + String.zeroBasedStringValue(CharData.UPPER[2]), + String.zeroBasedStringValue(CharData.UPPER[3]), + String.zeroBasedStringValue(CharData.UPPER[4]), + String.zeroBasedStringValue(CharData.UPPER[5]), + String.zeroBasedStringValue(CharData.UPPER[6]), + String.zeroBasedStringValue(CharData.UPPER[7]), + String.zeroBasedStringValue(CharData.UPPER[8]), + String.zeroBasedStringValue(CharData.UPPER[9]), + String.zeroBasedStringValue(CharData.UPPER[10]), + String.zeroBasedStringValue(CharData.UPPER[11]), + String.zeroBasedStringValue(CharData.UPPER[12]), + String.zeroBasedStringValue(CharData.UPPER[13]), + String.zeroBasedStringValue(CharData.UPPER[14]), + String.zeroBasedStringValue(CharData.UPPER[15]), + String.zeroBasedStringValue(CharData.UPPER[16])}; /** * Stores unicode lowercase attribute table. Exploit package visibility * of String.value to avoid copying the array. * @see CharData#LOWER */ - private static final char[] lower = String.zeroBasedStringValue(CharData.LOWER); + private static final char[][] lower = + new char[][]{ + String.zeroBasedStringValue(CharData.LOWER[0]), + String.zeroBasedStringValue(CharData.LOWER[1]), + String.zeroBasedStringValue(CharData.LOWER[2]), + String.zeroBasedStringValue(CharData.LOWER[3]), + String.zeroBasedStringValue(CharData.LOWER[4]), + String.zeroBasedStringValue(CharData.LOWER[5]), + String.zeroBasedStringValue(CharData.LOWER[6]), + String.zeroBasedStringValue(CharData.LOWER[7]), + String.zeroBasedStringValue(CharData.LOWER[8]), + String.zeroBasedStringValue(CharData.LOWER[9]), + String.zeroBasedStringValue(CharData.LOWER[10]), + String.zeroBasedStringValue(CharData.LOWER[11]), + String.zeroBasedStringValue(CharData.LOWER[12]), + String.zeroBasedStringValue(CharData.LOWER[13]), + String.zeroBasedStringValue(CharData.LOWER[14]), + String.zeroBasedStringValue(CharData.LOWER[15]), + String.zeroBasedStringValue(CharData.LOWER[16])}; /** * Stores unicode direction attribute table. Exploit package visibility @@ -2166,14 +2539,32 @@ public final class Character implements Serializable, Comparable * @see CharData#DIRECTION */ // Package visible for use by String. - static final char[] direction = String.zeroBasedStringValue(CharData.DIRECTION); + static final char[][] direction = + new char[][]{ + String.zeroBasedStringValue(CharData.DIRECTION[0]), + String.zeroBasedStringValue(CharData.DIRECTION[1]), + String.zeroBasedStringValue(CharData.DIRECTION[2]), + String.zeroBasedStringValue(CharData.DIRECTION[3]), + String.zeroBasedStringValue(CharData.DIRECTION[4]), + String.zeroBasedStringValue(CharData.DIRECTION[5]), + String.zeroBasedStringValue(CharData.DIRECTION[6]), + String.zeroBasedStringValue(CharData.DIRECTION[7]), + String.zeroBasedStringValue(CharData.DIRECTION[8]), + String.zeroBasedStringValue(CharData.DIRECTION[9]), + String.zeroBasedStringValue(CharData.DIRECTION[10]), + String.zeroBasedStringValue(CharData.DIRECTION[11]), + String.zeroBasedStringValue(CharData.DIRECTION[12]), + String.zeroBasedStringValue(CharData.DIRECTION[13]), + String.zeroBasedStringValue(CharData.DIRECTION[14]), + String.zeroBasedStringValue(CharData.DIRECTION[15]), + String.zeroBasedStringValue(CharData.DIRECTION[16])}; /** * Stores unicode titlecase table. Exploit package visibility of * String.value to avoid copying the array. * @see CharData#TITLE */ - private static final char[] title = String.zeroBasedStringValue(CharData.TITLE); + private static final char[] title = String.zeroBasedStringValue(CharData.TITLE); /** * Mask for grabbing the type out of the contents of data. @@ -2200,7 +2591,7 @@ public final class Character implements Serializable, Comparable * 5 bits are the character type, the next 2 bits are flags, and the top * 9 bits are the offset into the attribute tables. * - * @param ch the character to look up + * @param codePoint the character to look up * @return the character's attribute offset and type * @see #TYPE_MASK * @see #NO_BREAK_MASK @@ -2209,10 +2600,11 @@ public final class Character implements Serializable, Comparable * @see CharData#SHIFT */ // Package visible for use in String. - static char readChar(char ch) + static char readCodePoint(int codePoint) { - // Perform 16-bit addition to find the correct entry in data. - return data[(char) (blocks[ch >> CharData.SHIFT] + ch)]; + int plane = codePoint >>> 16; + char offset = (char) (codePoint & 0xffff); + return data[plane][(char) (blocks[plane][offset >> CharData.SHIFT[plane]] + offset)]; } /** @@ -2285,7 +2677,8 @@ public final class Character implements Serializable, Comparable /** * Determines if a character is a Unicode lowercase letter. For example, - * 'a' is lowercase. + * 'a' is lowercase. Returns true if getType() returns + * LOWERCASE_LETTER. *
    * lowercase = [Ll] * @@ -2298,12 +2691,34 @@ public final class Character implements Serializable, Comparable */ public static boolean isLowerCase(char ch) { - return getType(ch) == LOWERCASE_LETTER; + return isLowerCase((int)ch); + } + + /** + * Determines if a character is a Unicode lowercase letter. For example, + * 'a' is lowercase. Returns true if getType() returns + * LOWERCASE_LETTER. + *
    + * lowercase = [Ll] + * + * @param codePoint character to test + * @return true if ch is a Unicode lowercase letter, else false + * @see #isUpperCase(char) + * @see #isTitleCase(char) + * @see #toLowerCase(char) + * @see #getType(char) + * + * @since 1.5 + */ + public static boolean isLowerCase(int codePoint) + { + return getType(codePoint) == LOWERCASE_LETTER; } /** * Determines if a character is a Unicode uppercase letter. For example, - * 'A' is uppercase. + * 'A' is uppercase. Returns true if getType() returns + * UPPERCASE_LETTER. *
    * uppercase = [Lu] * @@ -2316,12 +2731,34 @@ public final class Character implements Serializable, Comparable */ public static boolean isUpperCase(char ch) { - return getType(ch) == UPPERCASE_LETTER; + return isUpperCase((int)ch); + } + + /** + * Determines if a character is a Unicode uppercase letter. For example, + * 'A' is uppercase. Returns true if getType() returns + * UPPERCASE_LETTER. + *
    + * uppercase = [Lu] + * + * @param codePoint character to test + * @return true if ch is a Unicode uppercase letter, else false + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #toUpperCase(char) + * @see #getType(char) + * + * @since 1.5 + */ + public static boolean isUpperCase(int codePoint) + { + return getType(codePoint) == UPPERCASE_LETTER; } /** * Determines if a character is a Unicode titlecase letter. For example, * the character "Lj" (Latin capital L with small letter j) is titlecase. + * True if getType() returns TITLECASE_LETTER. *
    * titlecase = [Lt] * @@ -2334,12 +2771,35 @@ public final class Character implements Serializable, Comparable */ public static boolean isTitleCase(char ch) { - return getType(ch) == TITLECASE_LETTER; + return isTitleCase((int)ch); } + /** + * Determines if a character is a Unicode titlecase letter. For example, + * the character "Lj" (Latin capital L with small letter j) is titlecase. + * True if getType() returns TITLECASE_LETTER. + *
    + * titlecase = [Lt] + * + * @param codePoint character to test + * @return true if ch is a Unicode titlecase letter, else false + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toTitleCase(char) + * @see #getType(char) + * + * @since 1.5 + */ + public static boolean isTitleCase(int codePoint) + { + return getType(codePoint) == TITLECASE_LETTER; + } + + /** * Determines if a character is a Unicode decimal digit. For example, - * '0' is a digit. + * '0' is a digit. A character is a Unicode digit if + * getType() returns DECIMAL_DIGIT_NUMBER. *
    * Unicode decimal digit = [Nd] * @@ -2351,7 +2811,28 @@ public final class Character implements Serializable, Comparable */ public static boolean isDigit(char ch) { - return getType(ch) == DECIMAL_DIGIT_NUMBER; + return isDigit((int)ch); + } + + /** + * Determines if a character is a Unicode decimal digit. For example, + * '0' is a digit. A character is a Unicode digit if + * getType() returns DECIMAL_DIGIT_NUMBER. + *
    + * Unicode decimal digit = [Nd] + * + * @param codePoint character to test + * @return true if ch is a Unicode decimal digit, else false + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see #getType(char) + * + * @since 1.5 + */ + + public static boolean isDigit(int codePoint) + { + return getType(codePoint) == DECIMAL_DIGIT_NUMBER; } /** @@ -2371,12 +2852,37 @@ public final class Character implements Serializable, Comparable */ public static boolean isDefined(char ch) { - return getType(ch) != UNASSIGNED; + return isDefined((int)ch); + } + + /** + * Determines if a character is part of the Unicode Standard. This is an + * evolving standard, but covers every character in the data file. + *
    + * defined = not [Cn] + * + * @param codePoint character to test + * @return true if ch is a Unicode character, else false + * @see #isDigit(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUpperCase(char) + * + * @since 1.5 + */ + public static boolean isDefined(int codePoint) + { + return getType(codePoint) != UNASSIGNED; } /** * Determines if a character is a Unicode letter. Not all letters have case, * so this may return true when isLowerCase and isUpperCase return false. + * A character is a Unicode letter if getType() returns one of + * UPPERCASE_LETTER, LOWERCASE_LETTER, TITLECASE_LETTER, MODIFIER_LETTER, + * or OTHER_LETTER. *
    * letter = [Lu]|[Ll]|[Lt]|[Lm]|[Lo] * @@ -2394,54 +2900,306 @@ public final class Character implements Serializable, Comparable */ public static boolean isLetter(char ch) { - return ((1 << getType(ch)) - & ((1 << UPPERCASE_LETTER) - | (1 << LOWERCASE_LETTER) - | (1 << TITLECASE_LETTER) - | (1 << MODIFIER_LETTER) - | (1 << OTHER_LETTER))) != 0; + return isLetter((int)ch); } - + /** - * Determines if a character is a Unicode letter or a Unicode digit. This - * is the combination of isLetter and isDigit. + * Determines if a character is a Unicode letter. Not all letters have case, + * so this may return true when isLowerCase and isUpperCase return false. + * A character is a Unicode letter if getType() returns one of + * UPPERCASE_LETTER, LOWERCASE_LETTER, TITLECASE_LETTER, MODIFIER_LETTER, + * or OTHER_LETTER. *
    - * letter or digit = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nd] + * letter = [Lu]|[Ll]|[Lt]|[Lm]|[Lo] * - * @param ch character to test - * @return true if ch is a Unicode letter or a Unicode digit, else false + * @param codePoint character to test + * @return true if ch is a Unicode letter, else false * @see #isDigit(char) - * @see #isJavaIdentifierPart(char) + * @see #isJavaIdentifierStart(char) * @see #isJavaLetter(char) * @see #isJavaLetterOrDigit(char) - * @see #isLetter(char) - * @see #isUnicodeIdentifierPart(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUnicodeIdentifierStart(char) + * @see #isUpperCase(char) + * + * @since 1.5 */ - public static boolean isLetterOrDigit(char ch) + public static boolean isLetter(int codePoint) { - return ((1 << getType(ch)) - & ((1 << UPPERCASE_LETTER) - | (1 << LOWERCASE_LETTER) - | (1 << TITLECASE_LETTER) - | (1 << MODIFIER_LETTER) - | (1 << OTHER_LETTER) - | (1 << DECIMAL_DIGIT_NUMBER))) != 0; + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER))) != 0; } - /** - * Determines if a character can start a Java identifier. This is the - * combination of isLetter, any character where getType returns - * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation - * (like '_'). - * - * @param ch character to test - * @return true if ch can start a Java identifier, else false - * @deprecated Replaced by {@link #isJavaIdentifierStart(char)} - * @see #isJavaLetterOrDigit(char) - * @see #isJavaIdentifierStart(char) - * @see #isJavaIdentifierPart(char) - * @see #isLetter(char) - * @see #isLetterOrDigit(char) + * Returns the index into the given CharSequence that is offset + * codePointOffset code points from index. + * @param seq the CharSequence + * @param index the start position in the CharSequence + * @param codePointOffset the number of code points offset from the start + * position + * @return the index into the CharSequence that is codePointOffset code + * points offset from index + * + * @throws NullPointerException if seq is null + * @throws IndexOutOfBoundsException if index is negative or greater than the + * length of the sequence. + * @throws IndexOutOfBoundsException if codePointOffset is positive and the + * subsequence from index to the end of seq has fewer than codePointOffset + * code points + * @throws IndexOutOfBoundsException if codePointOffset is negative and the + * subsequence from the start of seq to index has fewer than + * (-codePointOffset) code points + * @since 1.5 + */ + public static int offsetByCodePoints(CharSequence seq, + int index, + int codePointOffset) + { + int len = seq.length(); + if (index < 0 || index > len) + throw new IndexOutOfBoundsException(); + + int numToGo = codePointOffset; + int offset = index; + int adjust = 1; + if (numToGo >= 0) + { + for (; numToGo > 0; offset++) + { + numToGo--; + if (Character.isHighSurrogate(seq.charAt(offset)) + && (offset + 1) < len + && Character.isLowSurrogate(seq.charAt(offset + 1))) + offset++; + } + return offset; + } + else + { + numToGo *= -1; + for (; numToGo > 0;) + { + numToGo--; + offset--; + if (Character.isLowSurrogate(seq.charAt(offset)) + && (offset - 1) >= 0 + && Character.isHighSurrogate(seq.charAt(offset - 1))) + offset--; + } + return offset; + } + } + + /** + * Returns the index into the given char subarray that is offset + * codePointOffset code points from index. + * @param a the char array + * @param start the start index of the subarray + * @param count the length of the subarray + * @param index the index to be offset + * @param codePointOffset the number of code points offset from index + * + * @return the index into the char array + * + * @throws NullPointerException if a is null + * @throws IndexOutOfBoundsException if start or count is negative or if + * start + count is greater than the length of the array + * @throws IndexOutOfBoundsException if index is less than start or larger + * than start + count + * @throws IndexOutOfBoundsException if codePointOffset is positive and the + * subarray from index to start + count - 1 has fewer than codePointOffset + * code points. + * @throws IndexOutOfBoundsException if codePointOffset is negative and the + * subarray from start to index - 1 has fewer than (-codePointOffset) code + * points + * + * @since 1.5 + */ + public static int offsetByCodePoints(char[] a, + int start, + int count, + int index, + int codePointOffset) + { + int len = a.length; + int end = start + count; + if (start < 0 || count < 0 || end > len || index < start || index > end) + throw new IndexOutOfBoundsException(); + + int numToGo = codePointOffset; + int offset = index; + int adjust = 1; + if (numToGo >= 0) + { + for (; numToGo > 0; offset++) + { + numToGo--; + if (Character.isHighSurrogate(a[offset]) + && (offset + 1) < len + && Character.isLowSurrogate(a[offset + 1])) + offset++; + } + return offset; + } + else + { + numToGo *= -1; + for (; numToGo > 0;) + { + numToGo--; + offset--; + if (Character.isLowSurrogate(a[offset]) + && (offset - 1) >= 0 + && Character.isHighSurrogate(a[offset - 1])) + offset--; + if (offset < start) + throw new IndexOutOfBoundsException(); + } + return offset; + } + + } + + /** + * Returns the number of Unicode code points in the specified range of the + * given CharSequence. The first char in the range is at position + * beginIndex and the last one is at position endIndex - 1. Paired + * surrogates (supplementary characters are represented by a pair of chars - + * one from the high surrogates and one from the low surrogates) + * count as just one code point. + * @param seq the CharSequence to inspect + * @param beginIndex the beginning of the range + * @param endIndex the end of the range + * @return the number of Unicode code points in the given range of the + * sequence + * @throws NullPointerException if seq is null + * @throws IndexOutOfBoundsException if beginIndex is negative, endIndex is + * larger than the length of seq, or if beginIndex is greater than endIndex. + * @since 1.5 + */ + public static int codePointCount(CharSequence seq, int beginIndex, + int endIndex) + { + int len = seq.length(); + if (beginIndex < 0 || endIndex > len || beginIndex > endIndex) + throw new IndexOutOfBoundsException(); + + int count = 0; + for (int i = beginIndex; i < endIndex; i++) + { + count++; + // If there is a pairing, count it only once. + if (isHighSurrogate(seq.charAt(i)) && (i + 1) < endIndex + && isLowSurrogate(seq.charAt(i + 1))) + i ++; + } + return count; + } + + /** + * Returns the number of Unicode code points in the specified range of the + * given char array. The first char in the range is at position + * offset and the length of the range is count. Paired surrogates + * (supplementary characters are represented by a pair of chars - + * one from the high surrogates and one from the low surrogates) + * count as just one code point. + * @param a the char array to inspect + * @param offset the beginning of the range + * @param count the length of the range + * @return the number of Unicode code points in the given range of the + * array + * @throws NullPointerException if a is null + * @throws IndexOutOfBoundsException if offset or count is negative or if + * offset + countendIndex is larger than the length of a. + * @since 1.5 + */ + public static int codePointCount(char[] a, int offset, + int count) + { + int len = a.length; + int end = offset + count; + if (offset < 0 || count < 0 || end > len) + throw new IndexOutOfBoundsException(); + + int counter = 0; + for (int i = offset; i < end; i++) + { + counter++; + // If there is a pairing, count it only once. + if (isHighSurrogate(a[i]) && (i + 1) < end + && isLowSurrogate(a[i + 1])) + i ++; + } + return counter; + } + + /** + * Determines if a character is a Unicode letter or a Unicode digit. This + * is the combination of isLetter and isDigit. + *
    + * letter or digit = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nd] + * + * @param ch character to test + * @return true if ch is a Unicode letter or a Unicode digit, else false + * @see #isDigit(char) + * @see #isJavaIdentifierPart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + */ + public static boolean isLetterOrDigit(char ch) + { + return isLetterOrDigit((int)ch); + } + + /** + * Determines if a character is a Unicode letter or a Unicode digit. This + * is the combination of isLetter and isDigit. + *
    + * letter or digit = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nd] + * + * @param codePoint character to test + * @return true if ch is a Unicode letter or a Unicode digit, else false + * @see #isDigit(char) + * @see #isJavaIdentifierPart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + * + * @since 1.5 + */ + public static boolean isLetterOrDigit(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER))) != 0; + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + * + * @param ch character to test + * @return true if ch can start a Java identifier, else false + * @deprecated Replaced by {@link #isJavaIdentifierStart(char)} + * @see #isJavaLetterOrDigit(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) * @see #isUnicodeIdentifierStart(char) */ public static boolean isJavaLetter(char ch) @@ -2489,7 +3247,27 @@ public final class Character implements Serializable, Comparable */ public static boolean isJavaIdentifierStart(char ch) { - return ((1 << getType(ch)) + return isJavaIdentifierStart((int)ch); + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + *
    + * Java identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc] + * + * @param codePoint character to test + * @return true if ch can start a Java identifier, else false + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.5 + */ + public static boolean isJavaIdentifierStart(int codePoint) + { + return ((1 << getType(codePoint)) & ((1 << UPPERCASE_LETTER) | (1 << LOWERCASE_LETTER) | (1 << TITLECASE_LETTER) @@ -2521,7 +3299,31 @@ public final class Character implements Serializable, Comparable */ public static boolean isJavaIdentifierPart(char ch) { - int category = getType(ch); + return isJavaIdentifierPart((int)ch); + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. + *
    + * Java identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc]|[Mn]|[Mc]|[Nd]|[Cf] + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param codePoint character to test + * @return true if ch can follow the first letter in a Java identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierStart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.5 + */ + public static boolean isJavaIdentifierPart(int codePoint) + { + int category = getType(codePoint); return ((1 << category) & ((1 << UPPERCASE_LETTER) | (1 << LOWERCASE_LETTER) @@ -2535,7 +3337,7 @@ public final class Character implements Serializable, Comparable | (1 << CURRENCY_SYMBOL) | (1 << CONNECTOR_PUNCTUATION) | (1 << FORMAT))) != 0 - || (category == CONTROL && isIdentifierIgnorable(ch)); + || (category == CONTROL && isIdentifierIgnorable(codePoint)); } /** @@ -2554,7 +3356,26 @@ public final class Character implements Serializable, Comparable */ public static boolean isUnicodeIdentifierStart(char ch) { - return ((1 << getType(ch)) + return isUnicodeIdentifierStart((int)ch); + } + + /** + * Determines if a character can start a Unicode identifier. Only + * letters can start a Unicode identifier, but this includes characters + * in LETTER_NUMBER. + *
    + * Unicode identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl] + * + * @param codePoint character to test + * @return true if ch can start a Unicode identifier, else false + * @see #isJavaIdentifierStart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.5 + */ + public static boolean isUnicodeIdentifierStart(int codePoint) + { + return ((1 << getType(codePoint)) & ((1 << UPPERCASE_LETTER) | (1 << LOWERCASE_LETTER) | (1 << TITLECASE_LETTER) @@ -2583,7 +3404,30 @@ public final class Character implements Serializable, Comparable */ public static boolean isUnicodeIdentifierPart(char ch) { - int category = getType(ch); + return isUnicodeIdentifierPart((int)ch); + } + + /** + * Determines if a character can follow the first letter in + * a Unicode identifier. This includes letters, connecting punctuation, + * digits, numeric letters, combining marks, non-spacing marks, and + * isIdentifierIgnorable. + *
    + * Unicode identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Mn]|[Mc]|[Nd]|[Pc]|[Cf]| + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param codePoint character to test + * @return true if ch can follow the first letter in a Unicode identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.5 + */ + public static boolean isUnicodeIdentifierPart(int codePoint) + { + int category = getType(codePoint); return ((1 << category) & ((1 << UPPERCASE_LETTER) | (1 << LOWERCASE_LETTER) @@ -2596,7 +3440,7 @@ public final class Character implements Serializable, Comparable | (1 << LETTER_NUMBER) | (1 << CONNECTOR_PUNCTUATION) | (1 << FORMAT))) != 0 - || (category == CONTROL && isIdentifierIgnorable(ch)); + || (category == CONTROL && isIdentifierIgnorable(codePoint)); } /** @@ -2617,9 +3461,33 @@ public final class Character implements Serializable, Comparable */ public static boolean isIdentifierIgnorable(char ch) { - return (ch <= '\u009F' && (ch < '\t' || ch >= '\u007F' - || (ch <= '\u001B' && ch >= '\u000E'))) - || getType(ch) == FORMAT; + return isIdentifierIgnorable((int)ch); + } + + /** + * Determines if a character is ignorable in a Unicode identifier. This + * includes the non-whitespace ISO control characters ('\u0000' + * through '\u0008', '\u000E' through + * '\u001B', and '\u007F' through + * '\u009F'), and FORMAT characters. + *
    + * Unicode identifier ignorable = [Cf]|U+0000-U+0008|U+000E-U+001B + * |U+007F-U+009F + * + * @param codePoint character to test + * @return true if ch is ignorable in a Unicode or Java identifier + * @see #isJavaIdentifierPart(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.5 + */ + public static boolean isIdentifierIgnorable(int codePoint) + { + if ((codePoint >= 0 && codePoint <= 0x0008) + || (codePoint >= 0x000E && codePoint <= 0x001B) + || (codePoint >= 0x007F && codePoint <= 0x009F) + || getType(codePoint) == FORMAT) + return true; + return false; } /** @@ -2637,8 +3505,37 @@ public final class Character implements Serializable, Comparable */ public static char toLowerCase(char ch) { - // Signedness doesn't matter, as result is cast back to char. - return (char) (ch + lower[readChar(ch) >> 7]); + return (char) (lower[0][readCodePoint((int)ch) >>> 7] + ch); + } + + /** + * Converts a Unicode character into its lowercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isLowerCase(toLowerCase(ch)) does not always return true. + * + * @param codePoint character to convert to lowercase + * @return lowercase mapping of ch, or ch if lowercase mapping does + * not exist + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toTitleCase(char) + * @see #toUpperCase(char) + * + * @since 1.5 + */ + public static int toLowerCase(int codePoint) + { + // If the code point is unassigned or in one of the private use areas + // then we delegate the call to the appropriate private static inner class. + int plane = codePoint >>> 16; + if (plane > 2 && plane < 14) + return UnassignedCharacters.toLowerCase(codePoint); + if (plane > 14) + return PrivateUseCharacters.toLowerCase(codePoint); + + // The short value stored in lower[plane] is the signed difference between + // codePoint and its lowercase conversion. + return ((short)lower[plane][readCodePoint(codePoint) >>> 7]) + codePoint; } /** @@ -2656,8 +3553,37 @@ public final class Character implements Serializable, Comparable */ public static char toUpperCase(char ch) { - // Signedness doesn't matter, as result is cast back to char. - return (char) (ch + upper[readChar(ch) >> 7]); + return (char) (upper[0][readCodePoint((int)ch) >>> 7] + ch); + } + + /** + * Converts a Unicode character into its uppercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isUpperCase(toUpperCase(ch)) does not always return true. + * + * @param codePoint character to convert to uppercase + * @return uppercase mapping of ch, or ch if uppercase mapping does + * not exist + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toLowerCase(char) + * @see #toTitleCase(char) + * + * @since 1.5 + */ + public static int toUpperCase(int codePoint) + { + // If the code point is unassigned or in one of the private use areas + // then we delegate the call to the appropriate private static inner class. + int plane = codePoint >>> 16; + if (plane > 2 && plane < 14) + return UnassignedCharacters.toUpperCase(codePoint); + if (plane > 14) + return PrivateUseCharacters.toUpperCase(codePoint); + + // The short value stored in upper[plane] is the signed difference between + // codePoint and its uppercase conversion. + return ((short)upper[plane][readCodePoint(codePoint) >>> 7]) + codePoint; } /** @@ -2681,6 +3607,30 @@ public final class Character implements Serializable, Comparable return toUpperCase(ch); } + /** + * Converts a Unicode character into its titlecase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isTitleCase(toTitleCase(ch)) does not always return true. + * + * @param codePoint character to convert to titlecase + * @return titlecase mapping of ch, or ch if titlecase mapping does + * not exist + * @see #isTitleCase(char) + * @see #toLowerCase(char) + * @see #toUpperCase(char) + * + * @since 1.5 + */ + public static int toTitleCase(int codePoint) + { + // As of Unicode 4.0.0 no characters outside of plane 0 have + // titlecase mappings that are different from their uppercase + // mapping. + if (codePoint < 0x10000) + return (int) toTitleCase((char)codePoint); + return toUpperCase(codePoint); + } + /** * Converts a character into a digit of the specified radix. If the radix * exceeds MIN_RADIX or MAX_RADIX, or if the result of getNumericValue(ch) @@ -2703,19 +3653,67 @@ public final class Character implements Serializable, Comparable { if (radix < MIN_RADIX || radix > MAX_RADIX) return -1; - char attr = readChar(ch); + char attr = readCodePoint((int)ch); if (((1 << (attr & TYPE_MASK)) & ((1 << UPPERCASE_LETTER) | (1 << LOWERCASE_LETTER) | (1 << DECIMAL_DIGIT_NUMBER))) != 0) { // Signedness doesn't matter; 0xffff vs. -1 are both rejected. - int digit = numValue[attr >> 7]; + int digit = numValue[0][attr >> 7]; return (digit < radix) ? digit : -1; } return -1; } + /** + * Converts a character into a digit of the specified radix. If the radix + * exceeds MIN_RADIX or MAX_RADIX, or if the result of getNumericValue(ch) + * exceeds the radix, or if ch is not a decimal digit or in the case + * insensitive set of 'a'-'z', the result is -1. + *
    + * character argument boundary = [Nd]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param codePoint character to convert into a digit + * @param radix radix in which ch is a digit + * @return digit which ch represents in radix, or -1 not a valid digit + * @see #MIN_RADIX + * @see #MAX_RADIX + * @see #forDigit(int, int) + * @see #isDigit(char) + * @see #getNumericValue(char) + */ + public static int digit(int codePoint, int radix) + { + if (radix < MIN_RADIX || radix > MAX_RADIX) + return -1; + + // If the code point is unassigned or in one of the private use areas + // then we delegate the call to the appropriate private static inner class. + int plane = codePoint >>> 16; + if (plane > 2 && plane < 14) + return UnassignedCharacters.digit(codePoint, radix); + if (plane > 14) + return PrivateUseCharacters.digit(codePoint, radix); + char attr = readCodePoint(codePoint); + if (((1 << (attr & TYPE_MASK)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER))) != 0) + { + // Signedness doesn't matter; 0xffff vs. -1 are both rejected. + int digit = numValue[plane][attr >> 7]; + + // If digit is less than or equal to -3 then the numerical value was + // too large to fit into numValue and is stored in CharData.LARGENUMS. + if (digit <= -3) + digit = CharData.LARGENUMS[-digit - 3]; + return (digit < radix) ? digit : -1; + } + return -1; + } + /** * Returns the Unicode numeric value property of a character. For example, * '\\u216C' (the Roman numeral fifty) returns 50. @@ -2746,7 +3744,53 @@ public final class Character implements Serializable, Comparable public static int getNumericValue(char ch) { // Treat numValue as signed. - return (short) numValue[readChar(ch) >> 7]; + return (short) numValue[0][readCodePoint((int)ch) >> 7]; + } + + /** + * Returns the Unicode numeric value property of a character. For example, + * '\\u216C' (the Roman numeral fifty) returns 50. + * + *

    This method also returns values for the letters A through Z, (not + * specified by Unicode), in these ranges: '\u0041' + * through '\u005A' (uppercase); '\u0061' + * through '\u007A' (lowercase); and '\uFF21' + * through '\uFF3A', '\uFF41' through + * '\uFF5A' (full width variants). + * + *

    If the character lacks a numeric value property, -1 is returned. + * If the character has a numeric value property which is not representable + * as a nonnegative integer, such as a fraction, -2 is returned. + * + * character argument boundary = [Nd]|[Nl]|[No]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param codePoint character from which the numeric value property will + * be retrieved + * @return the numeric value property of ch, or -1 if it does not exist, or + * -2 if it is not representable as a nonnegative integer + * @see #forDigit(int, int) + * @see #digit(char, int) + * @see #isDigit(char) + * @since 1.5 + */ + public static int getNumericValue(int codePoint) + { + // If the code point is unassigned or in one of the private use areas + // then we delegate the call to the appropriate private static inner class. + int plane = codePoint >>> 16; + if (plane > 2 && plane < 14) + return UnassignedCharacters.getNumericValue(codePoint); + if (plane > 14) + return PrivateUseCharacters.getNumericValue(codePoint); + + // If the value N found in numValue[plane] is less than or equal to -3 + // then the numeric value was too big to fit into 16 bits and is + // stored in CharData.LARGENUMS at offset (-N - 3). + short num = (short)numValue[plane][readCodePoint(codePoint) >> 7]; + if (num <= -3) + return CharData.LARGENUMS[-num - 3]; + return num; } /** @@ -2786,7 +3830,23 @@ public final class Character implements Serializable, Comparable */ public static boolean isSpaceChar(char ch) { - return ((1 << getType(ch)) + return isSpaceChar((int)ch); + } + + /** + * Determines if a character is a Unicode space character. This includes + * SPACE_SEPARATOR, LINE_SEPARATOR, and PARAGRAPH_SEPARATOR. + *
    + * Unicode space = [Zs]|[Zp]|[Zl] + * + * @param codePoint character to test + * @return true if ch is a Unicode space, else false + * @see #isWhitespace(char) + * @since 1.5 + */ + public static boolean isSpaceChar(int codePoint) + { + return ((1 << getType(codePoint)) & ((1 << SPACE_SEPARATOR) | (1 << LINE_SEPARATOR) | (1 << PARAGRAPH_SEPARATOR))) != 0; @@ -2811,13 +3871,41 @@ public final class Character implements Serializable, Comparable */ public static boolean isWhitespace(char ch) { - int attr = readChar(ch); + return isWhitespace((int) ch); + } + + /** + * Determines if a character is Java whitespace. This includes Unicode + * space characters (SPACE_SEPARATOR, LINE_SEPARATOR, and + * PARAGRAPH_SEPARATOR) except the non-breaking spaces + * ('\u00A0', '\u2007', and '\u202F'); + * and these characters: '\u0009', '\u000A', + * '\u000B', '\u000C', '\u000D', + * '\u001C', '\u001D', '\u001E', + * and '\u001F'. + *
    + * Java whitespace = ([Zs] not Nb)|[Zl]|[Zp]|U+0009-U+000D|U+001C-U+001F + * + * @param codePoint character to test + * @return true if ch is Java whitespace, else false + * @see #isSpaceChar(char) + * @since 1.5 + */ + public static boolean isWhitespace(int codePoint) + { + int plane = codePoint >>> 16; + if (plane > 2 && plane < 14) + return UnassignedCharacters.isWhiteSpace(codePoint); + if (plane > 14) + return PrivateUseCharacters.isWhiteSpace(codePoint); + + int attr = readCodePoint(codePoint); return ((((1 << (attr & TYPE_MASK)) & ((1 << SPACE_SEPARATOR) | (1 << LINE_SEPARATOR) | (1 << PARAGRAPH_SEPARATOR))) != 0) && (attr & NO_BREAK_MASK) == 0) - || (ch <= '\u001F' && ((1 << ch) + || (codePoint <= '\u001F' && ((1 << codePoint) & ((1 << '\t') | (1 << '\n') | (1 << '\u000B') @@ -2842,7 +3930,24 @@ public final class Character implements Serializable, Comparable */ public static boolean isISOControl(char ch) { - return getType(ch) == CONTROL; + return isISOControl((int)ch); + } + + /** + * Determines if the character is an ISO Control character. This is true + * if the code point is in the range [0, 0x001F] or if it is in the range + * [0x007F, 0x009F]. + * @param codePoint the character to check + * @return true if the character is in one of the above ranges + * + * @since 1.5 + */ + public static boolean isISOControl(int codePoint) + { + if ((codePoint >= 0 && codePoint <= 0x001F) + || (codePoint >= 0x007F && codePoint <= 0x009F)) + return true; + return false; } /** @@ -2884,7 +3989,58 @@ public final class Character implements Serializable, Comparable */ public static int getType(char ch) { - return readChar(ch) & TYPE_MASK; + return getType((int)ch); + } + + /** + * Returns the Unicode general category property of a character. + * + * @param codePoint character from which the general category property will + * be retrieved + * @return the character category property of ch as an integer + * @see #UNASSIGNED + * @see #UPPERCASE_LETTER + * @see #LOWERCASE_LETTER + * @see #TITLECASE_LETTER + * @see #MODIFIER_LETTER + * @see #OTHER_LETTER + * @see #NON_SPACING_MARK + * @see #ENCLOSING_MARK + * @see #COMBINING_SPACING_MARK + * @see #DECIMAL_DIGIT_NUMBER + * @see #LETTER_NUMBER + * @see #OTHER_NUMBER + * @see #SPACE_SEPARATOR + * @see #LINE_SEPARATOR + * @see #PARAGRAPH_SEPARATOR + * @see #CONTROL + * @see #FORMAT + * @see #PRIVATE_USE + * @see #SURROGATE + * @see #DASH_PUNCTUATION + * @see #START_PUNCTUATION + * @see #END_PUNCTUATION + * @see #CONNECTOR_PUNCTUATION + * @see #OTHER_PUNCTUATION + * @see #MATH_SYMBOL + * @see #CURRENCY_SYMBOL + * @see #MODIFIER_SYMBOL + * @see #INITIAL_QUOTE_PUNCTUATION + * @see #FINAL_QUOTE_PUNCTUATION + * + * @since 1.5 + */ + public static int getType(int codePoint) + { + // If the codePoint is unassigned or in one of the private use areas + // then we delegate the call to the appropriate private static inner class. + int plane = codePoint >>> 16; + if (plane > 2 && plane < 14) + return UnassignedCharacters.getType(codePoint); + if (plane > 14) + return PrivateUseCharacters.getType(codePoint); + + return readCodePoint(codePoint) & TYPE_MASK; } /** @@ -2941,9 +4097,52 @@ public final class Character implements Serializable, Comparable public static byte getDirectionality(char ch) { // The result will correctly be signed. - return (byte) (direction[readChar(ch) >> 7] >> 2); + return getDirectionality((int)ch); } + + /** + * Returns the Unicode directionality property of the character. This + * is used in the visual ordering of text. + * + * @param codePoint the character to look up + * @return the directionality constant, or DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_LEFT_TO_RIGHT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC + * @see #DIRECTIONALITY_EUROPEAN_NUMBER + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR + * @see #DIRECTIONALITY_ARABIC_NUMBER + * @see #DIRECTIONALITY_COMMON_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_NONSPACING_MARK + * @see #DIRECTIONALITY_BOUNDARY_NEUTRAL + * @see #DIRECTIONALITY_PARAGRAPH_SEPARATOR + * @see #DIRECTIONALITY_SEGMENT_SEPARATOR + * @see #DIRECTIONALITY_WHITESPACE + * @see #DIRECTIONALITY_OTHER_NEUTRALS + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE + * @see #DIRECTIONALITY_POP_DIRECTIONAL_FORMAT + * @since 1.5 + */ + public static byte getDirectionality(int codePoint) + { + // If the code point is unassigned or in one of the private use areas + // then we delegate the call to the appropriate private static inner class. + int plane = codePoint >>> 16; + if (plane > 2 && plane < 14) + return UnassignedCharacters.getDirectionality(codePoint); + if (plane > 14) + return PrivateUseCharacters.getDirectionality(codePoint); + + // The result will correctly be signed. + return (byte) (direction[plane][readCodePoint(codePoint) >> 7] >> 2); + } + /** * Determines whether the character is mirrored according to Unicode. For * example, \u0028 (LEFT PARENTHESIS) appears as '(' in @@ -2955,7 +4154,29 @@ public final class Character implements Serializable, Comparable */ public static boolean isMirrored(char ch) { - return (readChar(ch) & MIRROR_MASK) != 0; + return (readCodePoint((int)ch) & MIRROR_MASK) != 0; + } + + /** + * Determines whether the character is mirrored according to Unicode. For + * example, \u0028 (LEFT PARENTHESIS) appears as '(' in + * left-to-right text, but ')' in right-to-left text. + * + * @param codePoint the character to look up + * @return true if the character is mirrored + * @since 1.5 + */ + public static boolean isMirrored(int codePoint) + { + // If the code point is unassigned or part of one of the private use areas + // then we delegate the call to the appropriate private static inner class. + int plane = codePoint >>> 16; + if (plane > 2 && plane < 14) + return UnassignedCharacters.isMirrored(codePoint); + if (plane > 14) + return PrivateUseCharacters.isMirrored(codePoint); + + return (readCodePoint(codePoint) & MIRROR_MASK) != 0; } /** @@ -2980,6 +4201,7 @@ public final class Character implements Serializable, Comparable * * @param val the value to wrap * @return the Character + * * @since 1.5 */ public static Character valueOf(char val) @@ -3018,6 +4240,9 @@ public final class Character implements Serializable, Comparable */ public static char[] toChars(int codePoint) { + if (!isValidCodePoint(codePoint)) + throw new IllegalArgumentException("Illegal Unicode code point : " + + codePoint); char[] result = new char[charCount(codePoint)]; int ignore = toChars(codePoint, result, 0); return result; @@ -3235,7 +4460,7 @@ public final class Character implements Serializable, Comparable */ public static int codePointAt(char[] chars, int index, int limit) { - if (index < 0 || index >= limit || limit < 0 || limit >= chars.length) + if (index < 0 || index >= limit || limit < 0 || limit > chars.length) throw new IndexOutOfBoundsException(); char high = chars[index]; if (! isHighSurrogate(high) || ++index >= limit) diff --git a/java/lang/ClassNotFoundException.java b/java/lang/ClassNotFoundException.java index 6b6ae949d..142bc5d03 100644 --- a/java/lang/ClassNotFoundException.java +++ b/java/lang/ClassNotFoundException.java @@ -70,7 +70,7 @@ public class ClassNotFoundException extends Exception */ public ClassNotFoundException() { - this(null, null); + this(null); } /** @@ -81,7 +81,8 @@ public class ClassNotFoundException extends Exception */ public ClassNotFoundException(String s) { - this(s, null); + super(s); + ex = null; } /** diff --git a/java/lang/Math.java b/java/lang/Math.java index 08081e252..d7c8aa1c4 100644 --- a/java/lang/Math.java +++ b/java/lang/Math.java @@ -1,5 +1,5 @@ -/* java.lang.Math -- common mathematical functions, native allowed - Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. +/* java.lang.Math -- common mathematical functions, native allowed (VMMath) + Copyright (C) 1998, 2001, 2002, 2003, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -52,25 +52,33 @@ import java.util.Random; * @author Paul Fisher * @author John Keiser * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) * @since 1.0 */ public final class Math { - /** - * Math is non-instantiable - */ - private Math() - { - } + // FIXME - This is here because we need to load the "javalang" system + // library somewhere late in the bootstrap cycle. We cannot do this + // from VMSystem or VMRuntime since those are used to actually load + // the library. This is mainly here because historically Math was + // late enough in the bootstrap cycle to start using System after it + // was initialized (called from the java.util classes). static { if (Configuration.INIT_LOAD_LIBRARY) { - System.loadLibrary("javalang"); + System.loadLibrary("javalang"); } } + /** + * Math is non-instantiable + */ + private Math() + { + } + /** * A random number generator, initialized on first use. */ @@ -298,7 +306,10 @@ public final class Math * @param a the angle (in radians) * @return sin(a) */ - public static native double sin(double a); + public static double sin(double a) + { + return VMMath.sin(a); + } /** * The trigonometric function cos. The cosine of NaN or infinity is @@ -307,7 +318,10 @@ public final class Math * @param a the angle (in radians) * @return cos(a) */ - public static native double cos(double a); + public static double cos(double a) + { + return VMMath.cos(a); + } /** * The trigonometric function tan. The tangent of NaN or infinity @@ -317,7 +331,10 @@ public final class Math * @param a the angle (in radians) * @return tan(a) */ - public static native double tan(double a); + public static double tan(double a) + { + return VMMath.tan(a); + } /** * The trigonometric function arcsin. The range of angles returned @@ -328,7 +345,10 @@ public final class Math * @param a the sin to turn back into an angle * @return arcsin(a) */ - public static native double asin(double a); + public static double asin(double a) + { + return VMMath.asin(a); + } /** * The trigonometric function arccos. The range of angles returned @@ -339,7 +359,10 @@ public final class Math * @param a the cos to turn back into an angle * @return arccos(a) */ - public static native double acos(double a); + public static double acos(double a) + { + return VMMath.acos(a); + } /** * The trigonometric function arcsin. The range of angles returned @@ -351,7 +374,10 @@ public final class Math * @return arcsin(a) * @see #atan2(double, double) */ - public static native double atan(double a); + public static double atan(double a) + { + return VMMath.atan(a); + } /** * A special version of the trigonometric function arctan, for @@ -400,7 +426,10 @@ public final class Math * @return theta in the conversion of (x, y) to (r, theta) * @see #atan(double) */ - public static native double atan2(double y, double x); + public static double atan2(double y, double x) + { + return VMMath.atan2(y,x); + } /** * Take ea. The opposite of log(). If the @@ -414,7 +443,10 @@ public final class Math * @see #log(double) * @see #pow(double, double) */ - public static native double exp(double a); + public static double exp(double a) + { + return VMMath.exp(a); + } /** * Take ln(a) (the natural log). The opposite of exp(). If the @@ -430,7 +462,10 @@ public final class Math * @return the natural log of a * @see #exp(double) */ - public static native double log(double a); + public static double log(double a) + { + return VMMath.log(a); + } /** * Take a square root. If the argument is NaN or negative, the result is @@ -438,13 +473,18 @@ public final class Math * infinity; and if the result is either zero, the result is the same. * This is accurate within the limits of doubles. * - *

    For other roots, use pow(a, 1 / rootNumber). + *

    For a cube root, use cbrt. For other roots, use + * pow(a, 1 / rootNumber).

    * * @param a the numeric argument * @return the square root of the argument + * @see #cbrt(double) * @see #pow(double, double) */ - public static native double sqrt(double a); + public static double sqrt(double a) + { + return VMMath.sqrt(a); + } /** * Raise a number to a power. Special cases:
      @@ -514,7 +554,10 @@ public final class Math * @param b the power to raise it to * @return ab */ - public static native double pow(double a, double b); + public static double pow(double a, double b) + { + return VMMath.pow(a,b); + } /** * Get the IEEE 754 floating point remainder on two numbers. This is the @@ -530,7 +573,10 @@ public final class Math * @return the IEEE 754-defined floating point remainder of x/y * @see #rint(double) */ - public static native double IEEEremainder(double x, double y); + public static double IEEEremainder(double x, double y) + { + return VMMath.IEEEremainder(x,y); + } /** * Take the nearest integer that is that is greater than or equal to the @@ -541,7 +587,10 @@ public final class Math * @param a the value to act upon * @return the nearest integer >= a */ - public static native double ceil(double a); + public static double ceil(double a) + { + return VMMath.ceil(a); + } /** * Take the nearest integer that is that is less than or equal to the @@ -551,7 +600,10 @@ public final class Math * @param a the value to act upon * @return the nearest integer <= a */ - public static native double floor(double a); + public static double floor(double a) + { + return VMMath.floor(a); + } /** * Take the nearest integer to the argument. If it is exactly between @@ -561,7 +613,10 @@ public final class Math * @param a the value to act upon * @return the nearest integer to a */ - public static native double rint(double a); + public static double rint(double a) + { + return VMMath.rint(a); + } /** * Take the nearest integer to the argument. This is equivalent to @@ -647,4 +702,250 @@ public final class Math { return (rads * 180) / PI; } + + /** + *

      + * Take a cube root. If the argument is NaN, an infinity or + * zero, then the original value is returned. The returned result is + * within 1 ulp of the exact result. For a finite value, x, + * the cube root of -x is equal to the negation of the cube root + * of x. + *

      + *

      + * For a square root, use sqrt. For other roots, use + * pow(a, 1 / rootNumber). + *

      + * + * @param a the numeric argument + * @return the cube root of the argument + * @see #sqrt(double) + * @see #pow(double, double) + * @since 1.5 + */ + public static double cbrt(double a) + { + return VMMath.cbrt(a); + } + + /** + *

      + * Returns the hyperbolic cosine of the given value. For a value, + * x, the hyperbolic cosine is (ex + + * e-x)/2 + * with e being Euler's number. The returned + * result is within 2.5 ulps of the exact result. + *

      + *

      + * If the supplied value is NaN, then the original value is + * returned. For either infinity, positive infinity is returned. + * The hyperbolic cosine of zero is 1.0. + *

      + * + * @param a the numeric argument + * @return the hyperbolic cosine of a. + * @since 1.5 + */ + public static double cosh(double a) + { + return VMMath.cosh(a); + } + + /** + *

      + * Returns ea - 1. For values close to 0, the + * result of expm1(a) + 1 tend to be much closer to the + * exact result than simply exp(x). The result is within + * 1 ulp of the exact result, and results are semi-monotonic. For finite + * inputs, the returned value is greater than or equal to -1.0. Once + * a result enters within half a ulp of this limit, the limit is returned. + *

      + *

      + * For NaN, positive infinity and zero, the original value + * is returned. Negative infinity returns a result of -1.0 (the limit). + *

      + * + * @param a the numeric argument + * @return ea - 1 + * @since 1.5 + */ + public static double expm1(double a) + { + return VMMath.expm1(a); + } + + /** + *

      + * Returns the hypotenuse, a2 + b2, + * without intermediate overflow or underflow. The returned result is + * within 1 ulp of the exact result. If one parameter is held constant, + * then the result in the other parameter is semi-monotonic. + *

      + *

      + * If either of the arguments is an infinity, then the returned result + * is positive infinity. Otherwise, if either argument is NaN, + * then NaN is returned. + *

      + * + * @param a the first parameter. + * @param b the second parameter. + * @return the hypotenuse matching the supplied parameters. + * @since 1.5 + */ + public static double hypot(double a, double b) + { + return VMMath.hypot(a,b); + } + + /** + *

      + * Returns the base 10 logarithm of the supplied value. The returned + * result is within 1 ulp of the exact result, and the results are + * semi-monotonic. + *

      + *

      + * Arguments of either NaN or less than zero return + * NaN. An argument of positive infinity returns positive + * infinity. Negative infinity is returned if either positive or negative + * zero is supplied. Where the argument is the result of + * 10n, then n is returned. + *

      + * + * @param a the numeric argument. + * @return the base 10 logarithm of a. + * @since 1.5 + */ + public static double log10(double a) + { + return VMMath.log10(a); + } + + /** + *

      + * Returns the natural logarithm resulting from the sum of the argument, + * a and 1. For values close to 0, the + * result of log1p(a) tend to be much closer to the + * exact result than simply log(1.0+a). The returned + * result is within 1 ulp of the exact result, and the results are + * semi-monotonic. + *

      + *

      + * Arguments of either NaN or less than -1 return + * NaN. An argument of positive infinity or zero + * returns the original argument. Negative infinity is returned from an + * argument of -1. + *

      + * + * @param a the numeric argument. + * @return the natural logarithm of a + 1. + * @since 1.5 + */ + public static double log1p(double a) + { + return VMMath.log1p(a); + } + + /** + *

      + * Returns the sign of the argument as follows: + *

      + *
        + *
      • If a is greater than zero, the result is 1.0.
      • + *
      • If a is less than zero, the result is -1.0.
      • + *
      • If a is NaN, the result is NaN. + *
      • If a is positive or negative zero, the result is the + * same.
      • + *
      + * + * @param a the numeric argument. + * @return the sign of the argument. + * @since 1.5. + */ + public static double signum(double a) + { + if (Double.isNaN(a)) + return Double.NaN; + if (a > 0) + return 1.0; + if (a < 0) + return -1.0; + return a; + } + + /** + *

      + * Returns the sign of the argument as follows: + *

      + *
        + *
      • If a is greater than zero, the result is 1.0f.
      • + *
      • If a is less than zero, the result is -1.0f.
      • + *
      • If a is NaN, the result is NaN. + *
      • If a is positive or negative zero, the result is the + * same.
      • + *
      + * + * @param a the numeric argument. + * @return the sign of the argument. + * @since 1.5. + */ + public static float signum(float a) + { + if (Float.isNaN(a)) + return Float.NaN; + if (a > 0) + return 1.0f; + if (a < 0) + return -1.0f; + return a; + } + + /** + *

      + * Returns the hyperbolic sine of the given value. For a value, + * x, the hyperbolic sine is (ex - + * e-x)/2 + * with e being Euler's number. The returned + * result is within 2.5 ulps of the exact result. + *

      + *

      + * If the supplied value is NaN, an infinity or a zero, then the + * original value is returned. + *

      + * + * @param a the numeric argument + * @return the hyperbolic sine of a. + * @since 1.5 + */ + public static double sinh(double a) + { + return VMMath.sinh(a); + } + + /** + *

      + * Returns the hyperbolic tangent of the given value. For a value, + * x, the hyperbolic tangent is (ex - + * e-x)/(ex + e-x) + * (i.e. sinh(a)/cosh(a)) + * with e being Euler's number. The returned + * result is within 2.5 ulps of the exact result. The absolute value + * of the exact result is always less than 1. Computed results are thus + * less than or equal to 1 for finite arguments, with results within + * half a ulp of either positive or negative 1 returning the appropriate + * limit value (i.e. as if the argument was an infinity). + *

      + *

      + * If the supplied value is NaN or zero, then the original + * value is returned. Positive infinity returns +1.0 and negative infinity + * returns -1.0. + *

      + * + * @param a the numeric argument + * @return the hyperbolic tangent of a. + * @since 1.5 + */ + public static double tanh(double a) + { + return VMMath.tanh(a); + } + } diff --git a/java/lang/String.java b/java/lang/String.java index c3c92a178..7a014d431 100644 --- a/java/lang/String.java +++ b/java/lang/String.java @@ -558,6 +558,49 @@ public final class String this.count = count; } + /** + * Creates a new String containing the characters represented in the + * given subarray of Unicode code points. + * @param codePoints the entire array of code points + * @param offset the start of the subarray + * @param count the length of the subarray + * + * @throws IllegalArgumentException if an invalid code point is found + * in the codePoints array + * @throws IndexOutOfBoundsException if offset is negative or offset + count + * is greater than the length of the array. + */ + public String(int[] codePoints, int offset, int count) + { + // FIXME: This implementation appears to give correct internal + // representation of the String because: + // - length() is correct + // - getting a char[] from toCharArray() and testing + // Character.codePointAt() on all the characters in that array gives + // the appropriate results + // however printing the String gives incorrect results. This may be + // due to printing method errors (such as incorrectly looping through + // the String one char at a time rather than one "character" at a time. + + if (offset < 0) + throw new IndexOutOfBoundsException(); + int end = offset + count; + int pos = 0; + // This creates a char array that is long enough for all of the code + // points to represent supplementary characters. This is more than likely + // a waste of storage, so we use it only temporarily and then copy the + // used portion into the value array. + char[] temp = new char[2 * codePoints.length]; + for (int i = offset; i < end; i++) + { + pos += Character.toChars(codePoints[i], temp, pos); + } + this.count = pos; + this.value = new char[pos]; + System.arraycopy(temp, 0, value, 0, pos); + this.offset = 0; + } + /** * Returns the number of characters contained in this String. * @@ -1824,7 +1867,7 @@ public final class String */ private static int upperCaseExpansion(char ch) { - return Character.direction[Character.readChar(ch) >> 7] & 3; + return Character.direction[0][Character.readCodePoint((int)ch) >> 7] & 3; } /** @@ -1920,4 +1963,29 @@ public final class String } return result.toString(); } + + /** + * Return the index into this String that is offset from the given index by + * codePointOffset code points. + * @param index the index at which to start + * @param codePointOffset the number of code points to offset + * @return the index into this String that is codePointOffset + * code points offset from index. + * + * @throws IndexOutOfBoundsException if index is negative or larger than the + * length of this string. + * @throws IndexOutOfBoundsException if codePointOffset is positive and the + * substring starting with index has fewer than codePointOffset code points. + * @throws IndexOutOfBoundsException if codePointOffset is negative and the + * substring ending with index has fewer than (-codePointOffset) code points. + * @since 1.5 + */ + public int offsetByCodePoints(int index, int codePointOffset) + { + if (index < 0 || index > count) + throw new IndexOutOfBoundsException(); + + return Character.offsetByCodePoints(value, offset, count, offset + index, + codePointOffset); + } } diff --git a/java/lang/System.java b/java/lang/System.java index d6c0609ac..1fb59794f 100644 --- a/java/lang/System.java +++ b/java/lang/System.java @@ -190,6 +190,23 @@ public final class System if (SecurityManager.current != null) SecurityManager.current.checkPermission (new RuntimePermission("setSecurityManager")); + + // java.security.Security's class initialiser loads and parses the + // policy files. If it hasn't been run already it will be run + // during the first permission check. That initialisation will + // fail if a very restrictive security manager is in force, so we + // preload it here. + if (SecurityManager.current == null) + { + try + { + Class.forName("java.security.Security"); + } + catch (ClassNotFoundException e) + { + } + } + SecurityManager.current = sm; } diff --git a/java/lang/Thread.java b/java/lang/Thread.java index e64402610..398a3864b 100644 --- a/java/lang/Thread.java +++ b/java/lang/Thread.java @@ -925,7 +925,7 @@ public class Thread implements Runnable if (sm != null) { sm.checkAccess(this); - if (this != currentThread()) + if (this != currentThread() || !(t instanceof ThreadDeath)) sm.checkPermission(new RuntimePermission("stopThread")); } VMThread vt = vmThread; diff --git a/java/lang/reflect/Proxy.java b/java/lang/reflect/Proxy.java index b1ef7429c..ef743f6bc 100644 --- a/java/lang/reflect/Proxy.java +++ b/java/lang/reflect/Proxy.java @@ -1,5 +1,5 @@ /* Proxy.java -- build a proxy class that implements reflected interfaces - Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,7 @@ import gnu.java.lang.reflect.TypeSignature; import java.io.Serializable; import java.security.ProtectionDomain; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -732,6 +733,12 @@ public class Proxy implements Serializable int j = methods.length; while (--j >= 0) { + if (isCoreObjectMethod(methods[j])) + { + // In the case of an attempt to redefine a public non-final + // method of Object, we must skip it + continue; + } ProxySignature sig = new ProxySignature(methods[j]); ProxySignature old = (ProxySignature) method_set.put(sig, sig); if (old != null) @@ -752,6 +759,41 @@ public class Proxy implements Serializable } return data; } + + /** + * Checks whether the method is similar to a public non-final method of + * Object or not (i.e. with the same name and parameter types). Note that we + * can't rely, directly or indirectly (via Collection.contains) on + * Method.equals as it would also check the declaring class, what we do not + * want. We only want to check that the given method have the same signature + * as a core method (same name and parameter types) + * + * @param method the method to check + * @return whether the method has the same name and parameter types as + * Object.equals, Object.hashCode or Object.toString + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see java.lang.Object#toString() + */ + private static boolean isCoreObjectMethod(Method method) + { + String methodName = method.getName(); + if (methodName.equals("equals")) + { + return Arrays.equals(method.getParameterTypes(), + new Class[] { Object.class }); + } + if (methodName.equals("hashCode")) + { + return method.getParameterTypes().length == 0; + } + if (methodName.equals("toString")) + { + return method.getParameterTypes().length == 0; + } + return false; + } + } // class ProxyData /** diff --git a/java/math/BigDecimal.java b/java/math/BigDecimal.java index 2726cdf87..6efed91b5 100644 --- a/java/math/BigDecimal.java +++ b/java/math/BigDecimal.java @@ -855,16 +855,13 @@ public class BigDecimal extends Number implements Comparable // quotients are the same, so compare remainders - // remove trailing zeros - if (thisParts[1].equals (BigInteger.ZERO) == false) - while (thisParts[1].mod (BigInteger.TEN).equals - (BigInteger.ZERO)) - thisParts[1] = thisParts[1].divide (BigInteger.TEN); - // again... - if (valParts[1].equals(BigInteger.ZERO) == false) - while (valParts[1].mod (BigInteger.TEN).equals - (BigInteger.ZERO)) - valParts[1] = valParts[1].divide (BigInteger.TEN); + // Add some trailing zeros to the remainder with the smallest scale + if (scale < val.scale) + thisParts[1] = thisParts[1].multiply + (BigInteger.valueOf (10).pow (val.scale - scale)); + else if (scale > val.scale) + valParts[1] = valParts[1].multiply + (BigInteger.valueOf (10).pow (scale - val.scale)); // and compare them return thisParts[1].compareTo (valParts[1]); diff --git a/java/net/InetAddress.java b/java/net/InetAddress.java index 7277331bb..ce65bc773 100644 --- a/java/net/InetAddress.java +++ b/java/net/InetAddress.java @@ -651,9 +651,9 @@ public class InetAddress implements Serializable /* * Needed for serialization */ - private void readResolve() throws ObjectStreamException + private Object readResolve() throws ObjectStreamException { - // FIXME: implement this + return new Inet4Address(addr, hostName); } private void readObject(ObjectInputStream ois) diff --git a/java/net/ServerSocket.java b/java/net/ServerSocket.java index afc861403..2b889531a 100644 --- a/java/net/ServerSocket.java +++ b/java/net/ServerSocket.java @@ -1,5 +1,5 @@ /* ServerSocket.java -- Class for implementing server side sockets - Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004 + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -314,11 +314,6 @@ public class ServerSocket */ public Socket accept() throws IOException { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkAccept(impl.getInetAddress().getHostAddress(), - impl.getLocalPort()); - Socket socket = new Socket(); try @@ -360,6 +355,9 @@ public class ServerSocket if (isClosed()) throw new SocketException("ServerSocket is closed"); + // FIXME: Add a security check to make sure we're allowed to + // connect to the remote host. + // The Sun spec says that if we have an associated channel and // it is in non-blocking mode, we throw an IllegalBlockingModeException. // However, in our implementation if the channel itself initiated this diff --git a/java/net/SocketPermission.java b/java/net/SocketPermission.java index 8ccd01bae..723ccc7a5 100644 --- a/java/net/SocketPermission.java +++ b/java/net/SocketPermission.java @@ -1,5 +1,6 @@ /* SocketPermission.java -- Class modeling permissions for socket operations - Copyright (C) 1998, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 1998, 2000, 2001, 2002, 2004, 2006 Free Software + Foundation, Inc. This file is part of GNU Classpath. @@ -37,9 +38,13 @@ exception statement from your version. */ package java.net; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; import java.security.Permission; import java.security.PermissionCollection; +import java.util.StringTokenizer; /** @@ -104,24 +109,52 @@ import java.security.PermissionCollection; * * @since 1.2 * - * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Written by Aaron M. Renn (arenn@urbanophile.com) + * @author Extensively modified by Gary Benson (gbenson@redhat.com) */ public final class SocketPermission extends Permission implements Serializable { static final long serialVersionUID = -7204263841984476862L; -// FIXME: Needs serialization work, including readObject/writeObject methods. + /** + * A hostname (possibly wildcarded) or IP address (IPv4 or IPv6). + */ + private transient String host; /** - * A hostname/port combination as described above + * A range of ports. */ - private transient String hostport; + private transient int minport; + private transient int maxport; /** - * A comma separated list of actions for which we have permission + * Values used for minimum and maximum ports when one or both bounds + * are omitted. This class is essentially independent of the + * networking code it describes, so we do not limit ports to the + * usual network limits of 1 and 65535. + */ + private static final int MIN_PORT = 0; + private static final int MAX_PORT = Integer.MAX_VALUE; + + /** + * The actions for which we have permission. This field is present + * to make the serialized form correct and should not be used by + * anything other than writeObject: everything else should use + * actionmask. */ private String actions; + /** + * A bitmask representing the actions for which we have permission. + */ + private transient int actionmask; + + /** + * The available actions, in the canonical order required for getActions(). + */ + private static final String[] ACTIONS = new String[] { + "connect", "listen", "accept", "resolve"}; + /** * Initializes a new instance of SocketPermission with the * specified host/port combination and actions string. @@ -133,8 +166,137 @@ public final class SocketPermission extends Permission implements Serializable { super(hostport); - this.hostport = hostport; - this.actions = actions; + setHostPort(hostport); + setActions(actions); + } + + /** + * Parse the hostport argument to the constructor. + */ + private void setHostPort(String hostport) + { + // Split into host and ports + String ports; + if (hostport.length() == 0) + { + host = ports = ""; + } + else if (hostport.charAt(0) == '[') + { + // host is a bracketed IPv6 address + int end = hostport.indexOf("]"); + if (end == -1) + throw new IllegalArgumentException("Unmatched '['"); + host = hostport.substring(1, end); + + if (end == hostport.length() - 1) + ports = ""; + else if (hostport.charAt(end + 1) == ':') + ports = hostport.substring(end + 2); + else + throw new IllegalArgumentException("Bad character after ']'"); + } + else + { + // host is a hostname or IPv4 address + int sep = hostport.indexOf(":"); + if (sep == -1) + { + host = hostport; + ports = ""; + } + else + { + host = hostport.substring(0, sep); + ports = hostport.substring(sep + 1); + } + } + if (ports.indexOf(":") != -1) + throw new IllegalArgumentException("Unexpected ':'"); + + // Parse and validate the ports + if (ports.length() == 0) + { + minport = MIN_PORT; + maxport = MAX_PORT; + } + else + { + int sep = ports.indexOf("-"); + if (sep == -1) + { + // a single port + minport = maxport = Integer.parseInt(ports); + } + else + { + if (ports.indexOf("-", sep + 1) != -1) + throw new IllegalArgumentException("Unexpected '-'"); + + if (sep == 0) + { + // an upper bound + minport = MIN_PORT; + maxport = Integer.parseInt(ports.substring(1)); + } + else if (sep == ports.length() - 1) + { + // a lower bound + minport = + Integer.parseInt(ports.substring(0, ports.length() - 1)); + maxport = MAX_PORT; + } + else + { + // a range with two bounds + minport = Integer.parseInt(ports.substring(0, sep)); + maxport = Integer.parseInt(ports.substring(sep + 1)); + } + } + } + } + + /** + * Parse the actions argument to the constructor. + */ + private void setActions(String actionstring) + { + actionmask = 0; + + boolean resolve_needed = false; + boolean resolve_present = false; + + StringTokenizer t = new StringTokenizer(actionstring, ","); + while (t.hasMoreTokens()) + { + String action = t.nextToken(); + action = action.trim().toLowerCase(); + setAction(action); + + if (action.equals("resolve")) + resolve_present = true; + else + resolve_needed = true; + } + + if (resolve_needed && !resolve_present) + setAction("resolve"); + } + + /** + * Parse one element of the actions argument to the constructor. + */ + private void setAction(String action) + { + for (int i = 0; i < ACTIONS.length; i++) + { + if (action.equals(ACTIONS[i])) + { + actionmask |= 1 << i; + return; + } + } + throw new IllegalArgumentException("Unknown action " + action); } /** @@ -150,14 +312,17 @@ public final class SocketPermission extends Permission implements Serializable */ public boolean equals(Object obj) { - if (! (obj instanceof SocketPermission)) - return false; + SocketPermission p; - if (((SocketPermission) obj).hostport.equals(hostport)) - if (((SocketPermission) obj).actions.equals(actions)) - return true; + if (obj instanceof SocketPermission) + p = (SocketPermission) obj; + else + return false; - return false; + return p.actionmask == actionmask && + p.minport == minport && + p.maxport == maxport && + p.host.equals(host); } /** @@ -168,12 +333,7 @@ public final class SocketPermission extends Permission implements Serializable */ public int hashCode() { - int hash = 100; - if (hostport != null) - hash += hostport.hashCode(); - if (actions != null) - hash += actions.hashCode(); - return hash; + return actionmask + minport + maxport + host.hashCode(); } /** @@ -184,38 +344,18 @@ public final class SocketPermission extends Permission implements Serializable */ public String getActions() { - boolean found = false; StringBuffer sb = new StringBuffer(""); - if (actions.indexOf("connect") != -1) + for (int i = 0; i < ACTIONS.length; i++) { - sb.append("connect"); - found = true; + if ((actionmask & (1 << i)) != 0) + { + if (sb.length() != 0) + sb.append(","); + sb.append(ACTIONS[i]); + } } - if (actions.indexOf("listen") != -1) - if (found) - sb.append(",listen"); - else - { - sb.append("listen"); - found = true; - } - - if (actions.indexOf("accept") != -1) - if (found) - sb.append(",accept"); - else - { - sb.append("accept"); - found = true; - } - - if (found) - sb.append(",resolve"); - else if (actions.indexOf("resolve") != -1) - sb.append("resolve"); - return sb.toString(); } @@ -268,136 +408,43 @@ public final class SocketPermission extends Permission implements Serializable return false; // Next check the actions - String ourlist = getActions(); - String theirlist = p.getActions(); + if ((p.actionmask & actionmask) != p.actionmask) + return false; - if (! ourlist.startsWith(theirlist)) + // Then check the ports + if ((p.minport < minport) || (p.maxport > maxport)) return false; - // Now check ports - int ourfirstport = 0; - - // Now check ports - int ourlastport = 0; - - // Now check ports - int theirfirstport = 0; - - // Now check ports - int theirlastport = 0; - - // Get ours - if (hostport.indexOf(":") == -1) - { - ourfirstport = 0; - ourlastport = 65535; - } - else - { - // FIXME: Needs bulletproofing. - // This will dump if hostport if all sorts of bad data was passed to - // the constructor - String range = hostport.substring(hostport.indexOf(":") + 1); - if (range.startsWith("-")) - ourfirstport = 0; - else if (range.indexOf("-") == -1) - ourfirstport = Integer.parseInt(range); - else - ourfirstport = - Integer.parseInt(range.substring(0, range.indexOf("-"))); - - if (range.endsWith("-")) - ourlastport = 65535; - else if (range.indexOf("-") == -1) - ourlastport = Integer.parseInt(range); - else - ourlastport = - Integer.parseInt(range.substring(range.indexOf("-") + 1, - range.length())); - } - - // Get theirs - if (p.hostport.indexOf(":") == -1) - { - theirfirstport = 0; - ourlastport = 65535; - } - else - { - // This will dump if hostport if all sorts of bad data was passed to - // the constructor - String range = p.hostport.substring(hostport.indexOf(":") + 1); - if (range.startsWith("-")) - theirfirstport = 0; - else if (range.indexOf("-") == -1) - theirfirstport = Integer.parseInt(range); - else - theirfirstport = - Integer.parseInt(range.substring(0, range.indexOf("-"))); - - if (range.endsWith("-")) - theirlastport = 65535; - else if (range.indexOf("-") == -1) - theirlastport = Integer.parseInt(range); - else - theirlastport = - Integer.parseInt(range.substring(range.indexOf("-") + 1, - range.length())); - } - - // Now check them - if ((theirfirstport < ourfirstport) || (theirlastport > ourlastport)) - return false; - - // Finally we can check the hosts - String ourhost; - - // Finally we can check the hosts - String theirhost; - - // Get ours - if (hostport.indexOf(":") == -1) - ourhost = hostport; - else - ourhost = hostport.substring(0, hostport.indexOf(":")); - - // Get theirs - if (p.hostport.indexOf(":") == -1) - theirhost = p.hostport; - else - theirhost = p.hostport.substring(0, p.hostport.indexOf(":")); - - // Are they equal? - if (ourhost.equals(theirhost)) + // Finally check the hosts + if (host.equals(p.host)) return true; // Try the canonical names String ourcanonical = null; - - // Try the canonical names String theircanonical = null; try { - ourcanonical = InetAddress.getByName(ourhost).getHostName(); - theircanonical = InetAddress.getByName(theirhost).getHostName(); + ourcanonical = InetAddress.getByName(host).getHostName(); + theircanonical = InetAddress.getByName(p.host).getHostName(); } catch (UnknownHostException e) { // Who didn't resolve? Just assume current address is canonical enough // Is this ok to do? if (ourcanonical == null) - ourcanonical = ourhost; + ourcanonical = host; if (theircanonical == null) - theircanonical = theirhost; + theircanonical = p.host; } if (ourcanonical.equals(theircanonical)) return true; // Well, last chance. Try for a wildcard - if (ourhost.indexOf("*.") != -1) + if (host.indexOf("*.") != -1) { - String wild_domain = ourhost.substring(ourhost.indexOf("*" + 1)); + String wild_domain = + host.substring(host.indexOf("*" + 1)); if (theircanonical.endsWith(wild_domain)) return true; } @@ -405,4 +452,35 @@ public final class SocketPermission extends Permission implements Serializable // Didn't make it return false; } + + /** + * Deserializes a SocketPermission object from + * an input stream. + * + * @param input the input stream. + * @throws IOException if an I/O error occurs in the stream. + * @throws ClassNotFoundException if the class of the + * serialized object could not be found. + */ + private void readObject(ObjectInputStream input) + throws IOException, ClassNotFoundException + { + input.defaultReadObject(); + setHostPort(getName()); + setActions(actions); + } + + /** + * Serializes a SocketPermission object to an + * output stream. + * + * @param output the output stream. + * @throws IOException if an I/O error occurs in the stream. + */ + private void writeObject(ObjectOutputStream output) + throws IOException + { + actions = getActions(); + output.defaultWriteObject(); + } } diff --git a/java/net/URI.java b/java/net/URI.java index 4ca1f8870..022e4a0f5 100644 --- a/java/net/URI.java +++ b/java/net/URI.java @@ -1,5 +1,5 @@ /* URI.java -- An URI class - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -346,8 +346,15 @@ public final class URI private static String getURIGroup(Matcher match, int group) { String matched = match.group(group); - return matched.length() == 0 - ? ((match.group(group - 1).length() == 0) ? null : "") : matched; + if (matched == null || matched.length() == 0) + { + String prevMatched = match.group(group -1); + if (prevMatched == null || prevMatched.length() == 0) + return null; + else + return ""; + } + return matched; } /** diff --git a/java/net/URLClassLoader.java b/java/net/URLClassLoader.java index 02a811d93..702a3de73 100644 --- a/java/net/URLClassLoader.java +++ b/java/net/URLClassLoader.java @@ -1,5 +1,5 @@ /* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -292,9 +292,10 @@ public class URLClassLoader extends SecureClassLoader Vector classPath; // The "Class-Path" attribute of this Jar's manifest - public JarURLLoader(URLClassLoader classloader, URL baseURL) + public JarURLLoader(URLClassLoader classloader, URL baseURL, + URL absoluteUrl) { - super(classloader, baseURL); + super(classloader, baseURL, absoluteUrl); // Cache url prefix for all resources in this jar url. String external = baseURL.toExternalForm(); @@ -526,10 +527,10 @@ public class URLClassLoader extends SecureClassLoader { File dir; //the file for this file url - FileURLLoader(URLClassLoader classloader, URL url) + FileURLLoader(URLClassLoader classloader, URL url, URL absoluteUrl) { - super(classloader, url); - dir = new File(baseURL.getFile()); + super(classloader, url, absoluteUrl); + dir = new File(absoluteUrl.getFile()); } /** get resource with the name "name" in the file url */ @@ -723,11 +724,42 @@ public class URLClassLoader extends SecureClassLoader String file = newUrl.getFile(); String protocol = newUrl.getProtocol(); + // If we have a file: URL, we want to make it absolute + // here, before we decide whether it is really a jar. + URL absoluteURL; + if ("file".equals (protocol)) + { + File dir = new File(file); + URL absUrl; + try + { + absoluteURL = dir.getCanonicalFile().toURL(); + } + catch (IOException ignore) + { + try + { + absoluteURL = dir.getAbsoluteFile().toURL(); + } + catch (MalformedURLException _) + { + // This really should not happen. + absoluteURL = newUrl; + } + } + } + else + { + // This doesn't hurt, and it simplifies the logic a + // little. + absoluteURL = newUrl; + } + // Check that it is not a directory if (! (file.endsWith("/") || file.endsWith(File.separator))) - loader = new JarURLLoader(this, newUrl); + loader = new JarURLLoader(this, newUrl, absoluteURL); else if ("file".equals(protocol)) - loader = new FileURLLoader(this, newUrl); + loader = new FileURLLoader(this, newUrl, absoluteURL); else loader = new RemoteURLLoader(this, newUrl); diff --git a/java/net/URLConnection.java b/java/net/URLConnection.java index 2b727c20d..986270cb2 100644 --- a/java/net/URLConnection.java +++ b/java/net/URLConnection.java @@ -599,6 +599,9 @@ public abstract class URLConnection */ public void setAllowUserInteraction(boolean allow) { + if (connected) + throw new IllegalStateException("Already connected"); + allowUserInteraction = allow; } @@ -777,7 +780,7 @@ public abstract class URLConnection * * @param key The name of the property * - * @return Value of the property + * @return Value of the property, or null if key is null. * * @exception IllegalStateException If already connected * diff --git a/java/rmi/AccessException.java b/java/rmi/AccessException.java index b47078004..40954dfd3 100644 --- a/java/rmi/AccessException.java +++ b/java/rmi/AccessException.java @@ -1,5 +1,6 @@ /* AccessException.java -- thrown if the caller does not have access - Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,7 +44,7 @@ package java.rmi; * * @author unknown * @see Naming - * @see ActivationSystem + * @see java.rmi.activation.ActivationSystem * @since 1.1 */ public class AccessException extends RemoteException diff --git a/java/rmi/AlreadyBoundException.java b/java/rmi/AlreadyBoundException.java index 091c0ee58..10f6e4cec 100644 --- a/java/rmi/AlreadyBoundException.java +++ b/java/rmi/AlreadyBoundException.java @@ -1,5 +1,6 @@ /* AlreadyBoundException.java -- thrown if a binding is already bound - Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,8 +43,8 @@ package java.rmi; * bound. * * @author unknown - * @see Naming#bind(String, Remote) - * @see Registry#bind(String, Remote) + * @see java.rmi.Naming#bind(String, Remote) + * @see java.rmi.registry.Registry#bind(String, Remote) * @since 1.1 * @status updated to 1.4 */ diff --git a/java/rmi/MarshalledObject.java b/java/rmi/MarshalledObject.java index 9ec0ace0e..e1a30f5f0 100644 --- a/java/rmi/MarshalledObject.java +++ b/java/rmi/MarshalledObject.java @@ -1,5 +1,6 @@ /* MarshalledObject.java -- - Copyright (c) 1996, 1997, 1998, 1999, 2004 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2004, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,38 +43,68 @@ import gnu.java.rmi.RMIMarshalledObjectInputStream; import gnu.java.rmi.RMIMarshalledObjectOutputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.Serializable; /** - * FIXME - doc missing + * A MarshalledObject consists of a serialized object which is + * marshalled according to the RMI specification. + *

      + * An object passed to the constructor is serialized and tagged with the needed + * URL to retrieve its class definition for remote usage. If the object is a + * remote reference its stub is serialized instead. The instance of this + * marshalled object can be later retrieved by its get() method. + *

      + * + * @author unknown */ -public final class MarshalledObject implements Serializable +public final class MarshalledObject + implements Serializable { - //The following fields are from Java API Documentation "Serialized form" + // The following fields are from Java API Documentation "Serialized form" private static final long serialVersionUID = 8988374069173025854L; + byte[] objBytes; byte[] locBytes; int hash; - - public MarshalledObject(Object obj) throws java.io.IOException + + /** + * Constructs a MarshalledObject from the given object. + * + * @param obj the object to marshal + * @throws IOException if an I/O error during serialization occurs. + */ + public MarshalledObject(Object obj) throws IOException { ByteArrayOutputStream objStream = new ByteArrayOutputStream(); - RMIMarshalledObjectOutputStream stream = new RMIMarshalledObjectOutputStream(objStream); + RMIMarshalledObjectOutputStream stream = + new RMIMarshalledObjectOutputStream(objStream); stream.writeObject(obj); stream.flush(); objBytes = objStream.toByteArray(); locBytes = stream.getLocBytes(); - - //The following algorithm of calculating hashCode is similar to String + + // The following algorithm of calculating hashCode is similar to String hash = 0; for (int i = 0; i < objBytes.length; i++) hash = hash * 31 + objBytes[i]; - if(locBytes != null) + + if (locBytes != null) for (int i = 0; i < locBytes.length; i++) - hash = hash * 31 + locBytes[i]; + hash = hash * 31 + locBytes[i]; } - - public boolean equals(Object obj) + + /** + * Checks if the given object is equal to this marshalled object. + * + *

      Marshalled objects are considered equal if they contain the + * same serialized object. Codebase annotations where the class + * definition can be downloaded are ignored in the equals test.

      + * + * @param obj the object to compare. + * @return true if equal, false otherwise. + */ + public boolean equals(Object obj) { if (! (obj instanceof MarshalledObject)) return false; @@ -81,33 +112,43 @@ public final class MarshalledObject implements Serializable // hashCode even differs, don't do the time-consuming comparisons if (obj.hashCode() != hash) return false; - - MarshalledObject aobj = (MarshalledObject)obj; + + MarshalledObject aobj = (MarshalledObject) obj; if (objBytes == null || aobj.objBytes == null) return objBytes == aobj.objBytes; if (objBytes.length != aobj.objBytes.length) return false; - for (int i = 0; i < objBytes.length; i++) + for (int i = 0; i < objBytes.length; i++) { - if (objBytes[i] != aobj.objBytes[i]) - return false; + if (objBytes[i] != aobj.objBytes[i]) + return false; } // Ignore comparison of locBytes(annotation) return true; } - -public Object get() - throws java.io.IOException, java.lang.ClassNotFoundException -{ - if(objBytes == null) - return null; - RMIMarshalledObjectInputStream stream = - new RMIMarshalledObjectInputStream(objBytes, locBytes); - return stream.readObject(); -} - - public int hashCode() { + + /** + * Constructs and returns a copy of the internal serialized object. + * + * @return The deserialized object. + * + * @throws IOException if an I/O exception occurs during deserialization. + * @throws ClassNotFoundException if the class of the deserialized object + * cannot be found. + */ + public Object get() throws IOException, ClassNotFoundException + { + if (objBytes == null) + return null; + + RMIMarshalledObjectInputStream stream = + new RMIMarshalledObjectInputStream(objBytes, locBytes); + return stream.readObject(); + } + + public int hashCode() + { return hash; } - + } diff --git a/java/rmi/Naming.java b/java/rmi/Naming.java index d48df069d..b605da70d 100644 --- a/java/rmi/Naming.java +++ b/java/rmi/Naming.java @@ -1,5 +1,6 @@ /* Naming.java -- - Copyright (c) 1996, 1997, 1998, 1999, 2004 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2004, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -76,136 +77,150 @@ import java.rmi.registry.Registry; * @author Andrew John Hughes (gnu_andrew@member.fsf.org) * @since 1.1 */ -public final class Naming { - +public final class Naming +{ /** * This class isn't intended to be instantiated. */ - private Naming() {} + private Naming() + { + } -/** - * Looks for the remote object that is associated with the named service. - * Name and location is given in form of a URL without a scheme: - * - *
      - * //host:port/service-name
      - * 
      - * - * The port is optional. - * - * @param name the service name and location - * @return Remote-object that implements the named service - * @throws NotBoundException if no object implements the service - * @throws MalformedURLException - * @throws RemoteException - */ -public static Remote lookup(String name) throws NotBoundException, MalformedURLException, RemoteException { - URL u = parseURL(name); - String serviceName = getName(u); - return (getRegistry(u).lookup(serviceName)); -} + /** + * Looks for the remote object that is associated with the named service. + * Name and location is given in form of a URL without a scheme: + * + *
      +   * //host:port/service-name
      +   * 
      + * + * The port is optional. + * + * @param name the service name and location + * @return Remote-object that implements the named service + * @throws NotBoundException if no object implements the service + * @throws MalformedURLException + * @throws RemoteException + */ + public static Remote lookup(String name) throws NotBoundException, + MalformedURLException, RemoteException + { + URL u = parseURL(name); + String serviceName = getName(u); + return (getRegistry(u).lookup(serviceName)); + } -/** - * Try to bind the given object to the given service name. - * @param name - * @param obj - * @throws AlreadyBoundException - * @throws MalformedURLException - * @throws RemoteException - */ -public static void bind(String name, Remote obj) throws AlreadyBoundException, MalformedURLException, RemoteException { - URL u = parseURL(name); - String serviceName = getName(u); - getRegistry(u).bind(serviceName, obj); -} + /** + * Try to bind the given object to the given service name. + * + * @param name + * @param obj + * @throws AlreadyBoundException + * @throws MalformedURLException + * @throws RemoteException + */ + public static void bind(String name, Remote obj) + throws AlreadyBoundException, MalformedURLException, RemoteException + { + URL u = parseURL(name); + String serviceName = getName(u); + getRegistry(u).bind(serviceName, obj); + } -/** - * Remove a binding for a given service name. - * @param name - * @throws RemoteException - * @throws NotBoundException - * @throws MalformedURLException - */ -public static void unbind(String name) throws RemoteException, NotBoundException, MalformedURLException { - URL u = parseURL(name); - String serviceName = getName(u); - getRegistry(u).unbind(serviceName); -} + /** + * Remove a binding for a given service name. + * + * @param name + * @throws RemoteException + * @throws NotBoundException + * @throws MalformedURLException + */ + public static void unbind(String name) throws RemoteException, + NotBoundException, MalformedURLException + { + URL u = parseURL(name); + String serviceName = getName(u); + getRegistry(u).unbind(serviceName); + } -/** - * Forces the binding between the given Remote-object and the given service name, even - * if there was already an object bound to this name. - * @param name - * @param obj - * @throws RemoteException - * @throws MalformedURLException - */ -public static void rebind(String name, Remote obj) throws RemoteException, MalformedURLException { - URL u = parseURL(name); - String serviceName = getName(u); - getRegistry(u).rebind(serviceName, obj); -} + /** + * Forces the binding between the given Remote-object and the given service + * name, even if there was already an object bound to this name. + * + * @param name + * @param obj + * @throws RemoteException + * @throws MalformedURLException + */ + public static void rebind(String name, Remote obj) throws RemoteException, + MalformedURLException + { + URL u = parseURL(name); + String serviceName = getName(u); + getRegistry(u).rebind(serviceName, obj); + } -/** - * Lists all services at the named registry. - * @param name url that specifies the registry - * @return list of services at the name registry - * @throws RemoteException - * @throws MalformedURLException - */ -public static String[] list(String name) throws RemoteException, MalformedURLException { - return (getRegistry(parseURL(name)).list()); -} + /** + * Lists all services at the named registry. + * + * @param name url that specifies the registry + * @return list of services at the name registry + * @throws RemoteException + * @throws MalformedURLException + */ + public static String[] list(String name) throws RemoteException, + MalformedURLException + { + return (getRegistry(parseURL(name)).list()); + } -private static Registry getRegistry(URL u) throws RemoteException { - if (u.getPort() == -1) { - return (LocateRegistry.getRegistry(u.getHost())); - } - else { - return (LocateRegistry.getRegistry(u.getHost(), u.getPort())); - } -} + private static Registry getRegistry(URL u) throws RemoteException + { + if (u.getPort() == - 1) + { + return (LocateRegistry.getRegistry(u.getHost())); + } + else + { + return (LocateRegistry.getRegistry(u.getHost(), u.getPort())); + } + } /** - * Parses the supplied URL and converts it to use the HTTP - * protocol. From an RMI perspective, the scheme is irrelevant - * and we want to be able to create a URL for which a handler is - * available. - * + * Parses the supplied URL and converts it to use the HTTP protocol. From an + * RMI perspective, the scheme is irrelevant and we want to be able to create + * a URL for which a handler is available. + * * @param name the URL in String form. * @throws MalformedURLException if the URL is invalid. */ - private static URL parseURL(String name) - throws MalformedURLException + private static URL parseURL(String name) throws MalformedURLException { try { - URI uri = new URI(name); - String host = uri.getHost(); - int port = uri.getPort(); - String query = uri.getQuery(); - String path = uri.getPath(); - return new URL("http", - (host == null ? "localhost" : host), - (port == -1 ? 1099 : port), - uri.getPath() + (query == null ? "" : query)); + URI uri = new URI(name); + String host = uri.getHost(); + int port = uri.getPort(); + String query = uri.getQuery(); + String path = uri.getPath(); + return new URL("http", (host == null ? "localhost" : host), + (port == - 1 ? 1099 : port), uri.getPath() + + (query == null ? "" : query)); } catch (URISyntaxException e) { - throw new MalformedURLException("The URL syntax was invalid: " + - e.getMessage()); + throw new MalformedURLException("The URL syntax was invalid: " + + e.getMessage()); } } /** - * Checks that the URL contains a name, and removes any leading - * slashes. - * + * Checks that the URL contains a name, and removes any leading slashes. + * * @param url the URL to check. * @throws MalformedURLException if no name is specified. - */ - private static String getName(URL url) - throws MalformedURLException + */ + private static String getName(URL url) throws MalformedURLException { String filename = url.getFile(); if (filename.length() == 0) @@ -216,5 +231,4 @@ private static Registry getRegistry(URL u) throws RemoteException { return filename.substring(1); return filename; } - } diff --git a/java/rmi/NoSuchObjectException.java b/java/rmi/NoSuchObjectException.java index 69f7d6c52..294390670 100644 --- a/java/rmi/NoSuchObjectException.java +++ b/java/rmi/NoSuchObjectException.java @@ -1,5 +1,6 @@ /* NoSuchObjectException.java -- thrown if the remote object no longer exists - Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,9 +44,9 @@ package java.rmi; * obey the semantics of "at most once". * * @author unknown - * @see RemoteObject#toStub(Remote) - * @see UnicastRemoteObject#unexportObject(Remote, boolean) - * @see Activatable#unexportObject(Remote, boolean) + * @see java.rmi.server.RemoteObject#toStub(Remote) + * @see java.rmi.server.UnicastRemoteObject#unexportObject(Remote, boolean) + * @see java.rmi.activation.Activatable#unexportObject(Remote, boolean) * @since 1.1 * @status updated to 1.4 */ diff --git a/java/rmi/NotBoundException.java b/java/rmi/NotBoundException.java index b8bc0a532..03d4adf8f 100644 --- a/java/rmi/NotBoundException.java +++ b/java/rmi/NotBoundException.java @@ -1,5 +1,6 @@ /* NotBoundException.java -- attempt to use a registry name with no binding - Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,10 +43,10 @@ package java.rmi; * associated binding. * * @author unknown - * @see Naming#lookup(String) - * @see Naming#unbind(String) - * @see Registry#lookup(String) - * @see Registry#unbind(String) + * @see java.rmi.Naming#lookup(String) + * @see java.rmi.Naming#unbind(String) + * @see java.rmi.registry.Registry#lookup(String) + * @see java.rmi.registry.Registry#unbind(String) * @since 1.1 * @status updated to 1.4 */ diff --git a/java/rmi/RMISecurityException.java b/java/rmi/RMISecurityException.java index a44a67e2a..6f15af852 100644 --- a/java/rmi/RMISecurityException.java +++ b/java/rmi/RMISecurityException.java @@ -1,5 +1,6 @@ /* RMISecurityException.java -- deprecated version of SecurityException - Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,11 +39,12 @@ exception statement from your version. */ package java.rmi; /** - * Never thrown, but originally intended to wrap a java.lang.SecurityException. + * Never thrown, but originally intended to wrap a + * {@link java.lang.SecurityException} in the case of RMI. * * @author unknown * @since 1.1 - * @deprecated use {@link SecurityException} instead + * @deprecated use {@link java.lang.SecurityException} instead * @status updated to 1.4 */ public class RMISecurityException extends SecurityException @@ -55,7 +57,7 @@ public class RMISecurityException extends SecurityException /** * Create an exception with a message. * - * @param s the message + * @param n the message * @deprecated no longer needed */ public RMISecurityException(String n) @@ -66,8 +68,8 @@ public class RMISecurityException extends SecurityException /** * Create an exception with a message and a cause. * - * @param s the message - * @param e the cause + * @param n the message + * @param a the cause (ignored) * @deprecated no longer needed */ public RMISecurityException(String n, String a) diff --git a/java/rmi/Remote.java b/java/rmi/Remote.java index 93c8d0aa1..0306981e9 100644 --- a/java/rmi/Remote.java +++ b/java/rmi/Remote.java @@ -1,5 +1,5 @@ /* Remote.java - Copyright (c) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,5 +37,22 @@ exception statement from your version. */ package java.rmi; +/** + * Marker interface for interfaces which methods are invokable + * from outside of this virtual machine through remote method calls. + *

      + * Remote invokable methods of remote object implementations are specified + * as the methods defined in the implemented remote interfaces. Typically + * remote object implementations are subclasses of the convenience classes + * {@link java.rmi.server.UnicastRemoteObject} or + * {@link java.rmi.activation.Activatable} implementing one or more remote + * interfaces indicating their remotely accessible methods. The convenience + * classes provide implementations for correct remote object creation, + * hash, equals and toString methods. + *

      + * + * @author unknown + */ public interface Remote { + // marker interface } diff --git a/java/rmi/RemoteException.java b/java/rmi/RemoteException.java index cbbb26299..929bc80f6 100644 --- a/java/rmi/RemoteException.java +++ b/java/rmi/RemoteException.java @@ -1,5 +1,6 @@ /* RemoteException.java -- common superclass for exceptions in java.rmi - Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -86,7 +87,7 @@ public class RemoteException extends IOException * Create an exception with the given message and cause. * * @param s the message - * @param ex the cause + * @param e the cause */ public RemoteException(String s, Throwable e) { diff --git a/java/rmi/StubNotFoundException.java b/java/rmi/StubNotFoundException.java index 2f9e0f5ff..524b418ce 100644 --- a/java/rmi/StubNotFoundException.java +++ b/java/rmi/StubNotFoundException.java @@ -1,5 +1,6 @@ /* StubNotFoundException.java -- thrown if a valid stub is not found - Copyright (c) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,8 +42,8 @@ package java.rmi; * Thrown if a valid stub class is not found for an object when it is exported. * * @author unknown - * @see UnicastRemoteObject - * @see Activatable + * @see java.rmi.server.UnicastRemoteObject + * @see java.rmi.activation.Activatable * @since 1.1 * @status updated to 1.4 */ diff --git a/java/rmi/package.html b/java/rmi/package.html index a7bf85020..1d36fe80a 100644 --- a/java/rmi/package.html +++ b/java/rmi/package.html @@ -40,7 +40,7 @@ exception statement from your version. --> GNU Classpath - java.rmi -

      +

      Provides basic Remote Method Invocation (RMI) interfaces, classes and exceptions.

      diff --git a/java/rmi/registry/Registry.java b/java/rmi/registry/Registry.java index 6cd2a04a6..02d8c50cc 100644 --- a/java/rmi/registry/Registry.java +++ b/java/rmi/registry/Registry.java @@ -47,7 +47,29 @@ import java.rmi.RemoteException; public interface Registry extends Remote { int REGISTRY_PORT = 1099; - + + /** + * Find and return the reference to the object that was previously bound + * to the registry by this name. For remote objects, this method returns + * the stub instances, containing the code for remote invocations. + * + * Since jdk 1.5 this method does not longer require the stub class + * (nameImpl_Stub) to be present. If such class is not found, the stub is + * replaced by the dynamically constructed proxy class. No attempt to find + * and load the stubs is made if the system property + * java.rmi.server.ignoreStubClasses is set to true (set to reduce the + * starting time if the stubs are surely not present and exclusively 1.2 + * RMI is used). + * + * @param name the name of the object + * + * @return the reference to that object on that it is possible to invoke + * the (usually remote) object methods. + * + * @throws RemoteException + * @throws NotBoundException + * @throws AccessException + */ Remote lookup(String name) throws RemoteException, NotBoundException, AccessException; diff --git a/java/rmi/server/RemoteObjectInvocationHandler.java b/java/rmi/server/RemoteObjectInvocationHandler.java new file mode 100644 index 000000000..afd1d5927 --- /dev/null +++ b/java/rmi/server/RemoteObjectInvocationHandler.java @@ -0,0 +1,221 @@ +/* RemoteObjectInvocationHandler.java -- RMI stub replacement. + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package java.rmi.server; + +import gnu.java.rmi.server.RMIHashes; + +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.UnexpectedException; +import java.rmi.registry.Registry; +import java.rmi.server.RemoteObject; +import java.rmi.server.RemoteRef; +import java.rmi.server.UnicastRemoteObject; +import java.util.Hashtable; + +/** + * Together with dynamic proxy instance, this class replaces the generated RMI + * stub (*_Stub) classes that (following 1.5 specification) should be no longer + * required. It is unusual to use the instances of this class directly in the + * user program. Such instances are automatically created and returned by + * {@link Registry} or {@link UnicastRemoteObject} methods if the remote + * reference is known but the corresponding stub class is not accessible. + * + * @see Registry#lookup + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class RemoteObjectInvocationHandler extends RemoteObject implements + InvocationHandler, Remote, Serializable +{ + /** + * Use the jdk 1.5 SUID for interoperability. + */ + static final long serialVersionUID = 2L; + + /** + * The RMI method hash codes, computed once as described in the section 8.3 + * of the Java Remote Method Invocation (RMI) Specification. + */ + static Hashtable methodHashCodes = new Hashtable(); + + /** + * The empty class array to define parameters of .hashCode and .toString. + */ + static final Class[] noArgsC = new Class[0]; + + /** + * The class array to define parameters of .equals + */ + static final Class[] anObjectC = new Class[] { Object.class }; + + /** + * Construct the remote invocation handler that forwards calls to the given + * remote object. + * + * @param reference the reference to the remote object where the method + * calls should be forwarded. + */ + public RemoteObjectInvocationHandler(RemoteRef reference) + { + super(reference); + } + + /** + * Invoke the remote method. When the known method is invoked on a created RMI + * stub proxy class, the call is delivered to this method and then transferred + * to the {@link RemoteRef#invoke(Remote, Method, Object[], long)} of the + * remote reference that was passed in constructor. The methods are handled as + * following: + *
        + *
      • The toString() method is delegated to the passed proxy instance.
      • + *
      • The .equals method only returns true if the passed object is an + * instance of proxy class and its invocation handler is equal to this + * invocation handles.
      • + *
      • The .hashCode returns the hashCode of this invocation handler (if the.
      • + *
      • All other methods are converted to remote calls and forwarded to the + * remote reference.
      • + *
      + * + * @param proxyInstance + * the instance of the proxy stub + * @param method + * the method being invoked + * @param parameters + * the method parameters + * @return the method return value, returned by RemoteRef.invoke + * @throws IllegalAccessException + * if the passed proxy instance does not implement Remote interface. + * @throws UnexpectedException + * if remote call throws some exception, not listed in the + * throws clause of the method being called. + * @throws Throwable + * that is thrown by remote call, if that exception is listend in + * the throws clause of the method being called. + */ + public Object invoke(Object proxyInstance, Method method, Object[] parameters) + throws Throwable + { + if (!(proxyInstance instanceof Remote)) + { + String name = proxyInstance == null ? "null" + : proxyInstance.getClass().getName(); + throw new IllegalAccessException(name + " does not implement " + + Remote.class.getName()); + } + + String name = method.getName(); + switch (name.charAt(0)) + { + case 'e': + if (parameters.length == 1 && name.equals("equals") + && method.getParameterTypes()[0].equals(Object.class)) + { + if (parameters[0] instanceof Proxy) + { + Object handler = Proxy.getInvocationHandler(parameters[0]); + if (handler == null) + return Boolean.FALSE; + else + return handler.equals(this) ? Boolean.TRUE : Boolean.FALSE; + } + else + return Boolean.FALSE; + } + break; + case 'h': + if (parameters.length == 0 && name.equals("hashCode")) + { + int hashC = Proxy.getInvocationHandler(proxyInstance).hashCode(); + return new Integer(hashC); + } + break; + case 't': + if (parameters.length == 0 && name.equals("toString")) + return proxyInstance.toString(); + break; + default: + break; + } + + Long hash = (Long) methodHashCodes.get(method); + if (hash == null) + { + hash = new Long(RMIHashes.getMethodHash(method)); + methodHashCodes.put(method, hash); + } + + try + { + return getRef().invoke((Remote) proxyInstance, method, parameters, + hash.longValue()); + } + catch (RuntimeException exception) + { + // RuntimeException is always supported. + throw exception; + } + catch (RemoteException exception) + { + // All remote methods can throw RemoteException. + throw exception; + } + catch (Error exception) + { + throw exception; + } + catch (Exception exception) + { + Class[] exceptions = method.getExceptionTypes(); + Class exceptionClass = exception.getClass(); + + for (int i = 0; i < exceptions.length; i++) + { + if (exceptions[i].equals(exceptionClass)) + throw exception; + } + throw new UnexpectedException(method.getName(), exception); + } + } + +} diff --git a/java/rmi/server/RemoteRef.java b/java/rmi/server/RemoteRef.java index f33f9d374..8bdb66330 100644 --- a/java/rmi/server/RemoteRef.java +++ b/java/rmi/server/RemoteRef.java @@ -1,5 +1,6 @@ /* RemoteRef.java -- - Copyright (c) 1996, 1997, 1998, 1999, 2004 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2004, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,8 +45,16 @@ import java.lang.reflect.Method; import java.rmi.Remote; import java.rmi.RemoteException; +/** + * Represents a handler to the remote object. Each instance of the + * {@link RemoteStub} contains such handler and uses it to invoke remote + * methods via {@link #invoke(Remote, Method, Object[], long)}. + */ public interface RemoteRef extends Externalizable { + /** + * Indicates compatibility with JDK 1.1.* + */ long serialVersionUID = 3632638527362204081L; /** @@ -55,29 +64,74 @@ public interface RemoteRef extends Externalizable String packagePrefix = "sun.rmi.server"; /** - * @deprecated + * @deprecated use {@link #invoke(Remote, Method, Object[], long)} instead. */ void invoke (RemoteCall call) throws Exception; - Object invoke (Remote obj, Method method, Object[] params, long opnum) + /** + * Invoke a method. This method either returns the result of remote invocation + * or throws RemoteException if the remote call failed. Other exceptions may + * be thrown if some problem has occured in the application level. + * + * @param obj the object, containing the remote reference (for instance, + * remote stub, generated by rmic). + * @param method the method to invoke + * @param params the method parameters + * @param methodHash a persistent hash code that can be used to represent a + * method + * @return the result of the remote invocation + * @throws RemoteException if the remote call has failed + * @throws Exception if one is raised at the application level + */ + Object invoke (Remote obj, Method method, Object[] params, long methodHash) throws Exception; /** - * @deprecated + * @deprecated use {@link #invoke(Remote, Method, Object[], long)} instead. */ RemoteCall newCall (RemoteObject obj, Operation[] op, int opnum, long hash) throws RemoteException; /** - * @deprecated + * @deprecated use {@link #invoke(Remote, Method, Object[], long)} instead. */ void done (RemoteCall call) throws RemoteException; + /** + * Compare two remote objects for equality. The references are equal if + * they point to the same remote object. + * + * @param ref the reference to compare. + * + * @return true if this and passed references both point to the same remote + * object, false otherwise. + */ boolean remoteEquals (RemoteRef ref); + /** + * Get the hashcode for a remote object. Two remote object stubs, referring + * to the same remote object, have the same hash code. + * + * @return the hashcode of the remote object + */ int remoteHashCode(); + + /** + * Returns the class name of the reference type that must be written to the + * given stream. When writing, this returned name is passed first, and + * the reference.writeExternal(out) writes the reference specific data. + * + * @param out the stream, where the data must be written + * + * @return the class name. + */ String getRefClass (ObjectOutput out); + /** + * Get the string representation of this remote reference. + * + * @return the string representation. + */ String remoteToString(); } diff --git a/java/rmi/server/RemoteStub.java b/java/rmi/server/RemoteStub.java index 18c614b54..d6dff7fad 100644 --- a/java/rmi/server/RemoteStub.java +++ b/java/rmi/server/RemoteStub.java @@ -37,21 +37,40 @@ exception statement from your version. */ package java.rmi.server; +/** + * This is a base class for the automatically generated RMI stubs. + */ public abstract class RemoteStub extends RemoteObject { + /** + * Use serialVersionUID for interoperability. + */ static final long serialVersionUID = -1585587260594494182l; - + + /** + * Constructs the remote stub with no reference set. + */ protected RemoteStub () { super (); } - + + /** + * Constructs the remote stub that uses given remote reference for the + * method invocations. + * + * @param ref the remote reference for the method invocation. + */ protected RemoteStub (RemoteRef ref) { super (ref); } /** + * Sets the given remote reference for the given stub. This method is + * deprecated. Pass the stub remote reference to the RemoteStub + * constructor instead. + * * @deprecated */ protected static void setRef (RemoteStub stub, RemoteRef ref) diff --git a/java/rmi/server/UnicastRemoteObject.java b/java/rmi/server/UnicastRemoteObject.java index dbe25bda3..31bf88023 100644 --- a/java/rmi/server/UnicastRemoteObject.java +++ b/java/rmi/server/UnicastRemoteObject.java @@ -1,5 +1,6 @@ /* UnicastRemoteObject.java -- - Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,61 +45,175 @@ import java.rmi.NoSuchObjectException; import java.rmi.Remote; import java.rmi.RemoteException; +/** + * This class obtains stub that communicates with the remote object. + */ public class UnicastRemoteObject extends RemoteServer { -private static final long serialVersionUID = 4974527148936298033L; -//The following serialized fields are from Java API Documentation "Serialized form" -private int port = 0; -private RMIClientSocketFactory csf = null; -private RMIServerSocketFactory ssf = null; + /** + * Use SVUID for interoperability. + */ + private static final long serialVersionUID = 4974527148936298033L; -protected UnicastRemoteObject() throws RemoteException { - this(0); -} + //The following serialized fields are from Java API Documentation + // "Serialized form" + + /** + * The port, on that the created remote object becomes available, + * zero meaning the anonymous port. + */ + private int port; + + /** + * The client socket factory for producing client sockets, used by this + * object. + */ + private RMIClientSocketFactory csf; + + /** + * The server socket factory for producing server sockets, used by this + * object. + */ + private RMIServerSocketFactory ssf; -protected UnicastRemoteObject(int port) throws RemoteException { - this(port, RMISocketFactory.getSocketFactory(), RMISocketFactory.getSocketFactory()); -} + /** + * Create and export new remote object without specifying the port value. + * + * @throws RemoteException if the attempt to export the object failed. + */ + protected UnicastRemoteObject() + throws RemoteException + { + this(0); + } + + /** + * Create and export the new remote object, making it available at the + * given port, local host. + * + * @param port the port, on that the object should become available. + * Zero means anonymous port. + * + * @throws RemoteException if the attempt to export the object failed. + */ + protected UnicastRemoteObject(int port) + throws RemoteException + { + this(port, RMISocketFactory.getSocketFactory(), + RMISocketFactory.getSocketFactory()); + } -protected UnicastRemoteObject(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws RemoteException { - this.port = port; - //Is RMIXXXSocketFactory serializable - //this.csf = csf; - //this.ssf = ssf; - this.ref = new UnicastServerRef(new ObjID(), port, ssf); - exportObject(this); -} + /** + * Create and export the new remote object, making it available at the + * given port, using sockets, produced by the specified factories. + * + * @param port the port, on that the object should become available. + * Zero means anonymous port. + * + * @param clientSocketFactory the client socket factory + * @param serverSocketFactory the server socket factory + * + * @throws RemoteException if the attempt to export the object failed. + */ + protected UnicastRemoteObject(int port, + RMIClientSocketFactory clientSocketFactory, + RMIServerSocketFactory serverSocketFactory) + throws RemoteException + { + this.port = port; + //Is RMIXXXSocketFactory serializable + //this.csf = csf; + //this.ssf = ssf; + this.ref = new UnicastServerRef(new ObjID(), port, serverSocketFactory); + exportObject(this, port); + } -protected UnicastRemoteObject(RemoteRef ref) throws RemoteException { - super((UnicastServerRef)ref); - exportObject(this); -} + protected UnicastRemoteObject(RemoteRef ref) + throws RemoteException + { + super((UnicastServerRef) ref); + exportObject(this, 0); + } -public Object clone() throws CloneNotSupportedException { + public Object clone() + throws CloneNotSupportedException + { throw new Error("Not implemented"); -} - -public static RemoteStub exportObject(Remote obj) throws RemoteException { - UnicastServerRef sref = (UnicastServerRef)((RemoteObject)obj).getRef(); - return (sref.exportObject(obj)); -} + } + + /** + * Export object, making it available for the remote calls at the + * anonymous port. + * + * This method returns the instance of the abstract class, not an interface. + * Hence it will not work with the proxy stubs that are supported since + * jdk 1.5 (such stubs cannot be derived from the RemoteStub). Only use + * this method if you are sure that the stub class will be accessible. + * + * @param obj the object being exported. + * + * @return the remote object stub + * + * @throws RemoteException if the attempt to export the object failed. + */ + public static RemoteStub exportObject(Remote obj) + throws RemoteException + { + return (RemoteStub) exportObject(obj, 0); + } - public static Remote exportObject(Remote obj, int port) throws RemoteException + /** + * Export object, making it available for the remote calls at the + * specified port. + * + * Since jdk 1.5 this method does not longer require the stub class to be + * present. If such class is not found, the stub is replaced by the + * dynamically constructed proxy class. No attempt to find and load the stubs + * is made if the system property java.rmi.server.ignoreStubClasses + * is set to true (set to reduce the starting time if the stubs are + * surely not present and exclusively 1.2 RMI is used). + * + * @param obj the object being exported. + * @param port the remote object port + * + * @return the remote object stub + * + * @throws RemoteException if the attempt to export the object failed. + */ + public static Remote exportObject(Remote obj, int port) + throws RemoteException { return exportObject(obj, port, null); } - - static Remote exportObject(Remote obj, int port, RMIServerSocketFactory ssf) - throws RemoteException + + /** + * Create and export the new remote object, making it available at the + * given port, using sockets, produced by the specified factories. + * + * Since jdk 1.5 this method does not longer require the stub class to be + * present. If such class is not found, the stub is replaced by the + * dynamically constructed proxy class. No attempt to find and load the stubs + * is made if the system property java.rmi.server.ignoreStubClasses + * is set to true (set to reduce the starting time if the stubs are + * surely not present and exclusively 1.2 RMI is used). + * + * @param port the port, on that the object should become available. + * Zero means anonymous port. + * + * @param serverSocketFactory the server socket factory + */ + static Remote exportObject(Remote obj, int port, + RMIServerSocketFactory serverSocketFactory) + throws RemoteException { UnicastServerRef sref = null; if (obj instanceof RemoteObject) - sref = (UnicastServerRef)((RemoteObject)obj).getRef (); - if(sref == null) - { - sref = new UnicastServerRef(new ObjID (), port, ssf); - } - Remote stub = sref.exportObject (obj); + sref = (UnicastServerRef) ((RemoteObject) obj).getRef(); + + if (sref == null) + sref = new UnicastServerRef(new ObjID(), port, serverSocketFactory); + + Remote stub = sref.exportObject(obj); addStub(obj, stub); return stub; } @@ -106,8 +221,9 @@ public static RemoteStub exportObject(Remote obj) throws RemoteException { /** * FIXME */ - public static Remote exportObject(Remote obj, int port, RMIClientSocketFactory csf, - RMIServerSocketFactory ssf) + public static Remote exportObject(Remote obj, int port, + RMIClientSocketFactory csf, + RMIServerSocketFactory ssf) throws RemoteException { return (exportObject(obj, port, ssf)); @@ -118,14 +234,15 @@ public static RemoteStub exportObject(Remote obj) throws RemoteException { { if (obj instanceof RemoteObject) { - deleteStub(obj); - UnicastServerRef sref = (UnicastServerRef)((RemoteObject)obj).getRef(); - return sref.unexportObject(obj, force); + deleteStub(obj); + UnicastServerRef sref = + (UnicastServerRef) ((RemoteObject) obj).getRef(); + return sref.unexportObject(obj, force); } else { - //FIX ME - ; + // FIXME + ; } return true; } diff --git a/java/security/AlgorithmParameterGenerator.java b/java/security/AlgorithmParameterGenerator.java index 5dc9e3bb2..e33fbaf81 100644 --- a/java/security/AlgorithmParameterGenerator.java +++ b/java/security/AlgorithmParameterGenerator.java @@ -43,38 +43,15 @@ import gnu.java.security.Engine; import java.security.spec.AlgorithmParameterSpec; /** - *

      The AlgorithmParameterGenerator class is used to generate a - * set of parameters to be used with a certain algorithm. Parameter generators - * are constructed using the getInstance() factory methods (static - * methods that return instances of a given class).

      - * - *

      The object that will generate the parameters can be initialized in two - * different ways: in an algorithm-independent manner, or in an - * algorithm-specific manner:

      - * - *
        - *
      • The algorithm-independent approach uses the fact that all parameter - * generators share the concept of a "size" and a source of - * randomness. The measure of size is universally shared by all - * algorithm parameters, though it is interpreted differently for different - * algorithms. For example, in the case of parameters for the DSA - * algorithm, "size" corresponds to the size of the prime modulus (in - * bits). When using this approach, algorithm-specific parameter generation - * values - if any - default to some standard values, unless they can be - * derived from the specified size.
      • - *
      • The other approach initializes a parameter generator object using - * algorithm-specific semantics, which are represented by a set of - * algorithm-specific parameter generation values. To generate Diffie-Hellman - * system parameters, for example, the parameter generation values usually - * consist of the size of the prime modulus and the size of the random - * exponent, both specified in number of bits.
      • - *
      - * + * AlgorithmParameterGenerator is used to generate algorithm + * parameters for specified algorithms. + * *

      In case the client does not explicitly initialize the - * AlgorithmParameterGenerator (via a call to an init() - * method), each provider must supply (and document) a default initialization. - * For example, the GNU provider uses a default modulus prime size of - * 1024 bits for the generation of DSA parameters. + * AlgorithmParameterGenerator (via a call to an + * init() method), each provider must supply (and document) a + * default initialization. For example, the GNU provider uses a default + * modulus prime size of 1024 bits for the generation of DSA + * parameters. * * @author Mark Benvenuto * @since 1.2 @@ -92,11 +69,14 @@ public class AlgorithmParameterGenerator private String algorithm; /** - * Creates an AlgorithmParameterGenerator object. - * - * @param paramGenSpi the delegate. - * @param provider the provider. - * @param algorithm the algorithm. + * Constructs a new instance of AlgorithmParameterGenerator. + * + * @param paramGenSpi + * the generator to use. + * @param provider + * the provider to use. + * @param algorithm + * the algorithm to use. */ protected AlgorithmParameterGenerator(AlgorithmParameterGeneratorSpi paramGenSpi, Provider provider, @@ -107,30 +87,21 @@ public class AlgorithmParameterGenerator this.algorithm = algorithm; } - /** - * Returns the standard name of the algorithm this parameter generator is - * associated with. - * - * @return the string name of the algorithm. - */ + /** @return the name of the algorithm. */ public final String getAlgorithm() { return algorithm; } /** - * Generates an AlgorithmParameterGenerator object that - * implements the specified digest algorithm. If the default provider package - * provides an implementation of the requested digest algorithm, an instance - * of AlgorithmParameterGenerator containing that implementation - * is returned. If the algorithm is not available in the default package, - * other packages are searched. - * - * @param algorithm the string name of the algorithm this parameter generator - * is associated with. - * @return the new AlgorithmParameterGenerator object. - * @throws NoSuchAlgorithmException if the algorithm is not available in the - * environment. + * Returns a new AlgorithmParameterGenerator instance which + * generates algorithm parameters for the specified algorithm. + * + * @param algorithm + * the name of algorithm to use. + * @return the new instance. + * @throws NoSuchAlgorithmException + * if algorithm is not implemented by any provider. */ public static AlgorithmParameterGenerator getInstance(String algorithm) throws NoSuchAlgorithmException @@ -150,20 +121,18 @@ public class AlgorithmParameterGenerator } /** - * Generates an AlgorithmParameterGenerator object for the - * requested algorithm, as supplied from the specified provider, if such a - * parameter generator is available from the provider. - * - * @param algorithm the string name of the algorithm. - * @param provider the string name of the provider. - * @return the new AlgorithmParameterGenerator object. - * @throws NoSuchAlgorithmException if the algorithm is not - * available from the provider. - * @throws NoSuchProviderException if the provider is not - * available in the environment. - * @throws IllegalArgumentException if the provider name is - * null or empty. - * @see Provider + * Returns a new AlgorithmParameterGenerator instance which + * generates algorithm parameters for the specified algorithm. + * + * @param algorithm + * the name of algorithm to use. + * @param provider + * the name of the {@link Provider} to use. + * @return the new instance. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by the named provider. + * @throws NoSuchProviderException + * if the named provider was not found. */ public static AlgorithmParameterGenerator getInstance(String algorithm, String provider) @@ -180,17 +149,16 @@ public class AlgorithmParameterGenerator } /** - * Generates an AlgorithmParameterGenerator object for the requested - * algorithm, as supplied from the specified provider, if such a parameter - * generator is available from the provider. Note: the provider - * doesn't have to be registered. - * - * @param algorithm the string name of the algorithm. - * @param provider the provider. - * @return the new AlgorithmParameterGenerator object. - * @throws NoSuchAlgorithmException if the algorithm is not available from - * the provider. - * @throws IllegalArgumentException if the provider is null. + * Returns a new AlgorithmParameterGenerator instance which + * generates algorithm parameters for the specified algorithm. + * + * @param algorithm + * the name of algorithm to use. + * @param provider + * the {@link Provider} to use. + * @return the new instance. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by {@link Provider}. * @since 1.4 * @see Provider */ @@ -218,24 +186,18 @@ public class AlgorithmParameterGenerator } } - /** - * Returns the provider of this algorithm parameter generator object. - * - * @return the provider of this algorithm parameter generator object. - */ + /** @return the {@link Provider} of this generator. */ public final Provider getProvider() { return provider; } /** - * Initializes this parameter generator for a certain size. To create - * the parameters, the {@link SecureRandom} implementation of the - * highest-priority installed provider is used as the source of randomness. - * (If none of the installed providers supply an implementation of - * {@link SecureRandom}, a system-provided source of randomness is used.) - * - * @param size the size (number of bits). + * Initializes this instance with the specified size. Since no source of + * randomness is supplied, a default one will be used. + * + * @param size + * size (in bits) to use. */ public final void init(int size) { @@ -243,11 +205,13 @@ public class AlgorithmParameterGenerator } /** - * Initializes this parameter generator for a certain size and source of + * Initializes this instance with the specified key-size and source of * randomness. - * - * @param size the size (number of bits). - * @param random the source of randomness. + * + * @param size + * the size (in bits) to use. + * @param random + * the {@link SecureRandom} to use. */ public final void init(int size, SecureRandom random) { @@ -255,33 +219,30 @@ public class AlgorithmParameterGenerator } /** - * Initializes this parameter generator with a set of algorithm-specific - * parameter generation values. To generate the parameters, the {@link - * SecureRandom} implementation of the highest-priority installed provider is - * used as the source of randomness. (If none of the installed providers - * supply an implementation of {@link SecureRandom}, a system-provided source - * of randomness is used.) - * - * @param genParamSpec the set of algorithm-specific parameter generation - * values. - * @throws InvalidAlgorithmParameterException if the given parameter - * generation values are inappropriate for this parameter generator. + * Initializes this instance with the specified {@link AlgorithmParameterSpec}. + * Since no source of randomness is supplied, a default one will be used. + * + * @param genParamSpec + * the {@link AlgorithmParameterSpec} to use. + * @throws InvalidAlgorithmParameterException + * if genParamSpec is invalid. */ public final void init(AlgorithmParameterSpec genParamSpec) - throws InvalidAlgorithmParameterException + throws InvalidAlgorithmParameterException { init(genParamSpec, new SecureRandom()); } /** - * Initializes this parameter generator with a set of algorithm-specific - * parameter generation values. - * - * @param genParamSpec the set of algorithm-specific parameter generation - * values. - * @param random the source of randomness. - * @throws InvalidAlgorithmParameterException if the given parameter - * generation values are inappropriate for this parameter generator. + * Initializes this instance with the specified {@link AlgorithmParameterSpec} + * and source of randomness. + * + * @param genParamSpec + * the {@link AlgorithmParameterSpec} to use. + * @param random + * the {@link SecureRandom} to use. + * @throws InvalidAlgorithmParameterException + * if genParamSpec is invalid. */ public final void init(AlgorithmParameterSpec genParamSpec, SecureRandom random) @@ -290,11 +251,7 @@ public class AlgorithmParameterGenerator paramGenSpi.engineInit(genParamSpec, random); } - /** - * Generates the parameters. - * - * @return the new {@link AlgorithmParameters} object. - */ + /** @return a new instance of {@link AlgorithmParameters}. */ public final AlgorithmParameters generateParameters() { return paramGenSpi.engineGenerateParameters(); diff --git a/java/security/AlgorithmParameters.java b/java/security/AlgorithmParameters.java index 385f15789..911c566c8 100644 --- a/java/security/AlgorithmParameters.java +++ b/java/security/AlgorithmParameters.java @@ -45,36 +45,9 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; /** - *

      This class is used as an opaque representation of cryptographic - * parameters.

      - * - *

      An AlgorithmParameters object for managing the parameters - * for a particular algorithm can be obtained by calling one of the - * getInstance() factory methods (static methods that return - * instances of a given class).

      - * - *

      There are two ways to request such an implementation: by specifying - * either just an algorithm name, or both an algorithm name and a package - * provider.

      - * - *
        - *
      • If just an algorithm name is specified, the system will determine if - * there is an AlgorithmParameters implementation for the algorithm requested - * available in the environment, and if there is more than one, if there is - * a preferred one.
      • - *
      • If both an algorithm name and a package provider are specified, the - * system will determine if there is an implementation in the package - * requested, and throw an exception if there is not.
      • - *
      - * - *

      Once an AlgorithmParameters object is returned, it must be - * initialized via a call to init(), using an appropriate - * parameter specification or parameter encoding.

      - * - *

      A transparent parameter specification is obtained from an - * AlgorithmParameters object via a call to - * getParameterSpec(), and a byte encoding of the parameters is - * obtained via a call to getEncoded().

      + * AlgorithmParameters is an Algorithm Parameters class which + * provides an interface through which the user can manage the parameters of an + * Algorithm. * * @author Mark Benvenuto * @since 1.2 @@ -92,11 +65,14 @@ public class AlgorithmParameters private String algorithm; /** - * Creates an AlgorithmParameters object. - * - * @param paramSpi the delegate. - * @param provider the provider. - * @param algorithm the algorithm. + * Constructs a new instance of AlgorithmParameters. + * + * @param paramSpi + * the engine to use. + * @param provider + * the provider to use. + * @param algorithm + * the algorithm to use. */ protected AlgorithmParameters(AlgorithmParametersSpi paramSpi, Provider provider, String algorithm) @@ -106,32 +82,24 @@ public class AlgorithmParameters this.algorithm = algorithm; } - /** - * Returns the name of the algorithm associated with this parameter object. - * - * @return the algorithm name. - */ + /** @return A string with the name of the algorithm used. */ public final String getAlgorithm() { return algorithm; } /** - *

      Generates a parameter object for the specified algorithm.

      - * - *

      If the default provider package provides an implementation of the - * requested algorithm, an instance of AlgorithmParameters - * containing that implementation is returned. If the algorithm is not - * available in the default package, other packages are searched.

      - * - *

      The returned parameter object must be initialized via a call to - * init(), using an appropriate parameter specification or - * parameter encoding.

      - * - * @param algorithm the name of the algorithm requested. - * @return the new parameter object. - * @throws NoSuchAlgorithmException if the algorithm is not available in the - * environment. + * Returns a new instance of AlgorithmParameters representing + * the specified algorithm parameters. + * + *

      The returned AlgorithmParameters must still be initialized + * with an init() method.

      + * + * @param algorithm + * the algorithm to use. + * @return the new instance repesenting the desired algorithm. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by any provider. */ public static AlgorithmParameters getInstance(String algorithm) throws NoSuchAlgorithmException @@ -152,23 +120,24 @@ public class AlgorithmParameters } /** - *

      Generates a parameter object for the specified algorithm, as supplied - * by the specified provider, if such an algorithm is available from the - * provider.

      - * - *

      The returned parameter object must be initialized via a call to - * init(), using an appropriate parameter specification or - * parameter encoding.

      - * - * @param algorithm the name of the algorithm requested. - * @param provider the name of the provider. - * @return the new parameter object. - * @throws NoSuchAlgorithmException if the algorithm is not available in the - * package supplied by the requested provider. - * @throws NoSuchProviderException if the provider is not available in the - * environment. - * @throws IllegalArgumentException if the provider name is null or empty. - * @see Provider + * Returns a new instance of AlgorithmParameters representing + * the specified algorithm parameters from a named provider. + * + *

      The returned AlgorithmParameters must still be intialized + * with an init() method.

      + * + * @param algorithm + * the algorithm to use. + * @param provider + * the name of the {@link Provider} to use. + * @return the new instance repesenting the desired algorithm. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by the named provider. + * @throws NoSuchProviderException + * if the named provider was not found. + * @throws IllegalArgumentException + * if provider is null or is an empty + * string. */ public static AlgorithmParameters getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException @@ -184,18 +153,21 @@ public class AlgorithmParameters } /** - * Generates an AlgorithmParameterGenerator object for the - * requested algorithm, as supplied from the specified provider, if such a - * parameter generator is available from the provider. Note: the - * provider doesn't have to be registered. - * - * @param algorithm the string name of the algorithm. - * @param provider the provider. - * @return the new AlgorithmParameterGenerator object. - * @throws NoSuchAlgorithmException if the algorithm is not - * available from the provider. - * @throws IllegalArgumentException if the provider is - * null. + * Returns a new instance of AlgorithmParameters representing + * the specified algorithm parameters from the specified {@link Provider}. + * + *

      The returned AlgorithmParameters must still be intialized + * with an init() method.

      + * + * @param algorithm + * the algorithm to use. + * @param provider + * the {@link Provider} to use. + * @return the new instance repesenting the desired algorithm. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by the {@link Provider}. + * @throws IllegalArgumentException + * if provider is null. * @since 1.4 */ public static AlgorithmParameters getInstance(String algorithm, @@ -221,24 +193,19 @@ public class AlgorithmParameters } } - /** - * Returns the provider of this parameter object. - * - * @return the provider of this parameter object. - */ + /** @return the provider of this parameter object. */ public final Provider getProvider() { return provider; } /** - * Initializes this parameter object using the parameters specified in - * paramSpec. - * - * @param paramSpec the parameter specification. - * @throws InvalidParameterSpecException if the given parameter specification - * is inappropriate for the initialization of this parameter object, or if - * this parameter object has already been initialized. + * Initializes the engine with the specified {@link AlgorithmParameterSpec}. + * + * @param paramSpec + * A {@link AlgorithmParameterSpec} to use. + * @throws InvalidParameterSpecException + * if paramSpec is invalid. */ public final void init(AlgorithmParameterSpec paramSpec) throws InvalidParameterSpecException @@ -247,13 +214,15 @@ public class AlgorithmParameters } /** - * Imports the specified parameters and decodes them according to the primary - * decoding format for parameters. The primary decoding format for parameters - * is ASN.1, if an ASN.1 specification for this type of parameters exists. - * - * @param params the encoded parameters. - * @throws IOException on decoding errors, or if this parameter object has - * already been initialized. + * Initializes the engine with the specified parameters stored in the byte + * array and decodes them according to the ASN.1 specification. If the ASN.1 + * specification exists then it succeeds otherwise an {@link IOException} is + * thrown. + * + * @param params + * the parameters to use. + * @throws IOException + * if a decoding error occurs. */ public final void init(byte[]params) throws IOException { @@ -261,15 +230,18 @@ public class AlgorithmParameters } /** - * Imports the parameters from params and decodes them according to the - * specified decoding scheme. If format is null, - * the primary decoding format for parameters is used. The primary decoding - * format is ASN.1, if an ASN.1 specification for these parameters exists. - * - * @param params the encoded parameters. - * @param format the name of the decoding scheme. - * @throws IOException on decoding errors, or if this parameter object has - * already been initialized. + * Initializes the engine with the specified parameters stored in the byte + * array and decodes them according to the specified decoding specification. + * If format is null, then this method decodes the + * byte array using the ASN.1 specification if it exists, otherwise it throws + * an {@link IOException}. + * + * @param params + * the parameters to use. + * @param format + * the name of decoding format to use. + * @throws IOException + * if a decoding error occurs. */ public final void init(byte[]params, String format) throws IOException { @@ -277,19 +249,14 @@ public class AlgorithmParameters } /** - * Returns a (transparent) specification of this parameter object. - * paramSpec identifies the specification class in which the - * parameters should be returned. It could, for example, be - * DSAParameterSpec.class, to indicate that the parameters should - * be returned in an instance of the {@link java.security.spec.DSAParameterSpec} - * class. - * - * @param paramSpec the specification class in which the parameters should be - * returned. + * Returns a new instance of AlgorithmParameters as a + * designated parameter specification {@link Class}. + * + * @param paramSpec + * the {@link Class} to use. * @return the parameter specification. - * @throws InvalidParameterSpecException if the requested parameter - * specification is inappropriate for this parameter object, or if this - * parameter object has not been initialized. + * @throws InvalidParameterSpecException + * if paramSpec is invalid. */ public final T getParameterSpec(Class paramSpec) @@ -299,13 +266,10 @@ public class AlgorithmParameters } /** - * Returns the parameters in their primary encoding format. The primary - * encoding format for parameters is ASN.1, if an ASN.1 specification for - * this type of parameters exists. - * - * @return the parameters encoded using their primary encoding format. - * @throws IOException on encoding errors, or if this parameter object has not - * been initialized. + * Returns the parameters in the default encoding format. The primary encoding + * format is ASN.1 if it exists for the specified type. + * + * @return byte array representing the parameters. */ public final byte[] getEncoded() throws IOException { @@ -313,15 +277,16 @@ public class AlgorithmParameters } /** - * Returns the parameters encoded in the specified scheme. If format is - * null, the primary encoding format for parameters is used. The - * primary encoding format is ASN.1, if an ASN.1 specification for these - * parameters exists. - * - * @param format the name of the encoding format. + * Returns the parameters in the specified encoding format. If + * format is null then the ASN.1 encoding + * format is used if it exists for the specified type. + * + * @param format + * the name of the encoding format to use. * @return the parameters encoded using the specified encoding scheme. - * @throws IOException on encoding errors, or if this parameter object has - * not been initialized. + * @throws IOException + * if an encoding exception occurs, or if this parameter object has + * not been initialized. */ public final byte[] getEncoded(String format) throws IOException { @@ -329,10 +294,9 @@ public class AlgorithmParameters } /** - * Returns a formatted string describing the parameters. - * - * @return a formatted string describing the parameters, or null - * if this parameter object has not been initialized. + * Returns a string representation of the encoded form. + * + * @return a string representation of the encoded form. */ public final String toString() { diff --git a/java/security/Identity.java b/java/security/Identity.java index 7ef59cfe2..c9df0a58f 100644 --- a/java/security/Identity.java +++ b/java/security/Identity.java @@ -41,31 +41,27 @@ import java.io.Serializable; import java.util.Vector; /** - *

      This class represents identities: real-world objects such as people, - * companies or organizations whose identities can be authenticated using their - * public keys. Identities may also be more abstract (or concrete) constructs, - * such as daemon threads or smart cards.

      - * - *

      All Identity objects have a name and a public key. Names - * are immutable. Identities may also be scoped. That is, if an - * Identity is specified to have a particular scope, then the - * name and public key of the Identity are unique within - * that scope.

      - * - *

      An Identity also has a set of certificates (all certifying - * its own public key). The Principal names specified in these - * certificates need not be the same, only the key.

      - * - *

      An Identity can be subclassed, to include postal and email - * addresses, telephone numbers, images of faces and logos, and so on.

      + * The Identity class is used to represent people and companies + * that can be authenticated using public key encryption. The identities can + * also be abstract objects such as smart cards. + * + *

      Identity objects store a name and public key for each + * identity. The names cannot be changed and the identities can be scoped. Each + * identity (name and public key) within a scope are unique to that scope.

      + * + *

      Each identity has a set of ceritificates which all specify the same + * public key, but not necessarily the same name.

      + * + *

      The Identity class can be subclassed to allow additional + * information to be attached to it.

      * * @author Mark Benvenuto * @see IdentityScope * @see Signer * @see Principal - * @deprecated This class is no longer used. Its functionality has been replaced - * by java.security.KeyStore, the java.security.cert - * package, and java.security.Principal. + * @deprecated Replaced by java.security.KeyStore, the + * java.security.cert package, and + * java.security.Principal. */ public abstract class Identity implements Principal, Serializable { @@ -83,12 +79,15 @@ public abstract class Identity implements Principal, Serializable } /** - * Constructs an identity with the specified name and scope. - * - * @param name the identity name. - * @param scope the scope of the identity. - * @throws KeyManagementException if there is already an identity with the - * same name in the scope. + * Constructs a new instance of Identity with the specified + * name and scope. + * + * @param name + * the name to use. + * @param scope + * the scope to use. + * @throws KeyManagementException + * if the identity is already present. */ public Identity(String name, IdentityScope scope) throws KeyManagementException @@ -98,9 +97,11 @@ public abstract class Identity implements Principal, Serializable } /** - * Constructs an identity with the specified name and no scope. - * - * @param name the identity name. + * Constructs a new instance of Identity with the specified + * name and no scope. + * + * @param name + * the name to use. */ public Identity(String name) { @@ -108,30 +109,20 @@ public abstract class Identity implements Principal, Serializable this.scope = null; } - /** - * Returns this identity's name. - * - * @return the name of this identity. - */ + /** @return the name of this identity. */ public final String getName() { return name; } - /** - * Returns this identity's scope. - * - * @return the scope of this identity. - */ + /** @return the scope of this identity. */ public final IdentityScope getScope() { return scope; } /** - * Returns this identity's public key. - * - * @return the public key for this identity. + * @return the public key of this identity. * @see #setPublicKey(java.security.PublicKey) */ public PublicKey getPublicKey() @@ -140,21 +131,17 @@ public abstract class Identity implements Principal, Serializable } /** - *

      Sets this identity's public key. The old key and all of this identity's - * certificates are removed by this operation.

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with "setIdentityPublicKey" as its - * argument to see if it's ok to set the public key.

      - * - * @param key the public key for this identity. - * @throws KeyManagementException if another identity in the identity's scope - * has the same public key, or if another exception occurs. - * @throws SecurityException if a security manager exists and its - * checkSecurityAccess() method doesn't allow setting the public - * key. - * @see #getPublicKey() - * @see SecurityManager#checkSecurityAccess(String) + * Sets the public key for this identity. The old key and all certificates + * are removed. + * + * @param key + * the public key to use. + * @throws KeyManagementException + * if this public key is used by another identity in the current + * scope. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public void setPublicKey(PublicKey key) throws KeyManagementException { @@ -166,18 +153,13 @@ public abstract class Identity implements Principal, Serializable } /** - *

      Specifies a general information string for this identity.

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with "setIdentityInfo" as its - * argument to see if it's ok to specify the information string.

      - * - * @param info the information string. - * @throws SecurityException if a security manager exists and its - * checkSecurityAccess() method doesn't allow setting the - * information string. - * @see #getInfo() - * @see SecurityManager#checkSecurityAccess(String) + * Sets the general information string. + * + * @param info + * the general information string. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public void setInfo(String info) { @@ -189,9 +171,7 @@ public abstract class Identity implements Principal, Serializable } /** - * Returns general information previously specified for this identity. - * - * @return general information about this identity. + * @return the general information string of this identity. * @see #setInfo(String) */ public String getInfo() @@ -200,23 +180,17 @@ public abstract class Identity implements Principal, Serializable } /** - *

      Adds a certificate for this identity. If the identity has a public key, - * the public key in the certificate must be the same, and if the identity - * does not have a public key, the identity's public key is set to be that - * specified in the certificate.

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with "addIdentityCertificate" as its - * argument to see if it's ok to add a certificate.

      - * - * @param certificate the certificate to be added. - * @throws KeyManagementException if the certificate is not valid, if the - * public key in the certificate being added conflicts with this identity's - * public key, or if another exception occurs. - * @throws SecurityException if a security manager exists and its - * checkSecurityAccess() method doesn't allow adding a - * certificate. - * @see SecurityManager#checkSecurityAccess(String) + * Adds a certificate to the list of ceritificates for this identity. The + * public key in this certificate must match the existing public key if it + * exists. + * + * @param certificate + * the certificate to add. + * @throws KeyManagementException + * if the certificate is invalid, or the public key conflicts. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public void addCertificate(Certificate certificate) throws KeyManagementException @@ -235,19 +209,15 @@ public abstract class Identity implements Principal, Serializable } /** - *

      Removes a certificate from this identity.

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with "removeIdentityCertificate" as - * its argument to see if it's ok to remove a certificate.

      - * - * @param certificate the certificate to be removed. - * @throws KeyManagementException if the certificate is missing, or if - * another exception occurs. - * @throws SecurityException if a security manager exists and its - * checkSecurityAccess() method doesn't allow removing a - * certificate. - * @see SecurityManager#checkSecurityAccess(String) + * Removes a certificate from the list of ceritificates for this identity. + * + * @param certificate + * the certificate to remove. + * @throws KeyManagementException + * if the certificate is invalid. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public void removeCertificate(Certificate certificate) throws KeyManagementException @@ -262,11 +232,7 @@ public abstract class Identity implements Principal, Serializable certificates.removeElement(certificate); } - /** - * Returns a copy of all the certificates for this identity. - * - * @return a copy of all the certificates for this identity. - */ + /** @return an array of {@link Certificate}s for this identity. */ public Certificate[] certificates() { Certificate[] certs = new Certificate[certificates.size()]; @@ -278,17 +244,13 @@ public abstract class Identity implements Principal, Serializable } /** - * Tests for equality between the specified object and this identity. This - * first tests to see if the entities actually refer to the same object, in - * which case it returns true. Next, it checks to see if the - * entities have the same name and the same scope. If they do, - * the method returns true. Otherwise, it calls - * identityEquals(), which subclasses should override. - * - * @param identity the object to test for equality with this identity. - * @return true if the objects are considered equal, false - * otherwise. - * @see #identityEquals(Identity) + * Checks for equality between this Identity and a specified object. It first + * checks if they are the same object, then if the name and scope match and + * returns true if successful. If these tests fail, the + * {@link #identityEquals(Identity)} method is called. + * + * @return true if they are equal, false + * otherwise. */ public final boolean equals(Object identity) { @@ -307,15 +269,12 @@ public abstract class Identity implements Principal, Serializable } /** - * Tests for equality between the specified identity and this - * identity. This method should be overriden by subclasses to test for - * equality. The default behavior is to return true if the names - * and public keys are equal. - * - * @param identity the identity to test for equality with this identity. - * @return true if the identities are considered equal, - * false otherwise. - * @see #equals(Object) + * Checks for equality between this Identity and a specified object. A + * subclass should override this method. The default behavior is to return + * true if the public key and names match. + * + * @return true if they are equal, false + * otherwise. */ protected boolean identityEquals(Identity identity) { @@ -324,19 +283,12 @@ public abstract class Identity implements Principal, Serializable } /** - *

      Returns a short string describing this identity, telling its name and - * its scope (if any).

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with "printIdentity" as its argument - * to see if it's ok to return the string.

      - * - * @return information about this identity, such as its name and the name of - * its scope (if any). - * @throws SecurityException if a security manager exists and its - * checkSecurityAccess() method doesn't allow returning a string - * describing this identity. - * @see SecurityManager#checkSecurityAccess(String) + * Returns a string representation of this Identity. + * + * @return a string representation of this Identity. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public String toString() { @@ -349,23 +301,14 @@ public abstract class Identity implements Principal, Serializable } /** - *

      Returns a string representation of this identity, with optionally more - * details than that provided by the toString() method without - * any arguments.

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with "printIdentity" as its argument - * to see if it's ok to return the string.

      - * - * @param detailed whether or not to provide detailed information. - * @return information about this identity. If detailed is true, - * then this method returns more information than that provided by the - * toString() method without any arguments. - * @throws SecurityException if a security manager exists and its - * checkSecurityAccess() method doesn't allow returning a string - * describing this identity. - * @see #toString() - * @see SecurityManager#checkSecurityAccess(String) + * Returns a detailed string representation of this Identity. + * + * @param detailed + * indicates whether or detailed information is desired. + * @return a string representation of this Identity. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public String toString(boolean detailed) { @@ -385,11 +328,7 @@ public abstract class Identity implements Principal, Serializable } } - /** - * Returns a hashcode for this identity. - * - * @return a hashcode for this identity. - */ + /** @return a hashcode of this identity. */ public int hashCode() { int ret = name.hashCode(); diff --git a/java/security/IdentityScope.java b/java/security/IdentityScope.java index 4b19d26e1..610d3534c 100644 --- a/java/security/IdentityScope.java +++ b/java/security/IdentityScope.java @@ -40,52 +40,42 @@ package java.security; import java.util.Enumeration; /** - *

      This class represents a scope for identities. It is an Identity itself, - * and therefore has a name and can have a scope. It can also optionally have a - * public key and associated certificates.

      - * - *

      An IdentityScope can contain {@link Identity} objects of all - * kinds, including {@link Signer}s. All types of Identity objects - * can be retrieved, added, and removed using the same methods. Note that it is - * possible, and in fact expected, that different types of identity scopes will - * apply different policies for their various operations on the various types of + * IdentityScope represents a scope of an identity. + * IdentityScope is also an {@link Identity} and can have a name + * and scope along with the other qualitites identities possess. + * + *

      An IdentityScope contains other {@link Identity} objects. + * All {@link Identity} objects are manipulated in the scope the same way. The + * scope is supposed to apply different scope to different type of * Identities.

      - * - *

      There is a one-to-one mapping between keys and identities, and there can - * only be one copy of one key per scope. For example, suppose Acme Software, - * Inc is a software publisher known to a user. Suppose it is an Identity, - * that is, it has a public key, and a set of associated certificates. It is - * named in the scope using the name "Acme Software". No other named Identity - * in the scope has the same public key. Of course, none has the same name - * as well.

      - * + * + *

      No identity within the same scope can have the same public key.

      + * * @author Mark Benvenuto * @see Identity * @see Signer * @see Principal * @see Key - * @deprecated This class is no longer used. Its functionality has been replaced - * by java.security.KeyStore, the java.security.cert - * package, and java.security.Principal. + * @deprecated Use java.security.KeyStore, the java.security.cert package, and + * java.security.Principal. */ public abstract class IdentityScope extends Identity { private static final long serialVersionUID = -2337346281189773310L; private static IdentityScope systemScope; - /** - * This constructor is used for serialization only and should not be used by - * subclasses. - */ + /** Constructor for serialization purposes. */ protected IdentityScope() { super(); } /** - * Constructs a new identity scope with the specified name. - * - * @param name the scope name. + * Constructs a new instance of IdentityScope with the + * specified name and no scope. + * + * @param name + * the name to use. */ public IdentityScope(String name) { @@ -93,12 +83,15 @@ public abstract class IdentityScope extends Identity } /** - * Constructs a new identity scope with the specified name and scope. - * - * @param name the scope name. - * @param scope the scope for the new identity scope. - * @throws KeyManagementException if there is already an identity with the - * same name in the scope. + * Constructs a new instance of IdentityScope with the + * specified name and {@link IdentityScope}. + * + * @param name + * the name to use. + * @param scope + * the scope to use. + * @throws KeyManagementException + * if the identity scope is already present. */ public IdentityScope(String name, IdentityScope scope) throws KeyManagementException @@ -107,10 +100,9 @@ public abstract class IdentityScope extends Identity } /** - * Returns the system's identity scope. - * - * @return the system's identity scope. - * @see #setSystemScope(IdentityScope) + * Returns the system's Scope. + * + * @return the system's Scope. */ public static IdentityScope getSystemScope() { @@ -123,18 +115,13 @@ public abstract class IdentityScope extends Identity } /** - * Sets the system's identity scope. - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with "setSystemScope" as its argument - * to see if it's ok to set the identity scope.

      - * - * @param scope the scope to set. - * @throws SecurityException if a security manager exists and its - * checkSecurityAccess() method doesn't allow setting the - * identity scope. - * @see #getSystemScope() - * @see SecurityManager#checkSecurityAccess(String) + * Sets the scope of the system. + * + * @param scope + * the new system scope. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ protected static void setSystemScope(IdentityScope scope) { @@ -146,29 +133,30 @@ public abstract class IdentityScope extends Identity } /** - * Returns the number of identities within this identity scope. - * - * @return the number of identities within this identity scope. + * Returns the number of entries within this IdentityScope. + * + * @return the number of entries within this IdentityScope. */ public abstract int size(); /** - * Returns the identity in this scope with the specified name (if any). - * - * @param name the name of the identity to be retrieved. - * @return the identity named name, or null if there are no - * identities named name in this scope. + * Returns the specified {@link Identity}, by name, within this scope. + * + * @param name + * name of {@link Identity} to get. + * @return an {@link Identity} representing the name or null if + * it cannot be found. */ public abstract Identity getIdentity(String name); /** - * Retrieves the identity whose name is the same as that of the specified - * principal. (Note: Identity implements Principal.) - * - * @param principal the principal corresponding to the identity to be - * retrieved. - * @return the identity whose name is the same as that of the principal, or - * null if there are no identities of the same name in this scope. + * Returns the specified {@link Identity}, by {@link Principal}, within this + * scope. + * + * @param principal + * the {@link Principal} to use. + * @return an identity representing the {@link Principal} or null + * if it cannot be found. */ public Identity getIdentity(Principal principal) { @@ -176,48 +164,50 @@ public abstract class IdentityScope extends Identity } /** - * Retrieves the identity with the specified public key. - * - * @param key the public key for the identity to be returned. - * @return the identity with the given key, or null if there are - * no identities in this scope with that key. + * Returns the specified {@link Identity}, by public key, within this scope. + * + * @param key + * the {@link PublicKey} to use. + * @return an identity representing the public key or null if + * it cannot be found. */ public abstract Identity getIdentity(PublicKey key); /** - * Adds an identity to this identity scope. - * - * @param identity the identity to be added. - * @throws KeyManagementException if the identity is not valid, a name - * conflict occurs, another identity has the same public key as the identity - * being added, or another exception occurs. + * Adds an identity to his scope. + * + * @param identity + * the {@link Identity} to add. + * @throws KeyManagementException + * if it is an invalid identity, an identity with the same key + * exists, or if another error occurs. */ public abstract void addIdentity(Identity identity) throws KeyManagementException; /** - * Removes an identity from this identity scope. - * - * @param identity the identity to be removed. - * @throws KeyManagementException if the identity is missing, or another - * exception occurs. + * Removes an identity in this scope. + * + * @param identity + * the {@link Identity} to remove. + * @throws KeyManagementException + * if it is a missing identity, or if another error occurs. */ public abstract void removeIdentity(Identity identity) throws KeyManagementException; /** - * Returns an enumeration of all identities in this identity scope. - * - * @return an enumeration of all identities in this identity scope. + * Returns an {@link Enumeration} of identities in this scope. + * + * @return an {@link Enumeration} of the identities in this scope. */ public abstract Enumeration identities(); /** - * Returns a string representation of this identity scope, including its name, - * its scope name, and the number of identities in this identity scope. - * - * @return a string representation of this identity scope. - * @see SecurityManager#checkSecurityAccess(String) + * Returns a string representing this instance. It includes the name, the + * scope name, and number of identities. + * + * @return a string representation of this instance. */ public String toString() { diff --git a/java/security/KeyFactory.java b/java/security/KeyFactory.java index 3632b3e26..1ecfd2f72 100644 --- a/java/security/KeyFactory.java +++ b/java/security/KeyFactory.java @@ -44,40 +44,18 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; /** - *

      Key factories are used to convert keys (opaque cryptographic keys of type + * Key factories are used to convert keys (opaque cryptographic keys of type * {@link Key}) into key specifications (transparent representations of the - * underlying key material), and vice versa.

      - * - *

      Key factories are bi-directional. That is, they allow you to build an - * opaque key object from a given key specification (key material), or to - * retrieve the underlying key material of a key object in a suitable format.

      - * - *

      Multiple compatible key specifications may exist for the same key. For - * example, a DSA public key may be specified using {@link - * java.security.spec.DSAPublicKeySpec} or {@link - * java.security.spec.X509EncodedKeySpec}. A key factory can be used to - * translate between compatible key specifications.

      - * - *

      The following is an example of how to use a key factory in order to - * instantiate a DSA public key from its encoding. Assume Alice has - * received a digital signature from Bob. Bob also sent her his public key (in - * encoded format) to verify his signature. Alice then performs the following - * actions: - * - *

      - *  X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
      - *  KeyFactory keyFactory = KeyFactory.getInstance("DSA");
      - *  PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
      - *  Signature sig = Signature.getInstance("DSA");
      - *  sig.initVerify(bobPubKey);
      - *  sig.update(data);
      - *  sig.verify(signature);
      - * 
      + * underlying key material). + * + *

      Key factories are bi-directional. They allow a key class to be converted + * into a key specification (key material) and back again. For example DSA + * public keys can be specified as DSAPublicKeySpec or + * X509EncodedKeySpec. A key factory translates these key + * specifications.

      * * @since 1.2 * @see Key - * @see PublicKey - * @see PrivateKey * @see KeySpec * @see java.security.spec.DSAPublicKeySpec * @see java.security.spec.X509EncodedKeySpec @@ -93,12 +71,15 @@ public class KeyFactory private String algorithm; /** - * Creates a KeyFactory object. - * - * @param keyFacSpi the delegate. - * @param provider the provider. - * @param algorithm the name of the algorithm to associate with this - * KeyFactory. + * Constructs a new instance of KeyFactory with the specified + * parameters. + * + * @param keyFacSpi + * the key factory to use. + * @param provider + * the provider to use. + * @param algorithm + * the name of the key algorithm to use. */ protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider, String algorithm) @@ -109,19 +90,14 @@ public class KeyFactory } /** - * Generates a KeyFactory object that implements the specified - * algorithm. If the default provider package provides an implementation of - * the requested algorithm, an instance of KeyFactory containing - * that implementation is returned. If the algorithm is not available in the - * default package, other packages are searched. - * - * @param algorithm the name of the requested key algorithm. See Appendix A - * in the Java Cryptography Architecture API Specification & Reference - * for information about standard algorithm names. - * @return a KeyFactory object for the specified algorithm. - * @throws NoSuchAlgorithmException if the requested algorithm is not - * available in the default provider package or any of the other provider - * packages that were searched. + * Returns a new instance of KeyFactory representing the + * specified key factory. + * + * @param algorithm + * the name of algorithm to use. + * @return a new instance repesenting the desired algorithm. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by any provider. */ public static KeyFactory getInstance(String algorithm) throws NoSuchAlgorithmException @@ -141,19 +117,21 @@ public class KeyFactory } /** - * Generates a KeyFactory object for the specified algorithm - * from the specified provider. - * - * @param algorithm the name of the requested key algorithm. See Appendix A - * in the Java Cryptography Architecture API Specification & Reference - * for information about standard algorithm names. - * @param provider the name of the provider. - * @return a KeyFactory object for the specified algorithm. - * @throws NoSuchAlgorithmException if the algorithm is not available from - * the specified provider. - * @throws NoSuchProviderException if the provider has not been configured. - * @throws IllegalArgumentException if the provider name is null or empty. - * @see Provider + * Returns a new instance of KeyFactory representing the + * specified key factory from the specified provider. + * + * @param algorithm + * the name of algorithm to use. + * @param provider + * the name of the provider to use. + * @return a new instance repesenting the desired algorithm. + * @throws IllegalArgumentException + * if provider is null or is an empty + * string. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by the named provider. + * @throws NoSuchProviderException + * if the named provider was not found. */ public static KeyFactory getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException @@ -169,19 +147,18 @@ public class KeyFactory } /** - * Generates a KeyFactory object for the specified algorithm from - * the specified provider. Note: the provider doesn't have to be - * registered. - * - * @param algorithm the name of the requested key algorithm. See Appendix A - * in the Java Cryptography Architecture API Specification & Reference for - * information about standard algorithm names. - * @param provider the provider. - * @return a KeyFactory object for the specified algorithm. - * @throws NoSuchAlgorithmException if the algorithm is not available from - * the specified provider. - * @throws IllegalArgumentException if the provider is - * null. + * Returns a new instance of KeyFactory representing the + * specified key factory from the designated {@link Provider}. + * + * @param algorithm + * the name of algorithm to use. + * @param provider + * the {@link Provider} to use. + * @return a new instance repesenting the desired algorithm. + * @throws IllegalArgumentException + * if provider is null. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by {@link Provider}. * @since 1.4 * @see Provider */ @@ -208,9 +185,9 @@ public class KeyFactory } /** - * Returns the provider of this key factory object. - * - * @return the provider of this key factory object. + * Returns the {@link Provider} of this instance. + * + * @return the {@link Provider} of this instance. */ public final Provider getProvider() { @@ -218,10 +195,9 @@ public class KeyFactory } /** - * Gets the name of the algorithm associated with this KeyFactory. - * - * @return the name of the algorithm associated with this - * KeyFactory. + * Returns the name of the algorithm used. + * + * @return the name of the algorithm used. */ public final String getAlgorithm() { @@ -229,13 +205,13 @@ public class KeyFactory } /** - * Generates a public key object from the provided key specification (key - * material). - * - * @param keySpec the specification (key material) of the public key. + * Generates a public key from the provided key specification. + * + * @param keySpec + * the key specification. * @return the public key. - * @throws InvalidKeySpecException if the given key specification is - * inappropriate for this key factory to produce a public key. + * @throws InvalidKeySpecException + * if the key specification is invalid. */ public final PublicKey generatePublic(KeySpec keySpec) throws InvalidKeySpecException @@ -244,13 +220,13 @@ public class KeyFactory } /** - * Generates a private key object from the provided key specification (key - * material). - * - * @param keySpec the specification (key material) of the private key. + * Generates a private key from the provided key specification. + * + * @param keySpec + * the key specification. * @return the private key. - * @throws InvalidKeySpecException if the given key specification is - * inappropriate for this key factory to produce a private key. + * @throws InvalidKeySpecException + * if the key specification is invalid. */ public final PrivateKey generatePrivate(KeySpec keySpec) throws InvalidKeySpecException @@ -259,21 +235,18 @@ public class KeyFactory } /** - * Returns a specification (key material) of the given key object. - * keySpec identifies the specification class in which the key - * material should be returned. It could, for example, be - * DSAPublicKeySpec.class, to indicate that the key material - * should be returned in an instance of the {@link - * java.security.spec.DSAPublicKeySpec} class. - * - * @param key the key. - * @param keySpec the specification class in which the key material should be - * returned. - * @return the underlying key specification (key material) in an instance of - * the requested specification class. - * @throws InvalidKeySpecException if the requested key specification is - * inappropriate for the given key, or the given key cannot be processed - * (e.g., the given key has an unrecognized algorithm or format). + * Returns a key specification for the given key. keySpec + * identifies the specification class to return the key material in. + * + * @param key + * the key to use. + * @param keySpec + * the specification class to use. + * @return the key specification in an instance of the requested specification + * class. + * @throws InvalidKeySpecException + * the requested key specification is inappropriate for this key or + * the key is unrecognized. */ public final T getKeySpec(Key key, Class keySpec) throws InvalidKeySpecException @@ -282,13 +255,14 @@ public class KeyFactory } /** - * Translates a key object, whose provider may be unknown or potentially - * untrusted, into a corresponding key object of this key factory. - * - * @param key the key whose provider is unknown or untrusted. + * Translates the key from an unknown or untrusted provider into a key from + * this key factory. + * + * @param key + * the key to translate from. * @return the translated key. - * @throws InvalidKeyException if the given key cannot be processed by this - * key factory. + * @throws InvalidKeyException + * if the key cannot be processed by this key factory. */ public final Key translateKey(Key key) throws InvalidKeyException { diff --git a/java/security/KeyPairGenerator.java b/java/security/KeyPairGenerator.java index a6e010be2..357d7a75f 100644 --- a/java/security/KeyPairGenerator.java +++ b/java/security/KeyPairGenerator.java @@ -43,72 +43,14 @@ import gnu.java.security.Engine; import java.security.spec.AlgorithmParameterSpec; /** - *

      The KeyPairGenerator class is used to generate pairs of - * public and private keys. Key pair generators are constructed using the - * getInstance() factory methods (static methods that return - * instances of a given class).

      + * KeyPairGenerator is a class used to generate key-pairs for a + * security algorithm. + * + *

      The KeyPairGenerator is created with the + * getInstance() Factory methods. It is used to generate a pair of + * public and private keys for a specific algorithm and associate this key-pair + * with the algorithm parameters it was initialized with.

      * - *

      A Key pair generator for a particular algorithm creates a public/private - * key pair that can be used with this algorithm. It also associates - * algorithm-specific parameters with each of the generated keys.

      - * - *

      There are two ways to generate a key pair: in an algorithm-independent - * manner, and in an algorithm-specific manner. The only difference between the - * two is the initialization of the object:

      - * - *
        - *
      • Algorithm-Independent Initialization
        - * All key pair generators share the concepts of a keysize and a - * source of randomness. The keysize is interpreted differently - * for different algorithms (e.g., in the case of the DSA algorithm, - * the keysize corresponds to the length of the modulus). There is an - * initialize() method in this KeyPairGenerator - * class that takes these two universally shared types of arguments. There - * is also one that takes just a keysize argument, and uses the - * {@link SecureRandom} implementation of the highest-priority installed - * provider as the source of randomness. (If none of the installed - * providers supply an implementation of {@link SecureRandom}, a - * system-provided source of randomness is used.) - * - *

        Since no other parameters are specified when you call the above - * algorithm-independent initialize methods, it is up to the provider what - * to do about the algorithm-specific parameters (if any) to be associated - * with each of the keys.

        - * - *

        If the algorithm is the DSA algorithm, and the keysize - * (modulus size) is 512, 768, or 1024, - * then the GNU provider uses a set of precomputed values for the - * p, q, and g parameters. If the - * modulus size is not one of the above values, the GNU - * provider creates a new set of parameters. Other providers might have - * precomputed parameter sets for more than just the three modulus sizes - * mentioned above. Still others might not have a list of precomputed - * parameters at all and instead always create new parameter sets.

      • - *
      • Algorithm-Specific Initialization
        - * For situations where a set of algorithm-specific parameters already - * exists (e.g., so-called community parameters in DSA), there - * are two initialize methods that have an {@link AlgorithmParameterSpec} - * argument. One also has a {@link SecureRandom} argument, while the the - * other uses the {@link SecureRandom} implementation of the highest-priority - * installed provider as the source of randomness. (If none of the installed - * providers supply an implementation of {@link SecureRandom}, a - * system-provided source of randomness is used.)
      • - *
      - * - *

      In case the client does not explicitly initialize the - * KeyPairGenerator (via a call to an initialize method), each - * provider must supply (and document) a default initialization. For example, - * the GNU provider uses a default modulus size (keysize) of - * 1024 bits.

      - * - *

      Note that this class is abstract and extends from {@link - * KeyPairGeneratorSpi} for historical reasons. Application developers should - * only take notice of the methods defined in this KeyPairGenerator - * class; all the methods in the superclass are intended for cryptographic - * service providers who wish to supply their own implementations of key pair - * generators.

      - * - * @see Signature * @see KeyPair * @see AlgorithmParameterSpec * @author Mark Benvenuto @@ -123,13 +65,10 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi private String algorithm; /** - * Creates a KeyPairGenerator object for the specified - * algorithm. - * - * @param algorithm the standard string name of the algorithm. - * See Appendix A in the Java Cryptography Architecture API - * Specification & Reference for information about standard - * algorithm names. + * Constructs a new instance of KeyPairGenerator. + * + * @param algorithm + * the algorithm to use. */ protected KeyPairGenerator(String algorithm) { @@ -138,11 +77,9 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } /** - * Returns the standard name of the algorithm for this key pair generator. - * See Appendix A in the Java Cryptography Architecture API Specification - * & Reference for information about standard algorithm names. - * - * @return the standard string name of the algorithm. + * Returns the name of the algorithm used. + * + * @return the name of the algorithm used. */ public String getAlgorithm() { @@ -150,19 +87,14 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } /** - * Generates a KeyPairGenerator object that implements the - * specified digest algorithm. If the default provider package provides an - * implementation of the requested digest algorithm, an instance of - * KeyPairGenerator containing that implementation is returned. - * If the algorithm is not available in the default package, other packages - * are searched. - * - * @param algorithm the standard string name of the algorithm. See Appendix A - * in the Java Cryptography Architecture API Specification & Reference for - * information about standard algorithm names. - * @return the new KeyPairGenerator object. - * @throws NoSuchAlgorithmException if the algorithm is not available in the - * environment. + * Returns a new instance of KeyPairGenerator which generates + * key-pairs for the specified algorithm. + * + * @param algorithm + * the name of the algorithm to use. + * @return a new instance repesenting the desired algorithm. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by any provider. */ public static KeyPairGenerator getInstance(String algorithm) throws NoSuchAlgorithmException @@ -184,22 +116,18 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } /** - * Generates a KeyPairGenerator object implementing the - * specified algorithm, as supplied from the specified provider, if - * such an algorithm is available from the provider. - * - * @param algorithm the standard string name of the algorithm. See - * Appendix A in the Java Cryptography Architecture API Specification - * & Reference for information about standard algorithm names. - * @param provider the string name of the provider. - * @return the new KeyPairGenerator object. - * @throws NoSuchAlgorithmException if the algorithm is not available - * from the provider. - * @throws NoSuchProviderException if the provider is not available in the - * environment. - * @throws IllegalArgumentException if the provider name is null - * or empty. - * @see Provider + * Returns a new instance of KeyPairGenerator which generates + * key-pairs for the specified algorithm from a named provider. + * + * @param algorithm + * the name of the algorithm to use. + * @param provider + * the name of a {@link Provider} to use. + * @return a new instance repesenting the desired algorithm. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by the named provider. + * @throws NoSuchProviderException + * if the named provider was not found. */ public static KeyPairGenerator getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException @@ -212,20 +140,18 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } /** - * Generates a KeyPairGenerator object implementing the specified - * algorithm, as supplied from the specified provider, if such an algorithm is - * available from the provider. Note: the provider doesn't have to be - * registered. - * - * @param algorithm the standard string name of the algorithm. See Appendix A - * in the Java Cryptography Architecture API Specification & Reference for - * information about standard algorithm names. - * @param provider the provider. - * @return the new KeyPairGenerator object. - * @throws NoSuchAlgorithmException if the algorithm is not - * available from the provider. - * @throws IllegalArgumentException if the provider is - * null. + * Returns a new instance of KeyPairGenerator which generates + * key-pairs for the specified algorithm from a designated {@link Provider}. + * + * @param algorithm + * the name of the algorithm to use. + * @param provider + * the {@link Provider} to use. + * @return a new insatnce repesenting the desired algorithm. + * @throws IllegalArgumentException + * if provider is null. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by the {@link Provider}. * @since 1.4 * @see Provider */ @@ -247,23 +173,22 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } KeyPairGenerator result = null; - if (o instanceof KeyPairGeneratorSpi) - { - result = new DummyKeyPairGenerator((KeyPairGeneratorSpi) o, algorithm); - } - else if (o instanceof KeyPairGenerator) + if (o instanceof KeyPairGenerator) { result = (KeyPairGenerator) o; result.algorithm = algorithm; } + else if (o instanceof KeyPairGeneratorSpi) + result = new DummyKeyPairGenerator((KeyPairGeneratorSpi) o, algorithm); + result.provider = provider; return result; } /** - * Returns the provider of this key pair generator object. - * - * @return the provider of this key pair generator object. + * Returns the {@link Provider} of this instance. + * + * @return the {@link Provider} of this instance. */ public final Provider getProvider() { @@ -271,16 +196,11 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } /** - * Initializes the key pair generator for a certain keysize using a default - * parameter set and the {@link SecureRandom} implementation of the - * highest-priority installed provider as the source of randomness. (If none - * of the installed providers supply an implementation of {@link SecureRandom}, - * a system-provided source of randomness is used.) - * - * @param keysize the keysize. This is an algorithm-specific metric, such as - * modulus length, specified in number of bits. - * @throws InvalidParameterException if the keysize is not supported by this - * KeyPairGenerator object. + * Initializes this instance for the specified key size. Since no source of + * randomness is specified, a default one will be used. + * + * @param keysize + * the size of keys to use. */ public void initialize(int keysize) { @@ -288,14 +208,13 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } /** - * Initializes the key pair generator for a certain keysize with the given - * source of randomness (and a default parameter set). - * - * @param keysize the keysize. This is an algorithm-specific metric, such as - * modulus length, specified in number of bits. - * @param random the source of randomness. - * @throws InvalidParameterException if the keysize is not - * supported by this KeyPairGenerator object. + * Initializes this instance for the specified key size and + * {@link SecureRandom}. + * + * @param keysize + * the size of keys to use. + * @param random + * the {@link SecureRandom} to use. * @since 1.2 */ public void initialize(int keysize, SecureRandom random) @@ -303,24 +222,14 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } /** - *

      Initializes the key pair generator using the specified parameter set and - * the {@link SecureRandom} implementation of the highest-priority installed - * provider as the source of randomness. (If none of the installed providers - * supply an implementation of {@link SecureRandom}, a system-provided source - * of randomness is used.)

      - * - *

      This concrete method has been added to this previously-defined abstract - * class. This method calls the - * {@link KeyPairGeneratorSpi#initialize(AlgorithmParameterSpec, SecureRandom)} - * initialize method, passing it params and a source of - * randomness (obtained from the highest-priority installed provider or - * system-provided if none of the installed providers supply one). That - * initialize method always throws an {@link UnsupportedOperationException} - * if it is not overridden by the provider.

      - * - * @param params the parameter set used to generate the keys. - * @throws InvalidAlgorithmParameterException if the given parameters are - * inappropriate for this key pair generator. + * Initializes this instance with the specified + * {@link AlgorithmParameterSpec}. Since no source of randomness is specified, + * a default one will be used. + * + * @param params + * the {@link AlgorithmParameterSpec} to use. + * @throws InvalidAlgorithmParameterException + * if the designated specifications are invalid. * @since 1.2 */ public void initialize(AlgorithmParameterSpec params) @@ -330,20 +239,15 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } /** - *

      Initializes the key pair generator with the given parameter set and - * source of randomness.

      - * - *

      This concrete method has been added to this previously-defined abstract - * class. This method calls the - * {@link KeyPairGeneratorSpi#initialize(AlgorithmParameterSpec, SecureRandom)} - * initialize method, passing it params and random. - * That initialize method always throws an {@link UnsupportedOperationException} - * if it is not overridden by the provider.

      - * - * @param params the parameter set used to generate the keys. - * @param random the source of randomness. - * @throws InvalidAlgorithmParameterException if the given parameters are - * inappropriate for this key pair generator. + * Initializes this instance with the specified {@link AlgorithmParameterSpec} + * and {@link SecureRandom}. + * + * @param params + * the {@link AlgorithmParameterSpec} to use. + * @param random + * the {@link SecureRandom} to use. + * @throws InvalidAlgorithmParameterException + * if the designated specifications are invalid. * @since 1.2 */ public void initialize(AlgorithmParameterSpec params, SecureRandom random) @@ -353,17 +257,12 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } /** - *

      Generates a key pair.

      - * - *

      If this KeyPairGenerator has not been initialized - * explicitly, provider-specific defaults will be used for the size and other - * (algorithm-specific) values of the generated keys.

      - * - *

      This will generate a new key pair every time it is called.

      - * - *

      This method is functionally equivalent to {@link #generateKeyPair()}.

      - * - * @return the generated key pair. + * Generates a new "DSA" {@link KeyPair} from the "GNU" security provider. + * + *

      This method generates a unique key-pair each time it is called.

      + * + * @return a new unique {@link KeyPair}. + * @see #generateKeyPair() * @since 1.2 */ public final KeyPair genKeyPair() @@ -381,17 +280,12 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi } /** - *

      Generates a key pair.

      - * - *

      If this KeyPairGenerator has not been initialized - * explicitly, provider-specific defaults will be used for the size and other - * (algorithm-specific) values of the generated keys.

      - * - *

      This will generate a new key pair every time it is called.

      - * - *

      This method is functionally equivalent to {@link #genKeyPair()}.

      - * - * @return the generated key pair. + * Generates a new "DSA" {@link KeyPair} from the "GNU" security provider. + * + *

      This method generates a unique key pair each time it is called.

      + * + * @return a new unique {@link KeyPair}. + * @see #genKeyPair() */ public KeyPair generateKeyPair() { diff --git a/java/security/MessageDigest.java b/java/security/MessageDigest.java index 8a6af645b..b817759f5 100644 --- a/java/security/MessageDigest.java +++ b/java/security/MessageDigest.java @@ -40,54 +40,10 @@ package java.security; import gnu.java.security.Engine; /** - *

      This MessageDigest class provides applications the - * functionality of a message digest algorithm, such as MD5 or SHA. * Message digests are secure one-way hash functions that take arbitrary-sized - * data and output a fixed-length hash value.

      - * - *

      A MessageDigest object starts out initialized. The data is - * processed through it using the update() methods. At any point - * reset() can be called to reset the digest. Once all the data to - * be updated has been updated, one of the digest() methods should - * be called to complete the hash computation.

      - * - *

      The digest() method can be called once for a given - * number of updates. After digest() has been called, the - * MessageDigest object is reset to its initialized state. - *

      - * - *

      Implementations are free to implement the {@link Cloneable} interface. - * Client applications can test cloneability by attempting cloning and catching - * the {@link CloneNotSupportedException}: - * - *

      - *    MessageDigest md = MessageDigest.getInstance("SHA");
      - *    try
      - *      {
      - *        md.update(toChapter1);
      - *        MessageDigest tc1 = md.clone();
      - *        byte[] toChapter1Digest = tc1.digest();
      - *        md.update(toChapter2);
      - *        // ...
      - *      }
      - *    catch (CloneNotSupportedException x)
      - *      {
      - *        throw new DigestException("couldn't make digest of partial content");
      - *      }
      - * 
      - * - *

      Note that if a given implementation is not cloneable, it is still possible - * to compute intermediate digests by instantiating several instances, if the - * number of digests is known in advance.

      - * - *

      Note that this class is abstract and extends from {@link MessageDigestSpi} - * for historical reasons. Application developers should only take notice of the - * methods defined in this MessageDigest class; all the methods in - * the superclass are intended for cryptographic service providers who wish to - * supply their own implementations of message digest algorithms.

      + * data and output a fixed-length hash value. * * @see MessageDigestSpi - * @see Provider * @since JDK 1.1 */ public abstract class MessageDigest extends MessageDigestSpi @@ -100,12 +56,11 @@ public abstract class MessageDigest extends MessageDigestSpi private byte[] lastDigest; /** - * Creates a message digest with the specified algorithm name. - * - * @param algorithm the standard name of the digest algorithm. - * See Appendix A in the Java Cryptography Architecture API - * Specification & Reference for information about standard - * algorithm names. + * Constructs a new instance of MessageDigest representing the + * specified algorithm. + * + * @param algorithm + * the name of the digest algorithm to use. */ protected MessageDigest(String algorithm) { @@ -114,19 +69,14 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Generates a MessageDigest object that implements the specified - * digest algorithm. If the default provider package provides an - * implementation of the requested digest algorithm, an instance of - * MessageDigest containing that implementation is returned. If - * the algorithm is not available in the default package, other packages are - * searched. - * - * @param algorithm the name of the algorithm requested. See Appendix A in the - * Java Cryptography Architecture API Specification & Reference for - * information about standard algorithm names. - * @return a Message Digest object implementing the specified algorithm. - * @throws NoSuchAlgorithmException if the algorithm is not available in the - * caller's environment. + * Returns a new instance of MessageDigest representing the + * specified algorithm. + * + * @param algorithm + * the name of the digest algorithm to use. + * @return a new instance representing the desired algorithm. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by any provider. */ public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException @@ -148,21 +98,18 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Generates a MessageDigest object implementing the specified - * algorithm, as supplied from the specified provider, if such an algorithm is - * available from the provider. - * - * @param algorithm the name of the algorithm requested. See Appendix A in the - * Java Cryptography Architecture API Specification & Reference for - * information about standard algorithm names. - * @param provider the name of the provider. - * @return a Message Digest object implementing the specified algorithm. - * @throws NoSuchAlgorithmException if the algorithm is not available in the - * package supplied by the requested provider. - * @throws NoSuchProviderException if the provider is not available in the - * environment. - * @throws IllegalArgumentException if the provider name is null or empty. - * @see Provider + * Returns a new instance of MessageDigest representing the + * specified algorithm from a named provider. + * + * @param algorithm + * the name of the digest algorithm to use. + * @param provider + * the name of the provider to use. + * @return a new instance representing the desired algorithm. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by the named provider. + * @throws NoSuchProviderException + * if the named provider was not found. */ public static MessageDigest getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException @@ -181,20 +128,18 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Generates a MessageDigest object implementing the specified - * algorithm, as supplied from the specified provider, if such an algorithm - * is available from the provider. Note: the provider doesn't have to be - * registered. - * - * @param algorithm the name of the algorithm requested. See Appendix A in - * the Java Cryptography Architecture API Specification & Reference for - * information about standard algorithm names. - * @param provider the provider. - * @return a Message Digest object implementing the specified algorithm. - * @throws NoSuchAlgorithmException if the algorithm is not - * available in the package supplied by the requested provider. - * @throws IllegalArgumentException if the provider is - * null. + * Returns a new instance of MessageDigest representing the + * specified algorithm from a designated {@link Provider}. + * + * @param algorithm + * the name of the digest algorithm to use. + * @param provider + * the {@link Provider} to use. + * @return a new instance representing the desired algorithm. + * @throws IllegalArgumentException + * if provider is null. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by {@link Provider}. * @since 1.4 * @see Provider */ @@ -233,9 +178,9 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Returns the provider of this message digest object. - * - * @return the provider of this message digest object. + * Returns the {@link Provider} of this instance. + * + * @return the {@link Provider} of this instance. */ public final Provider getProvider() { @@ -243,9 +188,9 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Updates the digest using the specified byte. - * - * @param input the byte with which to update the digest. + * Updates the digest with the byte. + * + * @param input byte to update the digest with. */ public void update(byte input) { @@ -253,12 +198,15 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Updates the digest using the specified array of bytes, starting at the - * specified offset. - * - * @param input the array of bytes. - * @param offset the offset to start from in the array of bytes. - * @param len the number of bytes to use, starting at offset. + * Updates the digest with the bytes from the array starting from the + * specified offset and using the specified length of bytes. + * + * @param input + * bytes to update the digest with. + * @param offset + * the offset to start at. + * @param len + * length of the data to update with. */ public void update(byte[] input, int offset, int len) { @@ -266,9 +214,9 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Updates the digest using the specified array of bytes. - * - * @param input the array of bytes. + * Updates the digest with the bytes of an array. + * + * @param input bytes to update the digest with. */ public void update(byte[] input) { @@ -276,10 +224,9 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Completes the hash computation by performing final operations such as - * padding. The digest is reset after this call is made. - * - * @return the array of bytes for the resulting hash value. + * Computes the final digest of the stored data. + * + * @return a byte array representing the message digest. */ public byte[] digest() { @@ -287,14 +234,15 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Completes the hash computation by performing final operations such as - * padding. The digest is reset after this call is made. - * - * @param buf An output buffer for the computed digest. - * @param offset The offset into the output buffer to begin storing the digest. - * @param len The number of bytes within buf allotted for the digest. - * @return The number of bytes placed into buf. - * @throws DigestException if an error occurs. + * Computes the final digest of the stored bytes and returns the result. + * + * @param buf + * an array of bytes to store the result in. + * @param offset + * an offset to start storing the result at. + * @param len + * the length of the buffer. + * @return Returns the length of the buffer. */ public int digest(byte[] buf, int offset, int len) throws DigestException { @@ -302,13 +250,13 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Performs a final update on the digest using the specified array of bytes, - * then completes the digest computation. That is, this method first calls - * update(input), passing the input array to the update() - * method, then calls digest(). - * - * @param input the input to be updated before the digest is completed. - * @return the array of bytes for the resulting hash value. + * Computes a final update using the input array of bytes, then computes a + * final digest and returns it. It calls {@link #update(byte[])} and then + * {@link #digest(byte[])}. + * + * @param input + * an array of bytes to perform final update with. + * @return a byte array representing the message digest. */ public byte[] digest(byte[] input) { @@ -317,9 +265,9 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Returns a string representation of this message digest object. - * - * @return a string representation of the object. + * Returns a string representation of this instance. + * + * @return a string representation of this instance. */ public String toString() { @@ -327,12 +275,14 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Compares two digests for equality. Does a simple byte compare. - * - * @param digesta one of the digests to compare. - * @param digestb the other digest to compare. - * @return true if the digests are equal, false - * otherwise. + * Does a simple byte comparison of the two digests. + * + * @param digesta + * first digest to compare. + * @param digestb + * second digest to compare. + * @return true if both are equal, false + * otherwise. */ public static boolean isEqual(byte[] digesta, byte[] digestb) { @@ -346,20 +296,16 @@ public abstract class MessageDigest extends MessageDigestSpi return true; } - /** Resets the digest for further use. */ + /** Resets this instance. */ public void reset() { engineReset(); } /** - * Returns a string that identifies the algorithm, independent of - * implementation details. The name should be a standard Java Security name - * (such as "SHA", "MD5", and so on). See Appendix - * A in the Java Cryptography Architecture API Specification & Reference - * for information about standard algorithm names. - * - * @return the name of the algorithm. + * Returns the name of message digest algorithm. + * + * @return the name of message digest algorithm. */ public final String getAlgorithm() { @@ -367,12 +313,10 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Returns the length of the digest in bytes, or 0 if this - * operation is not supported by the provider and the implementation is not - * cloneable. - * - * @return the digest length in bytes, or 0 if this operation is - * not supported by the provider and the implementation is not cloneable. + * Returns the length of the message digest. The default is zero which means + * that the concrete implementation does not implement this method. + * + * @return length of the message digest. * @since 1.2 */ public final int getDigestLength() @@ -381,11 +325,14 @@ public abstract class MessageDigest extends MessageDigestSpi } /** - * Returns a clone if the implementation is cloneable. - * - * @return a clone if the implementation is cloneable. - * @throws CloneNotSupportedException if this is called on an implementation - * that does not support {@link Cloneable}. + * Returns a clone of this instance if cloning is supported. If it does not + * then a {@link CloneNotSupportedException} is thrown. Cloning depends on + * whether the subclass {@link MessageDigestSpi} implements {@link Cloneable} + * which contains the actual implementation of the appropriate algorithm. + * + * @return a clone of this instance. + * @throws CloneNotSupportedException + * the implementation does not support cloning. */ public Object clone() throws CloneNotSupportedException { diff --git a/java/security/Policy.java b/java/security/Policy.java index 03d9bbb4e..de1ab80ef 100644 --- a/java/security/Policy.java +++ b/java/security/Policy.java @@ -43,49 +43,43 @@ import java.util.LinkedHashMap; import java.util.Map; /** - *

      This is an abstract class for representing the system security policy for - * a Java application environment (specifying which permissions are available - * for code from various sources). That is, the security policy is represented - * by a Policy subclass providing an implementation of the abstract - * methods in this Policy class.

      - * - *

      There is only one Policy object in effect at any given time. - *

      - * - *

      The source location for the policy information utilized by the - * Policy object is up to the Policy implementation. - * The policy configuration may be stored, for example, as a flat ASCII file, as - * a serialized binary file of the Policy class, or as a database. - *

      - * - *

      The currently-installed Policy object can be obtained by - * calling the getPolicy() method, and it can be changed by a call - * to the setPolicy() method (by code with permission to reset the - * Policy).

      - * - *

      The refresh() method causes the policy object to refresh / - * reload its current configuration.

      - * - *

      This is implementation-dependent. For example, if the policy object stores - * its policy in configuration files, calling refresh() will cause - * it to re-read the configuration policy files. The refreshed policy may not - * have an effect on classes in a particular {@link ProtectionDomain}. This is - * dependent on the Policy provider's implementation of the - * implies() method and the {@link PermissionCollection} caching - * strategy.

      - * + * Policy is an abstract class for managing the system security + * policy for the Java application environment. It specifies which permissions + * are available for code from various sources. The security policy is + * represented through a subclass of Policy. + * + *

      Only one Policy is in effect at any time. A + * {@link ProtectionDomain} initializes itself with information from this class + * on the set of permssions to grant.

      + * + *

      The location for the actual Policy could be anywhere in any + * form because it depends on the Policy implementation. The default system is + * in a flat ASCII file or it could be in a database.

      + * + *

      The current installed Policy can be accessed with + * {@link #getPolicy()} and changed with {@link #setPolicy(Policy)} if the code + * has the correct permissions.

      + * + *

      The {@link #refresh()} method causes the Policy instance to + * refresh/reload its configuration. The method used to refresh depends on the + * Policy implementation.

      + * + *

      When a protection domain initializes its permissions, it uses code like + * the following:

      + * + * + * policy = Policy.getPolicy(); + * PermissionCollection perms = policy.getPermissions(myCodeSource); + * + * + *

      The protection domain passes the Policy handler a + * {@link CodeSource} instance which contains the codebase URL and a public key. + * The Policy implementation then returns the proper set of + * permissions for that {@link CodeSource}.

      + * *

      The default Policy implementation can be changed by setting - * the value of the "policy.provider" security property (in the - * Java security properties file) to the fully qualified name of the desired - * Policy implementation class. The Java security properties file - * is located in the file named <JAVA_HOME>/lib/security/java.security - * , where <JAVA_HOME> refers to the directory where the - * SDK was installed.

      - * - *

      IMPLEMENTATION NOTE: This implementation attempts to read the - * System property named policy.provider to find the concrete - * implementation of the Policy. If/when this fails, it falls back - * to a default implementation, which allows everything. + * the "policy.provider" security provider in the "java.security" file to the + * correct Policy implementation class.

      * * @author Mark Benvenuto * @see CodeSource @@ -106,18 +100,14 @@ public abstract class Policy } /** - * Returns the installed Policy object. This value should not be - * cached, as it may be changed by a call to setPolicy(). This - * method first calls {@link SecurityManager#checkPermission(Permission)} with - * a SecurityPermission("getPolicy") permission to ensure it's ok - * to get the Policy object. - * - * @return the installed Policy. - * @throws SecurityException if a security manager exists and its - * checkPermission() method doesn't allow getting the - * Policy object. - * @see SecurityManager#checkPermission(Permission) - * @see #setPolicy(Policy) + * Returns the currently installed Policy handler. The value + * should not be cached as it can be changed any time by + * {@link #setPolicy(Policy)}. + * + * @return the current Policy. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public static Policy getPolicy() { @@ -129,17 +119,13 @@ public abstract class Policy } /** - * Sets the system-wide Policy object. This method first calls - * {@link SecurityManager#checkPermission(Permission)} with a - * SecurityPermission("setPolicy") permission to ensure it's ok - * to set the Policy. - * - * @param policy the new system Policy object. - * @throws SecurityException if a security manager exists and its - * checkPermission() method doesn't allow setting the - * Policy. - * @see SecurityManager#checkPermission(Permission) - * @see #getPolicy() + * Sets the Policy handler to a new value. + * + * @param policy + * the new Policy to use. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public static void setPolicy(Policy policy) { @@ -213,28 +199,27 @@ public abstract class Policy } /** - * Evaluates the global policy and returns a {@link PermissionCollection} - * object specifying the set of permissions allowed for code from the - * specified code source. - * - * @param codesource the {@link CodeSource} associated with the caller. This - * encapsulates the original location of the code (where the code came from) - * and the public key(s) of its signer. - * @return the set of permissions allowed for code from codesource according - * to the policy. The returned set of permissions must be a new mutable - * instance and it must support heterogeneous {@link Permission} types. + * Returns the set of Permissions allowed for a given {@link CodeSource}. + * + * @param codesource + * the {@link CodeSource} for which, the caller needs to find the + * set of granted permissions. + * @return a set of permissions for {@link CodeSource} specified by the + * current Policy. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public abstract PermissionCollection getPermissions(CodeSource codesource); /** - * Evaluates the global policy and returns a {@link PermissionCollection} - * object specifying the set of permissions allowed given the characteristics - * of the protection domain. - * - * @param domain the {@link ProtectionDomain} associated with the caller. - * @return the set of permissions allowed for the domain according to the - * policy. The returned set of permissions must be a new mutable instance and - * it must support heterogeneous {@link Permission} types. + * Returns the set of Permissions allowed for a given {@link ProtectionDomain}. + * + * @param domain + * the {@link ProtectionDomain} for which, the caller needs to find + * the set of granted permissions. + * @return a set of permissions for {@link ProtectionDomain} specified by the + * current Policy.. * @since 1.4 * @see ProtectionDomain * @see SecureClassLoader @@ -270,14 +255,16 @@ public abstract class Policy } /** - * Evaluates the global policy for the permissions granted to the {@link - * ProtectionDomain} and tests whether the permission is granted. - * - * @param domain the {@link ProtectionDomain} to test. - * @param permission the {@link Permission} object to be tested for - * implication. - * @return true if permission is a proper subset of - * a permission granted to this {@link ProtectionDomain}. + * Checks if the designated {@link Permission} is granted to a designated + * {@link ProtectionDomain}. + * + * @param domain + * the {@link ProtectionDomain} to test. + * @param permission + * the {@link Permission} to check. + * @return true if permission is implied by a + * permission granted to this {@link ProtectionDomain}. Returns + * false otherwise. * @since 1.4 * @see ProtectionDomain */ @@ -302,9 +289,9 @@ public abstract class Policy } /** - * Refreshes/reloads the policy configuration. The behavior of this method - * depends on the implementation. For example, calling refresh on a file-based - * policy will cause the file to be re-read. + * Causes this Policy instance to refresh / reload its + * configuration. The method used to refresh depends on the concrete + * implementation. */ public abstract void refresh(); } diff --git a/java/security/ProtectionDomain.java b/java/security/ProtectionDomain.java index a8a093925..33af8fdb8 100644 --- a/java/security/ProtectionDomain.java +++ b/java/security/ProtectionDomain.java @@ -40,17 +40,14 @@ package java.security; import gnu.classpath.SystemProperties; /** - *

      This ProtectionDomain class encapsulates the characteristics - * of a domain, which encloses a set of classes whose instances are granted a - * set of permissions when being executed on behalf of a given set of - * Principals. - * - *

      A static set of permissions can be bound to a ProtectionDomain - * when it is constructed; such permissions are granted to the domain regardless - * of the {@link Policy} in force. However, to support dynamic security - * policies, a ProtectionDomain can also be constructed such that - * it is dynamically mapped to a set of permissions by the current {@link - * Policy} whenever a permission is checked.

      + * This class represents a group of classes, along with their granted + * permissions. The classes are identified by a {@link CodeSource}. Thus, any + * class loaded from the specified {@link CodeSource} is treated as part of + * this domain. The set of permissions is represented by an instance of + * {@link PermissionCollection}. + * + *

      Every class in the system will belong to one and only one + * ProtectionDomain.

      * * @author Aaron M. Renn (arenn@urbanophile.com) * @version 0.0 @@ -73,15 +70,17 @@ public class ProtectionDomain private boolean staticBinding; /** - * Creates a new ProtectionDomain with the given {@link - * CodeSource} and {@link Permissions}. If the permissions object is not - * null, then setReadOnly() will be called on the - * passed in {@link Permissions} object. The only permissions granted to this - * domain are the ones specified; the current {@link Policy} will not be - * consulted. - * - * @param codesource the codesource associated with this domain. - * @param permissions the permissions granted to this domain + * Initializes a new instance of ProtectionDomain representing + * the specified {@link CodeSource} and set of permissions. No permissions + * can be added later to the {@link PermissionCollection} and this contructor + * will call the setReadOnly method on the specified set of + * permissions. + * + * @param codesource + * The {@link CodeSource} for this domain. + * @param permissions + * The set of permissions for this domain. + * @see PermissionCollection#setReadOnly() */ public ProtectionDomain(CodeSource codesource, PermissionCollection permissions) { @@ -89,28 +88,25 @@ public class ProtectionDomain } /** - *

      Creates a new ProtectionDomain qualified by the given CodeSource, - * Permissions, ClassLoader and array of Principals. If the permissions - * object is not null, then setReadOnly() will be called on the - * passed in Permissions object. The permissions granted to this domain are - * dynamic; they include both the static permissions passed to this - * constructor, and any permissions granted to this domain by the current - * Policy at the time a permission is checked.

      - * - *

      This constructor is typically used by {@link ClassLoader}s and {@link - * DomainCombiner}s which delegate to Policy to actively - * associate the permissions granted to this domain. This constructor affords - * the Policy provider the opportunity to augment the supplied - * PermissionCollection to reflect policy changes.

      - * - * @param codesource the CodeSource associated with this domain. - * @param permissions the permissions granted to this domain. - * @param classloader the ClassLoader associated with this domain. - * @param principals the array of Principals associated with this domain. + * This method initializes a new instance of ProtectionDomain + * given its {@link CodeSource}, granted permissions, associated + * {@link ClassLoader} and {@link Principal}s. + * + *

      Similar to the previous constructor, if the designated set of + * permissions is not null, the setReadOnly method + * is called on that set.

      + * + * @param codesource + * The {@link CodeSource} for this domain. + * @param permissions + * The permission set for this domain. + * @param classloader + * the ClassLoader associated with this domain. + * @param principals + * the array of {@link Principal}s associated with this domain. * @since 1.4 - * @see Policy#refresh() - * @see Policy#getPermissions(ProtectionDomain) - */ + * @see PermissionCollection#setReadOnly() + */ public ProtectionDomain(CodeSource codesource, PermissionCollection permissions, ClassLoader classloader, Principal[] principals) @@ -140,8 +136,8 @@ public class ProtectionDomain /** * Returns the {@link CodeSource} of this domain. - * - * @return the {@link CodeSource} of this domain which may be null. + * + * @return the {@link CodeSource} of this domain. * @since 1.2 */ public final CodeSource getCodeSource() @@ -151,9 +147,8 @@ public class ProtectionDomain /** * Returns the {@link ClassLoader} of this domain. - * - * @return the {@link ClassLoader} of this domain which may be - * null. + * + * @return the {@link ClassLoader} of this domain. * @since 1.4 */ public final ClassLoader getClassLoader() @@ -162,10 +157,9 @@ public class ProtectionDomain } /** - * Returns an array of principals for this domain. - * - * @return returns a non-null array of principals for this domain. Changes to - * this array will have no impact on the ProtectionDomain. + * Returns a clone of the {@link Principal}s of this domain. + * + * @return a clone of the {@link Principal}s of this domain. * @since 1.4 */ public final Principal[] getPrincipals() @@ -174,12 +168,9 @@ public class ProtectionDomain } /** - * Returns the static permissions granted to this domain. - * - * @return the static set of permissions for this domain which may be - * null. - * @see Policy#refresh() - * @see Policy#getPermissions(ProtectionDomain) + * Returns the {@link PermissionCollection} of this domain. + * + * @return The {@link PermissionCollection} of this domain. */ public final PermissionCollection getPermissions() { @@ -187,26 +178,13 @@ public class ProtectionDomain } /** - *

      Check and see if this ProtectionDomain implies the - * permissions expressed in the Permission object.

      - * - *

      The set of permissions evaluated is a function of whether the - * ProtectionDomain was constructed with a static set of - * permissions or it was bound to a dynamically mapped set of permissions.

      - * - *

      If the ProtectionDomain was constructed to a statically - * bound {@link PermissionCollection} then the permission will only be checked - * against the {@link PermissionCollection} supplied at construction.

      - * - *

      However, if the ProtectionDomain was constructed with the - * constructor variant which supports dynamically binding permissions, then - * the permission will be checked against the combination of the - * {@link PermissionCollection} supplied at construction and the current - * {@link Policy} binding. - * - * @param permission the {@link Permission} object to check. - * @return true if permission is implicit to this - * ProtectionDomain. + * Tests whether or not the specified {@link Permission} is implied by the + * set of permissions granted to this domain. + * + * @param permission + * the {@link Permission} to test. + * @return true if the specified {@link Permission} is implied + * for this domain, false otherwise. */ public boolean implies(Permission permission) { @@ -218,9 +196,10 @@ public class ProtectionDomain } /** - * Convert a ProtectionDomain to a String. - * - * @return a string representation of the object. + * Returns a string representation of this object. It will include the + * {@link CodeSource} and set of permissions associated with this domain. + * + * @return A string representation of this object. */ public String toString() { diff --git a/java/security/Security.java b/java/security/Security.java index d8d746b05..8cc6c8367 100644 --- a/java/security/Security.java +++ b/java/security/Security.java @@ -60,7 +60,7 @@ import java.util.Vector; /** * This class centralizes all security properties and common security methods. - * One of its primary uses is to manage providers. + * One of its primary uses is to manage security providers. * * @author Mark Benvenuto (ivymccough@worldnet.att.net) */ @@ -110,9 +110,9 @@ public final class Security } /** - * Tries to load the vender specific security providers from the given - * base URL. Returns true if the resource could be read and completely - * parsed successfully, false otherwise. + * Tries to load the vender specific security providers from the given base + * URL. Returns true if the resource could be read and completely parsed + * successfully, false otherwise. */ private static boolean loadProviders(String baseUrl, String vendor) { @@ -133,7 +133,8 @@ public final class Security Exception exception = null; try { - providers.addElement(Class.forName(name).newInstance()); + ClassLoader sys = ClassLoader.getSystemClassLoader(); + providers.addElement(Class.forName(name, true, sys).newInstance()); } catch (ClassNotFoundException x) { @@ -166,22 +167,18 @@ public final class Security } /** - * Gets a specified property for an algorithm. The algorithm name should be a - * standard name. See Appendix A in the Java Cryptography Architecture API - * Specification & Reference for information about standard algorithm - * names. One possible use is by specialized algorithm parsers, which may map - * classes to algorithms which they understand (much like {@link Key} parsers - * do). - * - * @param algName the algorithm name. - * @param propName the name of the property to get. - * @return the value of the specified property. - * @deprecated This method used to return the value of a proprietary property - * in the master file of the "SUN" Cryptographic Service Provider in order to - * determine how to parse algorithm-specific parameters. Use the new - * provider-based and algorithm-independent {@link AlgorithmParameters} and - * {@link KeyFactory} engine classes (introduced in the Java 2 platform) - * instead. + * Returns the value associated to a designated property name for a given + * algorithm. + * + * @param algName + * the algorithm name. + * @param propName + * the name of the property to return. + * @return the value of the specified property or null if none + * found. + * @deprecated Use the provider-based and algorithm-independent + * {@link AlgorithmParameters} and {@link KeyFactory} engine + * classes instead. */ public static String getAlgorithmProperty(String algName, String propName) { @@ -204,37 +201,21 @@ public final class Security } /** - *

      Adds a new provider, at a specified position. The position is the - * preference order in which providers are searched for requested algorithms. - * Note that it is not guaranteed that this preference will be respected. The - * position is 1-based, that is, 1 is most preferred, followed by - * 2, and so on.

      - * - *

      If the given provider is installed at the requested position, the - * provider that used to be at that position, and all providers with a - * position greater than position, are shifted up one position (towards the - * end of the list of installed providers).

      - * - *

      A provider cannot be added if it is already installed.

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with the string "insertProvider."+provider. - * getName() to see if it's ok to add a new provider. If the default - * implementation of checkSecurityAccess() is used (i.e., that - * method is not overriden), then this will result in a call to the security - * manager's checkPermission() method with a - * SecurityPermission("insertProvider."+provider.getName()) - * permission.

      - * - * @param provider the provider to be added. - * @param position the preference position that the caller would like for - * this provider. - * @return the actual preference position in which the provider was added, or - * -1 if the provider was not added because it is already - * installed. - * @throws SecurityException if a security manager exists and its - * {@link SecurityManager#checkSecurityAccess(String)} method denies access - * to add a new provider. + * Inserts a new designated {@link Provider} at a designated (1-based) + * position in the current list of installed {@link Provider}s, + * + * @param provider + * the new {@link Provider} to add. + * @param position + * the position (starting from 1) of where to install + * provider. + * @return the actual position, in the list of installed Providers. Returns + * -1 if provider was laready in the + * list. The actual position may be different than the desired + * position. + * @throws SecurityException + * if a {@link SecurityManager} is installed and it disallows this + * operation. * @see #getProvider(String) * @see #removeProvider(String) * @see SecurityPermission @@ -264,24 +245,17 @@ public final class Security } /** - *

      Adds a provider to the next position available.

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with the string "insertProvider."+provider. - * getName() to see if it's ok to add a new provider. If the default - * implementation of checkSecurityAccess() is used (i.e., that - * method is not overriden), then this will result in a call to the security - * manager's checkPermission() method with a - * SecurityPermission("insertProvider."+provider.getName()) - * permission.

      - * - * @param provider the provider to be added. - * @return the preference position in which the provider was added, or - * -1 if the provider was not added because it is already - * installed. - * @throws SecurityException if a security manager exists and its - * {@link SecurityManager#checkSecurityAccess(String)} method denies access - * to add a new provider. + * Appends the designated new {@link Provider} to the current list of + * installed {@link Provider}s. + * + * @param provider + * the new {@link Provider} to append. + * @return the position (starting from 1) of provider in the + * current list of {@link Provider}s, or -1 if + * provider was already there. + * @throws SecurityException + * if a {@link SecurityManager} is installed and it disallows this + * operation. * @see #getProvider(String) * @see #removeProvider(String) * @see SecurityPermission @@ -292,26 +266,14 @@ public final class Security } /** - *

      Removes the provider with the specified name.

      - * - *

      When the specified provider is removed, all providers located at a - * position greater than where the specified provider was are shifted down - * one position (towards the head of the list of installed providers).

      - * - *

      This method returns silently if the provider is not installed.

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with the string "removeProvider."+name - * to see if it's ok to remove the provider. If the default implementation of - * checkSecurityAccess() is used (i.e., that method is not - * overriden), then this will result in a call to the security manager's - * checkPermission() method with a SecurityPermission( - * "removeProvider."+name) permission.

      - * - * @param name the name of the provider to remove. - * @throws SecurityException if a security manager exists and its - * {@link SecurityManager#checkSecurityAccess(String)} method denies access - * to remove the provider. + * Removes an already installed {@link Provider}, given its name, from the + * current list of installed {@link Provider}s. + * + * @param name + * the name of an already installed {@link Provider} to remove. + * @throws SecurityException + * if a {@link SecurityManager} is installed and it disallows this + * operation. * @see #getProvider(String) * @see #addProvider(Provider) */ @@ -333,9 +295,9 @@ public final class Security } /** - * Returns an array containing all the installed providers. The order of the - * providers in the array is their preference order. - * + * Returns the current list of installed {@link Provider}s as an array + * ordered according to their installation preference order. + * * @return an array of all the installed providers. */ public static Provider[] getProviders() @@ -346,11 +308,13 @@ public final class Security } /** - * Returns the provider installed with the specified name, if any. Returns - * null if no provider with the specified name is installed. - * - * @param name the name of the provider to get. - * @return the provider of the specified name. + * Returns an already installed {@link Provider} given its name. + * + * @param name + * the name of an already installed {@link Provider}. + * @return the {@link Provider} known by name. Returns + * null if the current list of {@link Provider}s does + * not include one named name. * @see #removeProvider(String) * @see #addProvider(Provider) */ @@ -376,18 +340,16 @@ public final class Security } /** - *

      Gets a security property value.

      - * - *

      First, if there is a security manager, its checkPermission() - * method is called with a SecurityPermission("getProperty."+key) - * permission to see if it's ok to retrieve the specified security property - * value.

      - * - * @param key the key of the property being retrieved. - * @return the value of the security property corresponding to key. - * @throws SecurityException if a security manager exists and its - * {@link SecurityManager#checkPermission(Permission)} method denies access - * to retrieve the specified security property value. + * Returns the value associated with a Security propery. + * + * @param key + * the key of the property to fetch. + * @return the value of the Security property associated with + * key. Returns null if no such property + * was found. + * @throws SecurityException + * if a {@link SecurityManager} is installed and it disallows this + * operation. * @see #setProperty(String, String) * @see SecurityPermission */ @@ -404,18 +366,15 @@ public final class Security } /** - *

      Sets a security property value.

      - * - *

      First, if there is a security manager, its checkPermission() - * method is called with a SecurityPermission("setProperty."+key) - * permission to see if it's ok to set the specified security property value. - *

      - * - * @param key the name of the property to be set. - * @param datum the value of the property to be set. - * @throws SecurityException if a security manager exists and its - * {@link SecurityManager#checkPermission(Permission)} method denies access - * to set the specified security property value. + * Sets or changes a designated Security property to a designated value. + * + * @param key + * the name of the property to set. + * @param datum + * the new value of the property. + * @throws SecurityException + * if a {@link SecurityManager} is installed and it disallows this + * operation. * @see #getProperty(String) * @see SecurityPermission */ @@ -432,19 +391,16 @@ public final class Security } /** - * Returns a Set of Strings containing the names of all available algorithms - * or types for the specified Java cryptographic service (e.g., Signature, - * MessageDigest, Cipher, Mac, KeyStore). Returns an empty Set if there is no - * provider that supports the specified service. For a complete list of Java - * cryptographic services, please see the Java Cryptography Architecture API - * Specification & Reference. Note: the returned set is immutable. - * - * @param serviceName the name of the Java cryptographic service (e.g., - * Signature, MessageDigest, Cipher, Mac, KeyStore). Note: this parameter is - * case-insensitive. - * @return a Set of Strings containing the names of all available algorithms - * or types for the specified Java cryptographic service or an empty set if - * no provider supports the specified service. + * For a given service (e.g. Signature, MessageDigest, etc...) this + * method returns the {@link Set} of all available algorithm names (instances + * of {@link String}, from all currently installed {@link Provider}s. + * + * @param serviceName + * the case-insensitive name of a service (e.g. Signature, + * MessageDigest, etc). + * @return a {@link Set} of {@link String}s containing the names of all + * algorithm names provided by all of the currently installed + * {@link Provider}s. * @since 1.4 */ public static Set getAlgorithms(String serviceName) @@ -477,53 +433,48 @@ public final class Security } /** - *

      Returns an array containing all installed providers that satisfy the - * specified selection criterion, or null if no such providers - * have been installed. The returned providers are ordered according to their - * preference order.

      - * - *

      A cryptographic service is always associated with a particular - * algorithm or type. For example, a digital signature service is always - * associated with a particular algorithm (e.g., DSA), and a - * CertificateFactory service is always associated with a particular - * certificate type (e.g., X.509).

      - * - *

      The selection criterion must be specified in one of the following two - * formats:

      - * + * Returns an array of currently installed {@link Provider}s, ordered + * according to their installation preference order, which satisfy a given + * selection criterion. + * + *

      This implementation recognizes a selection criterion written in + * one of two following forms:

      + * *
        - *
      • <crypto_service>.<algorithm_or_type>

        - *

        The cryptographic service name must not contain any dots.

        - *

        A provider satisfies the specified selection criterion iff the - * provider implements the specified algorithm or type for the specified - * cryptographic service.

        - *

        For example, "CertificateFactory.X.509" would be satisfied by any - * provider that supplied a CertificateFactory implementation for X.509 - * certificates.

      • - * - *
      • <crypto_service>.<algorithm_or_type> <attribute_name>:<attribute_value>

        - *

        The cryptographic service name must not contain any dots. There must - * be one or more space charaters between the the <algorithm_or_type> - * and the <attribute_name>.

        - *

        A provider satisfies this selection criterion iff the provider - * implements the specified algorithm or type for the specified - * cryptographic service and its implementation meets the constraint - * expressed by the specified attribute name/value pair.

        - *

        For example, "Signature.SHA1withDSA KeySize:1024" would be satisfied - * by any provider that implemented the SHA1withDSA signature algorithm - * with a keysize of 1024 (or larger).

      • + *
      • <crypto_service>.<algorithm_or_type>: Where + * crypto_service is a case-insensitive string, similar to what has + * been described in the {@link #getAlgorithms(String)} method, and + * algorithm_or_type is a known case-insensitive name of an + * Algorithm, or one of its aliases. + * + *

        For example, "CertificateFactory.X.509" would return all the installed + * {@link Provider}s which provide a CertificateFactory + * implementation of X.509.

      • + * + *
      • <crypto_service>.<algorithm_or_type> <attribute_name>:<value>: + * Where crypto_service is a case-insensitive string, similar to what + * has been described in the {@link #getAlgorithms(String)} method, + * algorithm_or_type is a case-insensitive known name of an Algorithm + * or one of its aliases, attribute_name is a case-insensitive + * property name with no whitespace characters, and no dots, in-between, and + * value is a {@link String} with no whitespace characters in-between. + * + *

        For example, "Signature.Sha1WithDSS KeySize:1024" would return all the + * installed {@link Provider}s which declared their ability to provide + * Signature services, using the Sha1WithDSS algorithm with + * key sizes of 1024.

      • *
      - * - *

      See Appendix A in the Java Cryptogaphy Architecture API Specification - * & Reference for information about standard cryptographic service names, - * standard algorithm names and standard attribute names.

      - * - * @param filter the criterion for selecting providers. The filter is case- - * insensitive. - * @return all the installed providers that satisfy the selection criterion, - * or null if no such providers have been installed. - * @throws InvalidParameterException if the filter is not in the required - * format. + * + * @param filter + * the selection criterion for selecting among the installed + * {@link Provider}s. + * @return all the installed {@link Provider}s which satisfy the selection + * criterion. Returns null if no installed + * {@link Provider}s were found which satisfy the selection + * criterion. Returns ALL installed {@link Provider}s if + * filter is null or is an empty string. + * @throws InvalidParameterException + * if an exception occurs while parsing the filter. * @see #getProviders(Map) */ public static Provider[] getProviders(String filter) @@ -544,49 +495,48 @@ public final class Security return getProviders(map); } - /** - *

      Returns an array containing all installed providers that satisfy the - * specified selection criteria, or null if no such providers - * have been installed. The returned providers are ordered according to their - * preference order.

      - * - *

      The selection criteria are represented by a map. Each map entry - * represents a selection criterion. A provider is selected iff it satisfies - * all selection criteria. The key for any entry in such a map must be in one - * of the following two formats:

      - * - *
        - *
      • <crypto_service>.<algorithm_or_type>

        - *

        The cryptographic service name must not contain any dots.

        - *

        The value associated with the key must be an empty string.

        - *

        A provider satisfies this selection criterion iff the provider - * implements the specified algorithm or type for the specified - * cryptographic service.

      • - * - *
      • <crypto_service>.<algorithm_or_type> <attribute_name>

        - *

        The cryptographic service name must not contain any dots. There must - * be one or more space charaters between the <algorithm_or_type> and - * the <attribute_name>.

        - *

        The value associated with the key must be a non-empty string. A - * provider satisfies this selection criterion iff the provider implements - * the specified algorithm or type for the specified cryptographic service - * and its implementation meets the constraint expressed by the specified - * attribute name/value pair.

      • - *
      - * - *

      See Appendix A in the Java Cryptogaphy Architecture API Specification - * & Reference for information about standard cryptographic service names, - * standard algorithm names and standard attribute names.

      - * - * @param filter the criteria for selecting providers. The filter is case- - * insensitive. - * @return all the installed providers that satisfy the selection criteria, - * or null if no such providers have been installed. - * @throws InvalidParameterException if the filter is not in the required - * format. - * @see #getProviders(String) - */ - public static Provider[] getProviders(Map filter) + /** + * Returns an array of currently installed {@link Provider}s which satisfy a + * set of selection criteria. + * + *

      The selection criteria are defined in a {@link Map} where each + * element specifies a selection querry. The Keys in this + * {@link Map} must be in one of the two following forms:

      + * + *
        + *
      • <crypto_service>.<algorithm_or_type>: Where + * crypto_service is a case-insensitive string, similar to what has + * been described in the {@link #getAlgorithms(String)} method, and + * algorithm_or_type is a case-insensitive known name of an + * Algorithm, or one of its aliases. The value of the entry in the + * {@link Map} for such a Key MUST be the empty string. + * {@link Provider}s which provide an implementation for the designated + * service algorithm are included in the result.
      • + * + *
      • <crypto_service>.<algorithm_or_type> <attribute_name>: + * Where crypto_service is a case-insensitive string, similar to what + * has been described in the {@link #getAlgorithms(String)} method, + * algorithm_or_type is a case-insensitive known name of an Algorithm + * or one of its aliases, and attribute_name is a case-insensitive + * property name with no whitespace characters, and no dots, in-between. The + * value of the entry in this {@link Map} for such a Key MUST + * NOT be null or an empty string. {@link Provider}s which + * declare the designated attribute_name and value for the + * designated service algorithm are included in the result.
      • + *
      + * + * @param filter + * a {@link Map} of selection querries. + * @return all currently installed {@link Provider}s which satisfy ALL the + * selection criteria defined in filter. + * Returns ALL installed {@link Provider}s if filter + * is null or empty. + * @throws InvalidParameterException + * if an exception is encountered while parsing the syntax of the + * {@link Map}'s keys. + * @see #getProviders(String) + */ + public static Provider[] getProviders(Map filter) { if (providers == null || providers.isEmpty()) return null; diff --git a/java/security/Signature.java b/java/security/Signature.java index 852c95922..845a77a8b 100644 --- a/java/security/Signature.java +++ b/java/security/Signature.java @@ -45,66 +45,36 @@ import java.security.cert.X509Certificate; import java.security.spec.AlgorithmParameterSpec; /** - *

      This Signature class is used to provide applications the - * functionality of a digital signature algorithm. Digital signatures are used - * for authentication and integrity assurance of digital data.

      - * - *

      The signature algorithm can be, among others, the NIST standard DSS, - * using DSA and SHA-1. The DSA algorithm using the - * SHA-1 message digest algorithm can be specified as SHA1withDSA - * . In the case of RSA, there are multiple choices for the - * message digest algorithm, so the signing algorithm could be specified as, for - * example, MD2withRSA, MD5withRSA, or - * SHA1withRSA. The algorithm name must be specified, as there is - * no default.

      - * - *

      Like other algorithm-based classes in Java Security, Signature - * provides implementation-independent algorithms, whereby a caller (application - * code) requests a particular signature algorithm and is handed back a properly - * initialized Signature object. It is also possible, if desired, - * to request a particular algorithm from a particular provider. See the - * getInstance() methods.

      - * - *

      Thus, there are two ways to request a Signature algorithm - * object: by specifying either just an algorithm name, or both an algorithm - * name and a package provider.

      - * - *

      If just an algorithm name is specified, the system will determine if there - * is an implementation of the algorithm requested available in the environment, - * and if there is more than one, if there is a preferred one.

      - * - *

      If both an algorithm name and a package provider are specified, the system - * will determine if there is an implementation of the algorithm in the package - * requested, and throw an exception if there is not.

      - * - *

      A Signature object can be used to generate and verify digital - * signatures.

      - * - *

      There are three phases to the use of a Signature object for - * either signing data or verifying a signature:

      - * + * Signature is used to provide an interface to digital signature + * algorithms. Digital signatures provide authentication and data integrity of + * digital data. + * + *

      The GNU provider provides the NIST standard DSA which uses DSA and SHA-1. + * It can be specified by SHA/DSA, SHA-1/DSA or its OID. If the RSA signature + * algorithm is provided then it could be MD2/RSA. MD5/RSA, or SHA-1/RSA. The + * algorithm must be specified because there is no default.

      + * + *

      Signature provides implementation-independent algorithms which are + * requested by the user through the getInstance() methods. It can + * be requested by specifying just the algorithm name or by specifying both the + * algorithm name and provider name.

      + * + *

      The three phases of using Signature are:

      + * *
        - *
      1. Initialization, with either + *
      2. Initializing: *
          - *
        • a public key, which initializes the signature for verification - * (see initVerify()), or
        • - *
        • a private key (and optionally a Secure Random Number Generator), - * which initializes the signature for signing (see - * {@link #initSign(PrivateKey)} and {@link #initSign(PrivateKey, SecureRandom)} - * ).
        • - *
      3. - *
      4. Updating
        - * Depending on the type of initialization, this will update the bytes to - * be signed or verified. See the update methods.
      5. - *
      6. Signing or Verifying a signature on all updated bytes. See the - * sign() methods and the verify() method.
      7. - *
      - * - *

      Note that this class is abstract and extends from {@link SignatureSpi} for - * historical reasons. Application developers should only take notice of the - * methods defined in this Signature class; all the methods in the - * superclass are intended for cryptographic service providers who wish to - * supply their own implementations of digital signature algorithms. + *

    • It must be initialized with a private key for signing.
    • + *
    • It must be initialized with a public key for verifying.
    • + * + * + *
    • Updating: + *

      Update the bytes for signing or verifying with calls to update.

      + *
    • + * + *
    • Signing or Verify the signature on the currently stored bytes by + * calling sign or verify.
    • + * * * @author Mark Benvenuto (ivymccough@worldnet.att.net) */ @@ -114,38 +84,38 @@ public abstract class Signature extends SignatureSpi private static final String SIGNATURE = "Signature"; /** - * Possible state value, signifying that this signature object - * has not yet been initialized. + * Possible state value which signifies that this instance has not yet been + * initialized. */ protected static final int UNINITIALIZED = 0; - // Constructor. - // ------------------------------------------------------------------------ - /** - * Possible state value, signifying that this signature object - * has been initialized for signing. + * Possible state value which signifies that this instance has been + * initialized for signing purposes. */ protected static final int SIGN = 2; /** - * Possible state value, signifying that this signature object - * has been initialized for verification. + * Possible state value which signifies that this instance has been + * initialized for verification purposes. */ protected static final int VERIFY = 3; - /** Current state of this signature object. */ + /** Current sate of this instance. */ protected int state = UNINITIALIZED; private String algorithm; Provider provider; + // Constructor. + // ------------------------------------------------------------------------ + /** - * Creates a Signature object for the specified algorithm. - * - * @param algorithm the standard string name of the algorithm. See Appendix A - * in the Java Cryptography Architecture API Specification & Reference for - * information about standard algorithm names. + * Constructs a new Signature instance for a designated digital + * signature algorithm. + * + * @param algorithm + * the algorithm to use. */ protected Signature(String algorithm) { @@ -154,19 +124,14 @@ public abstract class Signature extends SignatureSpi } /** - * Generates a Signature object that implements the specified - * digest algorithm. If the default provider package provides an - * implementation of the requested digest algorithm, an instance of - * Signature containing that implementation is returned. If the - * algorithm is not available in the default package, other packages are - * searched. - * - * @param algorithm the standard name of the algorithm requested. See Appendix - * A in the Java Cryptography Architecture API Specification & Reference - * for information about standard algorithm names. - * @return the new Signature object. - * @throws NoSuchAlgorithmException if the algorithm is not available in the - * environment. + * Returns an instance of Signature representing the specified + * signature. + * + * @param algorithm + * the algorithm to use. + * @return a new instance repesenting the desired algorithm. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by any provider. */ public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException @@ -188,22 +153,20 @@ public abstract class Signature extends SignatureSpi } /** - * Generates a Signature object implementing the specified - * algorithm, as supplied from the specified provider, if such an algorithm - * is available from the provider. - * - * @param algorithm the name of the algorithm requested. See Appendix A in - * the Java Cryptography Architecture API Specification & Reference for - * information about standard algorithm names. - * @param provider the name of the provider. - * @return the new Signature object. - * @throws NoSuchAlgorithmException if the algorithm is not available in the - * package supplied by the requested provider. - * @throws NoSuchProviderException if the provider is not available in the - * environment. - * @throws IllegalArgumentException if the provider name is null - * or empty. - * @see Provider + * Returns an instance of Signature representing the specified + * signature from the named provider. + * + * @param algorithm + * the algorithm to use. + * @param provider + * the name of the provider to use. + * @return a new instance repesenting the desired algorithm. + * @throws IllegalArgumentException if provider is + * null or is an empty string. + * @throws NoSuchProviderException + * if the named provider was not found. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by the named provider. */ public static Signature getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException @@ -219,22 +182,16 @@ public abstract class Signature extends SignatureSpi } /** - * Generates a Signature object implementing the specified - * algorithm, as supplied from the specified provider, if such an algorithm - * is available from the provider. Note: the provider doesn't have to be - * registered. - * - * @param algorithm the name of the algorithm requested. See Appendix A in - * the Java Cryptography Architecture API Specification & Reference for - * information about standard algorithm names. - * @param provider the provider. - * @return the new Signature object. - * @throws NoSuchAlgorithmException if the algorithm is not - * available in the package supplied by the requested provider. - * @throws IllegalArgumentException if the provider is - * null. - * @since 1.4 - * @see Provider + * Returns an instance of Signature representing the specified + * signature from the specified {@link Provider}. + * + * @param algorithm + * the algorithm to use. + * @param provider + * the {@link Provider} to use. + * @return a new instance repesenting the desired algorithm. + * @throws NoSuchAlgorithmException + * if the algorithm is not implemented by the {@link Provider}. */ public static Signature getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException @@ -271,9 +228,9 @@ public abstract class Signature extends SignatureSpi } /** - * Returns the provider of this signature object. - * - * @return the provider of this signature object. + * Returns the {@link Provider} of this instance. + * + * @return the {@link Provider} of this instance. */ public final Provider getProvider() { @@ -281,12 +238,12 @@ public abstract class Signature extends SignatureSpi } /** - * Initializes this object for verification. If this method is called again - * with a different argument, it negates the effect of this call. - * - * @param publicKey the public key of the identity whose signature is going - * to be verified. - * @throws InvalidKeyException if the key is invalid. + * Initializes this instance with the public key for verification purposes. + * + * @param publicKey + * the public key to verify with. + * @throws InvalidKeyException + * if the key is invalid. */ public final void initVerify(PublicKey publicKey) throws InvalidKeyException { @@ -295,20 +252,16 @@ public abstract class Signature extends SignatureSpi } /** - *

      Initializes this object for verification, using the public key from the - * given certificate.

      - * - *

      If the certificate is of type X.509 and has a key usage - * extension field marked as critical, and the value of the key - * usage extension field implies that the public key in the certificate - * and its corresponding private key are not supposed to be used for digital - * signatures, an {@link InvalidKeyException} is thrown.

      - * - * @param certificate the certificate of the identity whose signature is - * going to be verified. - * @throws InvalidKeyException if the public key in the certificate is not - * encoded properly or does not include required parameter information or - * cannot be used for digital signature purposes. + * Verify a signature with a designated {@link Certificate}. This is a FIPS + * 140-1 compatible method since it verifies a signature with a certificate. + * + *

      If the {@link Certificate} is an X.509 one, has a KeyUsage + * parameter and that parameter indicates this key is not to be used for + * signing then an exception is thrown.

      + * + * @param certificate + * a {@link Certificate} containing a public key to verify with. + * @throws InvalidKeyException if the key is invalid. */ public final void initVerify(Certificate certificate) throws InvalidKeyException @@ -326,12 +279,12 @@ public abstract class Signature extends SignatureSpi } /** - * Initialize this object for signing. If this method is called again with a - * different argument, it negates the effect of this call. - * - * @param privateKey the private key of the identity whose signature is going - * to be generated. - * @throws InvalidKeyException if the key is invalid. + * Initializes this class with the private key for signing purposes. + * + * @param privateKey + * the private key to sign with. + * @throws InvalidKeyException + * if the key is invalid. */ public final void initSign(PrivateKey privateKey) throws InvalidKeyException { @@ -340,13 +293,15 @@ public abstract class Signature extends SignatureSpi } /** - * Initialize this object for signing. If this method is called again with a - * different argument, it negates the effect of this call. - * - * @param privateKey the private key of the identity whose signature is going - * to be generated. - * @param random the source of randomness for this signature. - * @throws InvalidKeyException if the key is invalid. + * Initializes this class with the private key and source of randomness for + * signing purposes. + * + * @param privateKey + * the private key to sign with. + * @param random + * the {@link SecureRandom} to use. + * @throws InvalidKeyException + * if the key is invalid. */ public final void initSign(PrivateKey privateKey, SecureRandom random) throws InvalidKeyException @@ -356,18 +311,12 @@ public abstract class Signature extends SignatureSpi } /** - *

      Returns the signature bytes of all the data updated. The format of the - * signature depends on the underlying signature scheme.

      - * - *

      A call to this method resets this signature object to the state it was - * in when previously initialized for signing via a call to - * initSign(PrivateKey). That is, the object is reset and - * available to generate another signature from the same signer, if desired, - * via new calls to update() and sign().

      - * - * @return the signature bytes of the signing operation's result. - * @throws SignatureException if this signature object is not initialized - * properly. + * Returns the signature bytes of all the data fed to this instance. The + * format of the output depends on the underlying signature algorithm. + * + * @return the signature bytes. + * @throws SignatureException + * if the engine is not properly initialized. */ public final byte[] sign() throws SignatureException { @@ -378,21 +327,27 @@ public abstract class Signature extends SignatureSpi } /** - *

      Finishes the signature operation and stores the resulting signature - * bytes in the provided buffer outbuf, starting at offset - * . The format of the signature depends on the underlying signature - * scheme.

      - * - *

      This signature object is reset to its initial state (the state it was - * in after a call to one of the initSign() methods) and can be - * reused to generate further signatures with the same private key.

      - * - * @param outbuf buffer for the signature result. - * @param offset offset into outbuf where the signature is stored. - * @param len number of bytes within outbuf allotted for the signature. - * @return the number of bytes placed into outbuf. - * @throws SignatureException if an error occurs or len is less than the - * actual signature length. + * Generates signature bytes of all the data fed to this instance and stores + * it in the designated array. The format of the result depends on the + * underlying signature algorithm. + * + *

      After calling this method, the instance is reset to its initial state + * and can then be used to generate additional signatures.

      + * + *

      IMPLEMENTATION NOTE: Neither this method nor the GNU provider + * will return partial digests. If len is less than the + * signature length, this method will throw a {@link SignatureException}. If + * it is greater than or equal then it is ignored.

      + * + * @param outbuf + * array of bytes of where to store the resulting signature bytes. + * @param offset + * the offset to start at in the array. + * @param len + * the number of the bytes to use in the array. + * @return the real number of bytes used. + * @throws SignatureException + * if the engine is not properly initialized. * @since 1.2 */ public final int sign(byte[] outbuf, int offset, int len) @@ -405,20 +360,14 @@ public abstract class Signature extends SignatureSpi } /** - *

      Verifies the passed-in signature.

      - * - *

      A call to this method resets this signature object to the state it was - * in when previously initialized for verification via a call to - * initVerify(PublicKey). That is, the object is reset and - * available to verify another signature from the identity whose public key - * was specified in the call to initVerify().

      - * - * @param signature the signature bytes to be verified. - * @return true if the signature was verified, false - * if not. - * @throws SignatureException if this signature object is not initialized - * properly, or the passed-in signature is improperly encoded or of the wrong - * type, etc. + * Verifies a designated signature. + * + * @param signature + * the signature bytes to verify. + * @return true if verified, false otherwise. + * @throws SignatureException + * if the engine is not properly initialized or the signature does + * not check. */ public final boolean verify(byte[]signature) throws SignatureException { @@ -429,28 +378,24 @@ public abstract class Signature extends SignatureSpi } /** - *

      Verifies the passed-in signature in the specified array of - * bytes, starting at the specified offset.

      - * - *

      A call to this method resets this signature object to the state it was - * in when previously initialized for verification via a call to - * initVerify(PublicKey). That is, the object is reset and - * available to verify another signature from the identity whose public key - * was specified in the call to initVerify().

      - * - * @param signature the signature bytes to be verified. - * @param offset the offset to start from in the array of bytes. - * @param length the number of bytes to use, starting at offset. - * @return true if the signature was verified, false - * if not. - * @throws SignatureException if this signature object is not initialized - * properly, or the passed-in signature is improperly encoded or - * of the wrong type, etc. - * @throws IllegalArgumentException if the signature byte array - * is null, or the offset or length is - * less than 0, or the sum of the offset and - * length is greater than the length of the signature - * byte array. + * Verifies a designated signature. + * + * @param signature + * the signature bytes to verify. + * @param offset + * the offset to start at in the array. + * @param length + * the number of the bytes to use from the array. + * @return true if verified, false otherwise. + * @throws IllegalArgumentException + * if the signature byte array is null, + * or the offset or length is less + * than 0, or the sum of the offset + * and length is greater than the length of the + * signature byte array. + * @throws SignatureException + * if the engine is not properly initialized or the signature does + * not check. */ public final boolean verify(byte[] signature, int offset, int length) throws SignatureException @@ -471,11 +416,12 @@ public abstract class Signature extends SignatureSpi } /** - * Updates the data to be signed or verified by a byte. - * - * @param b the byte to use for the update. - * @throws SignatureException if this signature object is not initialized - * properly. + * Updates the data to be signed or verified with the specified byte. + * + * @param b + * the byte to update with. + * @throws SignatureException + * if the engine is not properly initialized. */ public final void update(byte b) throws SignatureException { @@ -486,12 +432,12 @@ public abstract class Signature extends SignatureSpi } /** - * Updates the data to be signed or verified, using the specified array of - * bytes. - * - * @param data the byte array to use for the update. - * @throws SignatureException if this signature object is not initialized - * properly. + * Updates the data to be signed or verified with the specified bytes. + * + * @param data + * the array of bytes to use. + * @throws SignatureException + * if the engine is not properly initialized. */ public final void update(byte[]data) throws SignatureException { @@ -502,14 +448,16 @@ public abstract class Signature extends SignatureSpi } /** - * Updates the data to be signed or verified, using the specified array of - * bytes, starting at the specified offset. - * - * @param data the array of bytes. - * @param off the offset to start from in the array of bytes. - * @param len the number of bytes to use, starting at offset. - * @throws SignatureException if this signature object is not initialized - * properly. + * Updates the data to be signed or verified with the specified bytes. + * + * @param data + * an array of bytes to use. + * @param off + * the offset to start at in the array. + * @param len + * the number of bytes to use from the array. + * @throws SignatureException + * if the engine is not properly initialized. */ public final void update(byte[]data, int off, int len) throws SignatureException @@ -521,9 +469,10 @@ public abstract class Signature extends SignatureSpi } /** - * Returns the name of the algorithm for this signature object. - * - * @return the name of the algorithm for this signature object. + * Returns the name of the algorithm currently used. The names of algorithms + * are usually SHA/DSA or SHA/RSA. + * + * @return name of algorithm. */ public final String getAlgorithm() { @@ -531,11 +480,9 @@ public abstract class Signature extends SignatureSpi } /** - * Returns a string representation of this signature object, providing - * information that includes the state of the object and the name of the - * algorithm used. - * - * @return a string representation of this signature object. + * Returns a rstring representation of this instance. + * + * @return a rstring representation of this instance. */ public String toString() { @@ -543,22 +490,16 @@ public abstract class Signature extends SignatureSpi } /** - * Sets the specified algorithm parameter to the specified value. This method - * supplies a general-purpose mechanism through which it is possible to set - * the various parameters of this object. A parameter may be any settable - * parameter for the algorithm, such as a parameter size, or a source of - * random bits for signature generation (if appropriate), or an indication of - * whether or not to perform a specific but optional computation. A uniform - * algorithm-specific naming scheme for each parameter is desirable but left - * unspecified at this time. - * - * @param param the string identifier of the parameter. - * @param value the parameter value. - * @throws InvalidParameterException if param is an invalid parameter for this - * signature algorithm engine, the parameter is already set and cannot be set - * again, a security exception occurs, and so on. - * @see #getParameter(String) - * @deprecated Use setParameter(AlgorithmParameterSpec). + * Sets the specified algorithm parameter to the specified value. + * + * @param param + * the parameter name. + * @param value + * the parameter value. + * @throws InvalidParameterException + * if the parameter is invalid, the parameter is already set and + * can not be changed, a security exception occured, etc. + * @deprecated use the other setParameter */ public final void setParameter(String param, Object value) throws InvalidParameterException @@ -567,12 +508,16 @@ public abstract class Signature extends SignatureSpi } /** - * Initializes this signature engine with the specified parameter set. - * - * @param params the parameters. - * @throws InvalidAlgorithmParameterException if the given parameters are - * inappropriate for this signature engine. - * @see #getParameters() + * Sets the signature engine with the specified {@link AlgorithmParameterSpec}. + * + *

      By default, and unless overriden by the concrete SPI, this method always + * throws an {@link UnsupportedOperationException}.

      + * + * @param params + * the parameters to use for intializing this instance. + * @throws InvalidParameterException + * if the parameter is invalid, the parameter is already set and + * cannot be changed, a security exception occured, etc. */ public final void setParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException @@ -581,17 +526,11 @@ public abstract class Signature extends SignatureSpi } /** - *

      Returns the parameters used with this signature object.

      - * - *

      The returned parameters may be the same that were used to initialize - * this signature, or may contain a combination of default and randomly - * generated parameter values used by the underlying signature implementation - * if this signature requires algorithm parameters but was not initialized - * with any. - * - * @return the parameters used with this signature, or null if - * this signature does not use any parameters. - * @see #setParameter(AlgorithmParameterSpec) + * Return the parameters of the algorithm used in this instance as an + * {@link AlgorithmParameters}. + * + * @return the parameters used with this instance, or null if + * this instance does not use any parameters. */ public final AlgorithmParameters getParameters() { @@ -599,22 +538,14 @@ public abstract class Signature extends SignatureSpi } /** - * Gets the value of the specified algorithm parameter. This method supplies - * a general-purpose mechanism through which it is possible to get the various - * parameters of this object. A parameter may be any settable parameter for - * the algorithm, such as a parameter size, or a source of random bits for - * signature generation (if appropriate), or an indication of whether or not - * to perform a specific but optional computation. A uniform - * algorithm-specific naming scheme for each parameter is desirable but left - * unspecified at this time. - * - * @param param the string name of the parameter. - * @return the object that represents the parameter value, or null if there - * is none. - * @throws InvalidParameterException if param is an invalid parameter for this - * engine, or another exception occurs while trying to get this parameter. - * @see #setParameter(String, Object) - * @deprecated + * Returns the value for the specified algorithm parameter. + * + * @param param + * the parameter name. + * @return the parameter value. + * @throws InvalidParameterException + * if the parameter is invalid. + * @deprecated use the other getParameter */ public final Object getParameter(String param) throws InvalidParameterException @@ -623,11 +554,11 @@ public abstract class Signature extends SignatureSpi } /** - * Returns a clone if the implementation is cloneable. - * - * @return a clone if the implementation is cloneable. - * @throws CloneNotSupportedException if this is called on an implementation - * that does not support {@link Cloneable}. + * Returns a clone of this instance. + * + * @return a clone of this instace. + * @throws CloneNotSupportedException + * if the implementation does not support cloning. */ public Object clone() throws CloneNotSupportedException { diff --git a/java/security/SignatureSpi.java b/java/security/SignatureSpi.java index 471a73d17..25d49dedd 100644 --- a/java/security/SignatureSpi.java +++ b/java/security/SignatureSpi.java @@ -40,14 +40,10 @@ package java.security; import java.security.spec.AlgorithmParameterSpec; /** - *

      This class defines the Service Provider Interface (SPI) for the - * {@link Signature} class, which is used to provide the functionality of a + * SignatureSpi defines the Service Provider Interface (SPI) for + * the {@link Signature} class. The signature class provides an interface to a * digital signature algorithm. Digital signatures are used for authentication - * and integrity assurance of digital data.

      - * - *

      All the abstract methods in this class must be implemented by each - * cryptographic service provider who wishes to supply the implementation of a - * particular signature algorithm. + * and integrity of data. * * @author Mark Benvenuto (ivymccough@worldnet.att.net) * @since 1.2 @@ -55,50 +51,51 @@ import java.security.spec.AlgorithmParameterSpec; */ public abstract class SignatureSpi { - /** Application-specified source of randomness. */ + /** Source of randomness. */ protected SecureRandom appRandom; + /** + * Creates a new instance of SignatureSpi. + */ public SignatureSpi() { appRandom = null; } /** - * Initializes this signature object with the specified public key for - * verification operations. - * - * @param publicKey the public key of the identity whose signature is going - * to be verified. - * @throws InvalidKeyException if the key is improperly encoded, parameters - * are missing, and so on. + * Initializes this instance with the public key for verification purposes. + * + * @param publicKey + * the public key to verify with. + * @throws InvalidKeyException + * if the key is invalid. */ protected abstract void engineInitVerify(PublicKey publicKey) throws InvalidKeyException; /** - * Initializes this signature object with the specified private key for - * signing operations. - * - * @param privateKey the private key of the identity whose signature will be - * generated. - * @throws InvalidKeyException if the key is improperly encoded, parameters - * are missing, and so on. + * Initializes this instance with the private key for signing purposes. + * + * @param privateKey + * the private key to sign with. + * @throws InvalidKeyException + * if the key is invalid. */ protected abstract void engineInitSign(PrivateKey privateKey) throws InvalidKeyException; /** - *

      Initializes this signature object with the specified private key and - * source of randomness for signing operations.

      - * - *

      This concrete method has been added to this previously-defined abstract - * class. (For backwards compatibility, it cannot be abstract.)

      - * - * @param privateKey the private key of the identity whose signature will be - * generated. - * @param random the source of randomness. - * @throws InvalidKeyException if the key is improperly encoded, parameters - * are missing, and so on. + * Initializes this instance with the private key and source of randomness for + * signing purposes. + * + *

      This method cannot be abstract for backward compatibility reasons.

      + * + * @param privateKey + * the private key to sign with. + * @param random + * the {@link SecureRandom} to use. + * @throws InvalidKeyException + * if the key is invalid. * @since 1.2 */ protected void engineInitSign(PrivateKey privateKey, SecureRandom random) @@ -109,57 +106,63 @@ public abstract class SignatureSpi } /** - * Updates the data to be signed or verified using the specified byte. - * - * @param b the byte to use for the update. - * @throws SignatureException if the engine is not initialized properly. + * Updates the data to be signed or verified with the specified byte. + * + * @param b + * byte to update with. + * @throws SignatureException + * if the engine is not properly initialized. */ protected abstract void engineUpdate(byte b) throws SignatureException; /** - * Updates the data to be signed or verified, using the specified array of - * bytes, starting at the specified offset. - * - * @param b the array of bytes. - * @param off the offset to start from in the array of bytes. - * @param len the number of bytes to use, starting at offset. - * @throws SignatureException if the engine is not initialized properly. + * Updates the data to be signed or verified with the specified bytes. + * + * @param b + * the array of bytes to use. + * @param off + * the offset to start at in the array. + * @param len + * the number of the bytes to use from the array. + * @throws SignatureException + * if the engine is not properly initialized. */ protected abstract void engineUpdate(byte[] b, int off, int len) throws SignatureException; /** - * Returns the signature bytes of all the data updated so far. The format of - * the signature depends on the underlying signature scheme. - * - * @return the signature bytes of the signing operation's result. - * @throws SignatureException if the engine is not initialized properly. + * Returns the signature bytes of all the data fed to this instance. The + * format of the output depends on the underlying signature algorithm. + * + * @return the signature bytes. + * @throws SignatureException + * if the engine is not properly initialized. */ protected abstract byte[] engineSign() throws SignatureException; /** - *

      Finishes this signature operation and stores the resulting signature - * bytes in the provided buffer outbuf, starting at offset - * . The format of the signature depends on the underlying signature - * scheme.

      - * - *

      The signature implementation is reset to its initial state (the state it - * was in after a call to one of the engineInitSign() methods) - * and can be reused to generate further signatures with the same private key. - * This method should be abstract, but we leave it concrete for binary - * compatibility. Knowledgeable providers should override this method.

      - * - * @param outbuf buffer for the signature result. - * @param offset offset into outbuf where the signature is stored. - * @param len number of bytes within outbuf allotted for the signature. Both - * this default implementation and the GNU provider do not return - * partial digests. If the value of this parameter is less than the actual - * signature length, this method will throw a {@link SignatureException}. This - * parameter is ignored if its value is greater than or equal to the actual - * signature length. - * @return the number of bytes placed into outbuf. - * @throws SignatureException if an error occurs or len is less than the - * actual signature length. + * Generates signature bytes of all the data fed to this instance and stores + * the result in the designated array. The format of the output depends on + * the underlying signature algorithm. + * + *

      This method cannot be abstract for backward compatibility reasons. + * After calling this method, the signature is reset to its initial state and + * can be used to generate additional signatures.

      + * + *

      IMPLEMENTATION NOTE:: Neither this method nor the GNU provider + * will return partial digests. If len is less than the + * signature length, this method will throw a {@link SignatureException}. If + * it is greater than or equal then it is ignored.

      + * + * @param outbuf + * the array of bytes to store the result in. + * @param offset + * the offset to start at in the array. + * @param len + * the number of the bytes to use in the array. + * @return the real number of bytes used. + * @throws SignatureException + * if the engine is not properly initialized. * @since 1.2 */ protected int engineSign(byte[] outbuf, int offset, int len) @@ -174,31 +177,32 @@ public abstract class SignatureSpi } /** - * Verifies the passed-in signature. - * - * @param sigBytes the signature bytes to be verified. - * @return true if the signature was verified, false - * if not. - * @throws SignatureException if the engine is not initialized properly, or - * the passed-in signature is improperly encoded or of the wrong type, etc. + * Verifies a designated signature. + * + * @param sigBytes + * the signature bytes to verify. + * @return true if verified, false otherwise. + * @throws SignatureException + * if the engine is not properly initialized or if it is the wrong + * signature. */ protected abstract boolean engineVerify(byte[] sigBytes) throws SignatureException; /** - *

      Verifies the passed-in signature in the specified array of - * bytes, starting at the specified offset.

      - * - *

      Note: Subclasses should overwrite the default implementation.

      - * - * @param sigBytes the signature bytes to be verified. - * @param offset the offset to start from in the array of bytes. - * @param length the number of bytes to use, starting at offset. - * @return true if the signature was verified, false - * if not. - * @throws SignatureException if the engine is not initialized properly, or - * the passed-in signature is improperly encoded or of the wrong - * type, etc. + * Convenience method which calls the method with the same name and one + * argument after copying the designated bytes into a temporary byte array. + * Subclasses may override this method for performance reasons. + * + * @param sigBytes + * the array of bytes to use. + * @param offset + * the offset to start from in the array of bytes. + * @param length + * the number of bytes to use, starting at offset. + * @return true if verified, false otherwise. + * @throws SignatureException + * if the engine is not properly initialized. */ protected boolean engineVerify(byte[] sigBytes, int offset, int length) throws SignatureException @@ -209,35 +213,32 @@ public abstract class SignatureSpi } /** - * Sets the specified algorithm parameter to the specified value. This method - * supplies a general-purpose mechanism through which it is possible to set - * the various parameters of this object. A parameter may be any settable - * parameter for the algorithm, such as a parameter size, or a source of - * random bits for signature generation (if appropriate), or an indication of - * whether or not to perform a specific but optional computation. A uniform - * algorithm-specific naming scheme for each parameter is desirable but left - * unspecified at this time. - * - * @param param the string identifier of the parameter. - * @param value the parameter value. - * @throws InvalidParameterException if param is an invalid - * parameter for this signature algorithm engine, the parameter is already set - * and cannot be set again, a security exception occurs, and so on. - * @deprecated Replaced by engineSetParameter(AlgorithmParameterSpec). + * Sets the specified algorithm parameter to the specified value. + * + * @param param + * the parameter name. + * @param value + * the parameter value. + * @throws InvalidParameterException + * if the parameter invalid, the parameter is already set and + * cannot be changed, a security exception occured, etc. + * @deprecated use the other setParameter. */ protected abstract void engineSetParameter(String param, Object value) throws InvalidParameterException; /** - * This method is overridden by providers to initialize this signature engine - * with the specified parameter set. - * - * @param params the parameters. - * @throws UnsupportedOperationException if this method is not overridden by - * a provider. - * @throws InvalidAlgorithmParameterException if this method is overridden by - * a provider and the the given parameters are inappropriate for this - * signature engine. + * Sets the signature engine with the specified {@link AlgorithmParameterSpec}. + * + *

      This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.

      + * + * @param params + * the parameters. + * @throws InvalidParameterException + * if the parameter is invalid, the parameter is already set and + * cannot be changed, a security exception occured, etc. */ protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException @@ -246,20 +247,16 @@ public abstract class SignatureSpi } /** - *

      This method is overridden by providers to return the parameters used - * with this signature engine, or null if this signature engine - * does not use any parameters.

      - * - *

      The returned parameters may be the same that were used to initialize - * this signature engine, or may contain a combination of default and randomly - * generated parameter values used by the underlying signature implementation - * if this signature engine requires algorithm parameters but was not - * initialized with any.

      - * - * @return the parameters used with this signature engine, or null - * if this signature engine does not use any parameters. - * @throws UnsupportedOperationException if this method is not overridden by - * a provider. + * The default implementaion of this method always throws a + * {@link UnsupportedOperationException}. It MUST be overridden by concrete + * implementations to return the appropriate {@link AlgorithmParameters} for + * this signature engine (or null when that engine does not use + * any parameters. + * + * @return the parameters used with this signature engine, or + * null if it does not use any parameters. + * @throws UnsupportedOperationException + * always. */ protected AlgorithmParameters engineGetParameters() { @@ -267,33 +264,24 @@ public abstract class SignatureSpi } /** - * Gets the value of the specified algorithm parameter. This method supplies - * a general-purpose mechanism through which it is possible to get the various - * parameters of this object. A parameter may be any settable parameter for - * the algorithm, such as a parameter size, or a source of random bits for - * signature generation (if appropriate), or an indication of whether or not - * to perform a specific but optional computation. A uniform algorithm-specific - * naming scheme for each parameter is desirable but left unspecified at this - * time. - * - * @param param the string name of the parameter. - * @return the object that represents the parameter value, or null - * if there is none. - * @throws InvalidParameterException if param is an invalid - * parameter for this engine, or another exception occurs while trying to get - * this parameter. - * @deprecated + * Returns the value for the specified algorithm parameter. + * + * @param param + * the parameter name. + * @return the parameter value. + * @throws InvalidParameterException + * if the parameter is invalid. + * @deprecated use the other getParameter */ protected abstract Object engineGetParameter(String param) throws InvalidParameterException; /** - * Returns a clone if the implementation is cloneable. - * - * @return a clone if the implementation is cloneable. - * @throws CloneNotSupportedException if this is called on an implementation - * that does not support {@link Cloneable}. - * @see Cloneable + * Returns a clone of this instance. + * + * @return a clone of this instance. + * @throws CloneNotSupportedException + * if the implementation does not support cloning. */ public Object clone() throws CloneNotSupportedException { diff --git a/java/security/SignedObject.java b/java/security/SignedObject.java index d565b2ea3..be5a67461 100644 --- a/java/security/SignedObject.java +++ b/java/security/SignedObject.java @@ -46,82 +46,34 @@ import java.io.ObjectOutputStream; import java.io.Serializable; /** - *

      SignedObject is a class for the purpose of creating authentic - * runtime objects whose integrity cannot be compromised without being detected. - *

      - * - *

      More specifically, a SignedObject contains another - * {@link Serializable} object, the (to-be-)signed object and its signature.

      - * - *

      The signed object is a "deep copy" (in serialized form) of an - * original object. Once the copy is made, further manipulation of the original - * object has no side effect on the copy.

      - * - *

      The underlying signing algorithm is designated by the {@link Signature} - * object passed to the constructor and the verify() method. A - * typical usage for signing is the following:

      - * - *
      - * Signature signingEngine = Signature.getInstance(algorithm, provider);
      - * SignedObject so = new SignedObject(myobject, signingKey, signingEngine);
      - * 
      - * - *

      A typical usage for verification is the following (having received - * SignedObject so):

      - * - *
      - * Signature verificationEngine = Signature.getInstance(algorithm, provider);
      - * if (so.verify(publickey, verificationEngine))
      - *   try
      - *     {
      - *       Object myobj = so.getObject();
      - *     }
      - *   catch (ClassNotFoundException ignored) {};
      - * 
      - * - *

      Several points are worth noting. First, there is no need to initialize the - * signing or verification engine, as it will be re-initialized inside the - * constructor and the verify() method. Secondly, for verification - * to succeed, the specified public key must be the public key corresponding to - * the private key used to generate the SignedObject.

      - * - *

      More importantly, for flexibility reasons, the constructor - * and verify() method allow for customized signature engines, - * which can implement signature algorithms that are not installed formally as - * part of a crypto provider. However, it is crucial that the programmer writing - * the verifier code be aware what {@link Signature} engine is being used, as - * its own implementation of the verify() method is invoked to - * verify a signature. In other words, a malicious {@link Signature} may choose - * to always return true on verification in an attempt to bypass a - * security check.

      - * - *

      The signature algorithm can be, among others, the NIST standard DSS, - * using DSA and SHA-1. The algorithm is specified using the same - * convention as that for signatures. The DSA algorithm using the - * SHA-1 message digest algorithm can be specified, for example, as - * "SHA/DSA" or "SHA-1/DSA" (they are equivalent). In - * the case of RSA, there are multiple choices for the message digest - * algorithm, so the signing algorithm could be specified as, for example, - * "MD2/RSA", "MD5/RSA" or "SHA-1/RSA". - * The algorithm name must be specified, as there is no default.

      - * - *

      The name of the Cryptography Package Provider is designated also by the - * {@link Signature} parameter to the constructor and the - * verify() method. If the provider is not specified, the default - * provider is used. Each installation can be configured to use a particular - * provider as default.

      - * - *

      Potential applications of SignedObject include:

      - * - *
        - *
      • It can be used internally to any Java runtime as an unforgeable - * authorization token -- one that can be passed around without the fear that - * the token can be maliciously modified without being detected.
      • - *
      • It can be used to sign and serialize data/object for storage outside the - * Java runtime (e.g., storing critical access control data on disk).
      • - *
      • Nested SignedObjects can be used to construct a logical sequence - * of signatures, resembling a chain of authorization and delegation.
      • - *
      + * SignedObject is used for storing runtime objects whose + * integrity cannot be compromised without being detected. + * + *

      SignedObject contains a {@link Serializable} object which is + * yet to be signed and a digital signature of that object.

      + * + *

      The signed copy is a "deep copy" (in serialized form) of an original + * object. Any changes to that original instance are not reflected in the + * enclosed copy inside this SignedObject.

      + * + *

      Several things to note are that, first there is no need to initialize the + * signature engine as this class will handle that automatically. Second, + * verification will only succeed if the public key corresponds to the private + * key used to generate the digital signature inside this + * SignedObject.

      + * + *

      For fexibility, the signature engine can be specified in the constructor + * or the verify() method. Programmers wishing to verify + * SignedObjects should be aware of the {@link Signature} engine + * they use. A malicious or flawed {@link Signature} implementation may always + * return true on verification thus circumventing the intended secrity check + * provided by the SignedObject.

      + * + *

      The GNU security provider offers an implementation of the standard NIST + * DSA which uses "DSA" and "SHA-1". It can be specified by "SHA/DSA", + * "SHA-1/DSA" or its OID. If the RSA signature algorithm is provided then it + * could be "MD2/RSA". "MD5/RSA", or "SHA-1/RSA". The algorithm must be + * specified because there is no default.

      * * @author Mark Benvenuto (ivymccough@worldnet.att.net) * @since 1.2 @@ -139,16 +91,22 @@ public final class SignedObject implements Serializable private String thealgorithm; /** - * Constructs a SignedObject from any {@link Serializable} - * object. The given object is signed with the given signing key, using the - * designated signature engine. - * - * @param object the object to be signed. - * @param signingKey the private key for signing. - * @param signingEngine the signature signing engine. - * @throws IOException if an error occurs during serialization. - * @throws InvalidKeyException if the key is invalid. - * @throws SignatureException if signing fails. + * Constructs a new instance of SignedObject from a + * {@link Serializable} object. The object is signed with a designated + * private key and a signature engine. + * + * @param object + * the object to sign. + * @param signingKey + * the key to use. + * @param signingEngine + * the signature engine to use. + * @throws IOException + * if a serialization error occurred. + * @throws InvalidKeyException + * if the key is invalid. + * @throws SignatureException + * if a signing error occurs. */ public SignedObject(Serializable object, PrivateKey signingKey, Signature signingEngine) @@ -170,12 +128,14 @@ public final class SignedObject implements Serializable } /** - * Retrieves the encapsulated object. The encapsulated object is de-serialized - * before it is returned. - * + * Returns the encapsulated object. The object is de-serialized before being + * returned. + * * @return the encapsulated object. - * @throws IOException if an error occurs during de-serialization. - * @throws ClassNotFoundException if an error occurs during de-serialization. + * @throws IOException + * if a de-serialization error occurs. + * @throws ClassNotFoundException + * if the encapsulated object's class was not found. */ public Object getObject() throws IOException, ClassNotFoundException { @@ -189,9 +149,9 @@ public final class SignedObject implements Serializable } /** - * Retrieves the signature on the signed object, in the form of a byte array. - * - * @return a copy of the signature. + * Returns the signature bytes of the encapsulated object. + * + * @return the signature bytes of the encapsulated object. */ public byte[] getSignature() { @@ -200,9 +160,9 @@ public final class SignedObject implements Serializable } /** - * Retrieves the name of the signature algorithm. - * - * @return the signature algorithm name. + * Returns the name of the signature algorithm. + * + * @return the name of the signature algorithm. */ public String getAlgorithm() { @@ -210,16 +170,19 @@ public final class SignedObject implements Serializable } /** - * Verifies that the signature in this SignedObject is the valid - * signature for the object stored inside, with the given verification key, - * using the designated verification engine. - * - * @param verificationKey the public key for verification. - * @param verificationEngine the signature verification engine. - * @return true if the signature is valid, false - * otherwise. - * @throws SignatureException if signature verification failed. - * @throws InvalidKeyException if the verification key is invalid. + * Verifies the encapsulated digital signature by checking that it was + * generated by the owner of a designated public key. + * + * @param verificationKey + * the public key to use. + * @param verificationEngine + * the signature engine to use. + * @return true if signature is correct, false + * otherwise. + * @throws InvalidKeyException + * if the key is invalid. + * @throws SignatureException + * if verification fails. */ public boolean verify(PublicKey verificationKey, Signature verificationEngine) throws InvalidKeyException, SignatureException diff --git a/java/security/Signer.java b/java/security/Signer.java index ae1463db8..c7780f6d3 100644 --- a/java/security/Signer.java +++ b/java/security/Signer.java @@ -38,35 +38,29 @@ exception statement from your version. */ package java.security; /** - *

      This class is used to represent an {@link Identity} that can also - * digitally sign data.

      - * - *

      The management of a signer's private keys is an important and sensitive - * issue that should be handled by subclasses as appropriate to their intended - * use.

      + * Signer is a subclass of {@link Identity}. It is used to store a + * digital signature key with an Identity. * * @author Mark Benvenuto (ivymccough@worldnet.att.net) - * @deprecated This class is no longer used. Its functionality has been replaced - * by java.security.KeyStore, the java.security.cert - * package, and java.security.Principal. + * @deprecated Replaced by java.security.KeyStore, the + * java.security.cert package, and java.security.Principal. */ public abstract class Signer extends Identity { private static final long serialVersionUID = -1763464102261361480L; private PrivateKey privateKey = null; - /** - * Creates a Signer. This constructor should only be used for - * serialization. - */ + /** Trivial constructor for serialization purposes. */ protected Signer() { } /** - * Creates a Signer with the specified identity name. - * - * @param name the identity name. + * Constructs a new instance of Signer with the specified + * identity name. + * + * @param name + * the name of the identity to use. */ public Signer(String name) { @@ -74,12 +68,16 @@ public abstract class Signer extends Identity } /** - * Creates a Signer with the specified identity name and scope. - * - * @param name the identity name. - * @param scope the scope of the identity. - * @throws KeyManagementException if there is already an identity with the - * same name in the scope. + * Constructs a new instance of Signer with the specified + * identity name and {@link IdentityScope}. + * + * @param name + * the name of the the identity to use. + * @param scope + * the {@link IdentityScope} to use. + * @throws KeyManagementException + * if a duplicate identity name exists within + * scope. */ public Signer(String name, IdentityScope scope) throws KeyManagementException { @@ -87,18 +85,12 @@ public abstract class Signer extends Identity } /** - *

      Returns this signer's private key.

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with "getSignerPrivateKey" as its - * argument to see if it's ok to return the private key.

      - * - * @return this signer's private key, or null if the private key - * has not yet been set. - * @throws SecurityException if a security manager exists and its - * checkSecurityAccess() method doesn't allow returning the - * private key. - * @see SecurityManager#checkSecurityAccess(String) + * Returns the private key of this Signer. + * + * @returns the private key of this Signer. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public PrivateKey getPrivateKey() { @@ -110,20 +102,17 @@ public abstract class Signer extends Identity } /** - *

      Sets the key pair (public key and private key) for this signer.

      - * - *

      First, if there is a security manager, its checkSecurityAccess() - * method is called with "setSignerKeyPair" as its - * argument to see if it's ok to set the key pair.

      - * - * @param pair an initialized key pair. - * @throws InvalidParameterException if the key pair is not properly - * initialized. - * @throws KeyException if the key pair cannot be set for any other reason. - * @throws SecurityException if a security manager exists and its - * checkSecurityAccess() method doesn't allow setting the key - * pair. - * @see SecurityManager#checkSecurityAccess(String) + * Specifies the {@link KeyPair} associated with this Signer. + * + * @param pair + * the {@link KeyPair} to use. + * @throws InvalidParameterException + * if the key-pair is invalid. + * @throws KeyException + * if any another key-related error occurs. + * @throws SecurityException + * if a {@link SecurityManager} is installed which disallows this + * operation. */ public final void setKeyPair(KeyPair pair) throws InvalidParameterException, KeyException @@ -151,12 +140,7 @@ public abstract class Signer extends Identity throw new InvalidParameterException(); } - /** - * Returns a string of information about the signer. - * - * @return a string of information about the signer. - * @see SecurityManager#checkSecurityAccess(String) - */ + /** @returns a string representing this Signer. */ public String toString() { return (getName() + ": " + privateKey); diff --git a/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java b/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java index d80b962d0..da7d7479d 100644 --- a/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java +++ b/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java @@ -54,6 +54,7 @@ public interface RSAMultiPrimePrivateCrtKey extends RSAPrivateKey { // Constants // -------------------------------------------------------------------------- + long serialVersionUID = 618058533534628008L; // Methods @@ -67,45 +68,45 @@ public interface RSAMultiPrimePrivateCrtKey extends RSAPrivateKey BigInteger getPublicExponent(); /** - * Returns the primeP. + * Returns the prime p. * - * @return the primeP. + * @return the prime p. */ BigInteger getPrimeP(); /** - * Returns the primeQ. + * Returns the prime q. * - * @return the primeQ. + * @return the prime q. */ BigInteger getPrimeQ(); /** - * Returns the primeExponentP. + * Returns the prime's exponent p. * - * @return the primeExponentP. + * @return the prime's exponent p. */ BigInteger getPrimeExponentP(); /** - * Returns the primeExponentQ. + * Returns the prime's exponent q. * - * @return the primeExponentQ. + * @return the prime's exponent q. */ BigInteger getPrimeExponentQ(); /** - * Returns the crtCoefficient. + * Returns the CRT Coefficient. * - * @return the crtCoefficient. + * @return the CRT Coefficient. */ BigInteger getCrtCoefficient(); /** - * Returns the otherPrimeInfo or null if there are only two - * prime factors (p and q). + * Returns the OtherPrimeInfo triplet MPIs or null if + * there are only two known prime factors (p and q). * - * @return the otherPrimeInfo. + * @return the OtherPrimeInfo INTEGERs. */ RSAOtherPrimeInfo[] getOtherPrimeInfo(); } diff --git a/java/security/spec/PSSParameterSpec.java b/java/security/spec/PSSParameterSpec.java index 7a14a24fb..f2a83d967 100644 --- a/java/security/spec/PSSParameterSpec.java +++ b/java/security/spec/PSSParameterSpec.java @@ -38,9 +38,9 @@ exception statement from your version. */ package java.security.spec; /** - * This class specifies a parameter spec for RSA PSS encoding scheme, as - * defined in the PKCS#1 v2.1. - * + * An implementation of {@link AlgorithmParameterSpec} for the RSA PSS encoding + * scheme. + * * @since 1.4 * @see AlgorithmParameterSpec * @see java.security.Signature @@ -56,12 +56,13 @@ public class PSSParameterSpec implements AlgorithmParameterSpec // -------------------------------------------------------------------------- /** - * Creates a new PSSParameterSpec given the salt length as - * defined in PKCS#1. - * - * @param saltLen the length of salt in bits to be used in PKCS#1 PSS encoding. - * @throws IllegalArgumentException if saltLen is less than - * 0. + * Construct a new instance of PSSParameterSpec given a salt + * length. + * + * @param saltLen + * the length in bits of the salt. + * @throws IllegalArgumentException + * if saltLen is less than 0. */ public PSSParameterSpec(int saltLen) { @@ -78,11 +79,7 @@ public class PSSParameterSpec implements AlgorithmParameterSpec // Instance methods // -------------------------------------------------------------------------- - /** - * Returns the salt length in bits. - * - * @return the salt length. - */ + /** @return the length (in bits) of the salt. */ public int getSaltLength() { return this.saltLen; diff --git a/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java b/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java index 519a02913..9e8ad0da7 100644 --- a/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java +++ b/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java @@ -40,9 +40,9 @@ package java.security.spec; import java.math.BigInteger; /** - * This class specifies an RSA multi-prime private key, as defined in the + * This class represents an RSA multi-prime private key, as defined in the * PKCS#1 v2.1, using the Chinese Remainder Theorem (CRT) information - * values for efficiency. + * values. * * @since 1.4 * @see java.security.Key @@ -70,29 +70,35 @@ public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec // -------------------------------------------------------------------------- /** - *

      Creates a new RSAMultiPrimePrivateCrtKeySpec given the - * modulus, publicExponent, privateExponent, primeP, primeQ, primeExponentP, - * primeExponentQ, crtCoefficient, and otherPrimeInfo as defined in PKCS#1 - * v2.1.

      - * + * Constructs a new instance of RSAMultiPrimePrivateCrtKeySpec + * given the various PKCS#1 v2.1 parameters. + * *

      Note that otherPrimeInfo is cloned when constructing this * object.

      - * - * @param modulus the modulus n. - * @param publicExponent the public exponent e. - * @param privateExponent the private exponent d. - * @param primeP the prime factor p of n. - * @param primeQ the prime factor q of n. - * @param primeExponentP this is d mod (p-1). - * @param primeExponentQ this is d mod (q-1). - * @param crtCoefficient the Chinese Remainder Theorem coefficient q-1 mod p. - * @param otherPrimeInfo triplets of the rest of primes, null - * can be specified if there are only two prime factors (p and q). - * @throws NullPointerException if any of the parameters, i.e. modulus, - * publicExponent, privateExponent, primeP, primeQ, primeExponentP, - * primeExponentQ, crtCoefficient, is null. - * @throws IllegalArgumentException if an empty, i.e. 0-length, - * otherPrimeInfo is specified. + * + * @param modulus + * the modulus n. + * @param publicExponent + * the public exponent e. + * @param privateExponent + * the private exponent d. + * @param primeP + * the prime factor p of n. + * @param primeQ + * the prime factor q of n. + * @param primeExponentP + * this is d mod (p-1). + * @param primeExponentQ + * this is d mod (q-1). + * @param crtCoefficient + * the Chinese Remainder Theorem coefficient q-1 mod p. + * @param otherPrimeInfo + * triplets of the rest of primes, null can be + * specified if there are only two prime factors (p and q). + * @throws NullPointerException + * if any of the parameters is null. + * @throws IllegalArgumentException + * if an empty otherPrimeInfo is specified. */ public RSAMultiPrimePrivateCrtKeySpec(BigInteger modulus, BigInteger publicExponent, @@ -153,9 +159,9 @@ public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec } /** - * Returns the primeP. + * Returns the prime p. * - * @return the primeP. + * @return the prime p. */ public BigInteger getPrimeP() { @@ -163,9 +169,9 @@ public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec } /** - * Returns the primeQ. + * Returns the prime q. * - * @return the primeQ. + * @return the prime q. */ public BigInteger getPrimeQ() { @@ -173,9 +179,9 @@ public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec } /** - * Returns the primeExponentP. + * Returns d mod (p-1). * - * @return the primeExponentP. + * @return d mod (p-1). */ public BigInteger getPrimeExponentP() { @@ -183,9 +189,9 @@ public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec } /** - * Returns the primeExponentQ. + * Returns d mod (q-1). * - * @return the primeExponentQ. + * @return d mod (q-1). */ public BigInteger getPrimeExponentQ() { @@ -193,9 +199,9 @@ public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec } /** - * Returns the crtCoefficient. + * Returns the CRT Coefficient q-1 mod p. * - * @return the crtCoefficient. + * @return the CRT Coefficient q-1 mod p. */ public BigInteger getCrtCoefficient() { @@ -203,10 +209,10 @@ public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec } /** - * Returns a copy of the otherPrimeInfo or null if there are - * only two prime factors (p and q). + * Returns a clone of otherPrimeInfo or null if + * it was null at construction time. * - * @return the otherPrimeInfo. + * @return a cloned copy of otherPrimeInfo. */ public RSAOtherPrimeInfo[] getOtherPrimeInfo() { diff --git a/java/security/spec/RSAOtherPrimeInfo.java b/java/security/spec/RSAOtherPrimeInfo.java index 654bcb574..03cdca227 100644 --- a/java/security/spec/RSAOtherPrimeInfo.java +++ b/java/security/spec/RSAOtherPrimeInfo.java @@ -40,17 +40,8 @@ package java.security.spec; import java.math.BigInteger; /** - * This class represents the triplet (prime, exponent, and coefficient) inside - * RSA's OtherPrimeInfo structure, as defined in the PKCS#1 v2.1. The ASN.1 - * syntax of RSA's OtherPrimeInfo is as follows: - * - *
      - *  OtherPrimeInfo ::= SEQUENCE {
      - *    prime INTEGER,
      - *    exponent INTEGER,
      - *    coefficient INTEGER
      - *  }
      - * 
      + * An in-memory representation of the RSA triplet (prime, exponent, and + * coefficient) inside a PKCS#1 v2.1 OtherPrimeInfo structure. * * @since 1.4 * @see RSAPrivateCrtKeySpec @@ -69,14 +60,16 @@ public class RSAOtherPrimeInfo // -------------------------------------------------------------------------- /** - * Creates a new RSAOtherPrimeInfo given the prime, - * primeExponent, and crtCoefficient as defined in PKCS#1. - * - * @param prime the prime factor of n. - * @param primeExponent the exponent. - * @param crtCoefficient the Chinese Remainder Theorem coefficient. - * @throws NullPointerException if any of the parameters, i.e. prime, - * primeExponent, crtCoefficient, is null. + * Constructs a new RSAOtherPrimeInfo given the PKCS#1 MPIs. + * + * @param prime + * the prime factor of n. + * @param primeExponent + * the exponent. + * @param crtCoefficient + * the Chinese Remainder Theorem coefficient. + * @throws NullPointerException + * if any of the parameters is null. */ public RSAOtherPrimeInfo(BigInteger prime, BigInteger primeExponent, BigInteger crtCoefficient) @@ -122,9 +115,9 @@ public class RSAOtherPrimeInfo } /** - * Returns the prime's crtCoefficient. + * Returns the CRT Coefficient. * - * @return the crtCoefficient. + * @return the CRT Coefficient. */ public final BigInteger getCrtCoefficient() { diff --git a/java/util/AbstractCollection.java b/java/util/AbstractCollection.java index a84f221af..7af850b46 100644 --- a/java/util/AbstractCollection.java +++ b/java/util/AbstractCollection.java @@ -435,7 +435,9 @@ public abstract class AbstractCollection * of the form "[a, b, ...]" where a and b etc are the results of calling * toString on the elements of the collection. This implementation obtains an * Iterator over the Collection and adds each element to a StringBuffer as it - * is returned by the iterator. + * is returned by the iterator. "" is inserted when the collection + * contains itself (only works for direct containment, not for collections + * inside collections). * * @return a String representation of the Collection */ @@ -443,10 +445,16 @@ public abstract class AbstractCollection { Iterator itr = iterator(); StringBuffer r = new StringBuffer("["); - for (int pos = size(); pos > 0; pos--) + boolean hasNext = itr.hasNext(); + while (hasNext) { - r.append(itr.next()); - if (pos > 1) + Object o = itr.next(); + if (o == this) + r.append(""); + else + r.append(o); + hasNext = itr.hasNext(); + if (hasNext) r.append(", "); } r.append("]"); diff --git a/java/util/Hashtable.java b/java/util/Hashtable.java index 8dfd6215e..37ee03ccc 100644 --- a/java/util/Hashtable.java +++ b/java/util/Hashtable.java @@ -1,6 +1,7 @@ /* Hashtable.java -- a class providing a basic hashtable data structure, mapping Object --> Object - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -110,12 +111,6 @@ public class Hashtable extends Dictionary */ private static final int DEFAULT_CAPACITY = 11; - /** An "enum" of iterator types. */ - // Package visible for use by nested classes. - static final int KEYS = 0, - VALUES = 1, - ENTRIES = 2; - /** * The default load factor; this is explicitly specified by the spec. */ @@ -303,7 +298,7 @@ public class Hashtable extends Dictionary */ public Enumeration keys() { - return new Enumerator(KEYS); + return new KeyEnumerator(); } /** @@ -317,7 +312,7 @@ public class Hashtable extends Dictionary */ public Enumeration elements() { - return new Enumerator(VALUES); + return new ValueEnumerator(); } /** @@ -334,21 +329,20 @@ public class Hashtable extends Dictionary */ public synchronized boolean contains(Object value) { + if (value == null) + throw new NullPointerException(); + for (int i = buckets.length - 1; i >= 0; i--) { HashEntry e = buckets[i]; while (e != null) { - if (value.equals(e.value)) + if (e.value.equals(value)) return true; e = e.next; } } - // Must throw on null argument even if the table is empty - if (value == null) - throw new NullPointerException(); - return false; } @@ -386,7 +380,7 @@ public class Hashtable extends Dictionary HashEntry e = buckets[idx]; while (e != null) { - if (key.equals(e.key)) + if (e.key.equals(key)) return true; e = e.next; } @@ -409,7 +403,7 @@ public class Hashtable extends Dictionary HashEntry e = buckets[idx]; while (e != null) { - if (key.equals(e.key)) + if (e.key.equals(key)) return e.value; e = e.next; } @@ -439,7 +433,7 @@ public class Hashtable extends Dictionary while (e != null) { - if (key.equals(e.key)) + if (e.key.equals(key)) { // Bypass e.setValue, since we already know value is non-null. V r = e.value; @@ -485,7 +479,7 @@ public class Hashtable extends Dictionary while (e != null) { - if (key.equals(e.key)) + if (e.key.equals(key)) { modCount++; if (last == null) @@ -584,9 +578,8 @@ public class Hashtable extends Dictionary { // Since we are already synchronized, and entrySet().iterator() // would repeatedly re-lock/release the monitor, we directly use the - // unsynchronized HashIterator instead. - Iterator> entries - = new HashIterator>(ENTRIES); + // unsynchronized EntryIterator instead. + Iterator> entries = new EntryIterator(); StringBuffer r = new StringBuffer("{"); for (int pos = size; pos > 0; pos--) { @@ -628,7 +621,7 @@ public class Hashtable extends Dictionary public Iterator iterator() { - return new HashIterator(KEYS); + return new KeyIterator(); } public void clear() @@ -686,7 +679,7 @@ public class Hashtable extends Dictionary public Iterator iterator() { - return new HashIterator(VALUES); + return new ValueIterator(); } public void clear() @@ -738,7 +731,7 @@ public class Hashtable extends Dictionary public Iterator> iterator() { - return new HashIterator>(ENTRIES); + return new EntryIterator(); } public void clear() @@ -782,7 +775,7 @@ public class Hashtable extends Dictionary */ public boolean equals(Object o) { - // No need to synchronize, entrySet().equals() does that. + // no need to synchronize, entrySet().equals() does that. if (o == this) return true; if (!(o instanceof Map)) @@ -802,8 +795,8 @@ public class Hashtable extends Dictionary { // Since we are already synchronized, and entrySet().iterator() // would repeatedly re-lock/release the monitor, we directly use the - // unsynchronized HashIterator instead. - Iterator> itr = new HashIterator>(ENTRIES); + // unsynchronized EntryIterator instead. + Iterator> itr = new EntryIterator(); int hashcode = 0; for (int pos = size; pos > 0; pos--) hashcode += itr.next().hashCode(); @@ -848,7 +841,7 @@ public class Hashtable extends Dictionary HashEntry e = buckets[idx]; while (e != null) { - if (o.equals(e)) + if (e.equals(o)) return e; e = e.next; } @@ -909,8 +902,12 @@ public class Hashtable extends Dictionary if (dest != null) { - while (dest.next != null) - dest = dest.next; + HashEntry next = dest.next; + while (next != null) + { + dest = next; + next = dest.next; + } dest.next = e; } else @@ -945,8 +942,8 @@ public class Hashtable extends Dictionary s.writeInt(size); // Since we are already synchronized, and entrySet().iterator() // would repeatedly re-lock/release the monitor, we directly use the - // unsynchronized HashIterator instead. - Iterator> it = new HashIterator>(ENTRIES); + // unsynchronized EntryIterator instead. + Iterator> it = new EntryIterator(); while (it.hasNext()) { HashEntry entry = (HashEntry) it.next(); @@ -985,21 +982,18 @@ public class Hashtable extends Dictionary /** * A class which implements the Iterator interface and is used for * iterating over Hashtables. - * This implementation is parameterized to give a sequential view of - * keys, values, or entries; it also allows the removal of elements, - * as per the Javasoft spec. Note that it is not synchronized; this is - * a performance enhancer since it is never exposed externally and is - * only used within synchronized blocks above. + * This implementation iterates entries. Subclasses are used to + * iterate key and values. It also allows the removal of elements, + * as per the Javasoft spec. Note that it is not synchronized; this + * is a performance enhancer since it is never exposed externally + * and is only used within synchronized blocks above. * * @author Jon Zeppieri + * @author Fridjof Siebert */ - private final class HashIterator implements Iterator + private class EntryIterator + implements Iterator> { - /** - * The type of this Iterator: {@link #KEYS}, {@link #VALUES}, - * or {@link #ENTRIES}. - */ - final int type; /** * The number of modifications to the backing Hashtable that we know about. */ @@ -1018,14 +1012,13 @@ public class Hashtable extends Dictionary HashEntry next; /** - * Construct a new HashIterator with the supplied type. - * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + * Construct a new EntryIterator */ - HashIterator(int type) + EntryIterator() { - this.type = type; } + /** * Returns true if the Iterator has more elements. * @return true if there are more elements @@ -1044,7 +1037,7 @@ public class Hashtable extends Dictionary * @throws ConcurrentModificationException if the hashtable was modified * @throws NoSuchElementException if there is none */ - public T next() + public Map.Entry next() { if (knownMod != modCount) throw new ConcurrentModificationException(); @@ -1054,15 +1047,14 @@ public class Hashtable extends Dictionary HashEntry e = next; while (e == null) - e = buckets[--idx]; + if (idx <= 0) + return null; + else + e = buckets[--idx]; next = e.next; last = e; - if (type == VALUES) - return (T) e.value; - if (type == KEYS) - return (T) e.key; - return (T) e; + return e; } /** @@ -1082,29 +1074,156 @@ public class Hashtable extends Dictionary last = null; knownMod++; } - } // class HashIterator + } // class EntryIterator + /** + * A class which implements the Iterator interface and is used for + * iterating over keys in Hashtables. This class uses an + * EntryIterator to obtain the keys of each entry. + * + * @author Fridtjof Siebert + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private class KeyIterator + implements Iterator + { + /** + * This entry iterator is used for most operations. Only + * next() gives a different result, by returning just + * the key rather than the whole element. + */ + private EntryIterator iterator; + + /** + * Construct a new KeyIterator + */ + KeyIterator() + { + iterator = new EntryIterator(); + } + + + /** + * Returns true if the entry iterator has more elements. + * + * @return true if there are more elements + * @throws ConcurrentModificationException if the hashtable was modified + */ + public boolean hasNext() + { + return iterator.hasNext(); + } + + /** + * Returns the next element in the Iterator's sequential view. + * + * @return the next element + * + * @throws ConcurrentModificationException if the hashtable was modified + * @throws NoSuchElementException if there is none + */ + public K next() + { + return ((HashEntry) iterator.next()).key; + } + + /** + * Removes the last element used by the next() method + * using the entry iterator. + * + * @throws ConcurrentModificationException if the hashtable was modified + * @throws IllegalStateException if called when there is no last element + */ + public void remove() + { + iterator.remove(); + } + } // class KeyIterator + /** - * Enumeration view of this Hashtable, providing sequential access to its - * elements; this implementation is parameterized to provide access either - * to the keys or to the values in the Hashtable. + * A class which implements the Iterator interface and is used for + * iterating over values in Hashtables. This class uses an + * EntryIterator to obtain the values of each entry. + * + * @author Fridtjof Siebert + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private class ValueIterator + implements Iterator + { + + /** + * This entry iterator is used for most operations. Only + * next() gives a different result, by returning just + * the value rather than the whole element. + */ + private EntryIterator iterator; + + /** + * Construct a new KeyIterator + */ + ValueIterator() + { + iterator = new EntryIterator(); + } + + + /** + * Returns true if the entry iterator has more elements. + * + * @return true if there are more elements + * @throws ConcurrentModificationException if the hashtable was modified + */ + public boolean hasNext() + { + return iterator.hasNext(); + } + + /** + * Returns the value of the next element in the iterator's sequential view. + * + * @return the next value + * + * @throws ConcurrentModificationException if the hashtable was modified + * @throws NoSuchElementException if there is none + */ + public V next() + { + return ((HashEntry) iterator.next()).value; + } + + /** + * Removes the last element used by the next() method + * using the entry iterator. + * + * @throws ConcurrentModificationException if the hashtable was modified + * @throws IllegalStateException if called when there is no last element + */ + public void remove() + { + iterator.remove(); + } + + } // class ValueIterator + + /** + * Enumeration view of the entries in this Hashtable, providing + * sequential access to its elements. * * NOTE: Enumeration is not safe if new elements are put in the table * as this could cause a rehash and we'd completely lose our place. Even * without a rehash, it is undetermined if a new element added would * appear in the enumeration. The spec says nothing about this, but - * the "Java Class Libraries" book infers that modifications to the + * the "Java Class Libraries" book implies that modifications to the * hashtable during enumeration causes indeterminate results. Don't do it! * * @author Jon Zeppieri + * @author Fridjof Siebert */ - private final class Enumerator implements Enumeration + private class EntryEnumerator + implements Enumeration> { - /** - * The type of this Iterator: {@link #KEYS} or {@link #VALUES}. - */ - final int type; /** The number of elements remaining to be returned by next(). */ int count = size; /** Current index in the physical hash table. */ @@ -1118,11 +1237,10 @@ public class Hashtable extends Dictionary /** * Construct the enumeration. - * @param type either {@link #KEYS} or {@link #VALUES}. */ - Enumerator(int type) + EntryEnumerator() { - this.type = type; + // Nothing to do here. } /** @@ -1139,7 +1257,7 @@ public class Hashtable extends Dictionary * @return the next element * @throws NoSuchElementException if there is none. */ - public T nextElement() + public Map.Entry nextElement() { if (count == 0) throw new NoSuchElementException("Hashtable Enumerator"); @@ -1147,10 +1265,136 @@ public class Hashtable extends Dictionary HashEntry e = next; while (e == null) - e = buckets[--idx]; + if (idx <= 0) + return null; + else + e = buckets[--idx]; next = e.next; - return type == VALUES ? (T) e.value : (T) e.key; + return e; + } + } // class EntryEnumerator + + + /** + * Enumeration view of this Hashtable, providing sequential access to its + * elements. + * + * NOTE: Enumeration is not safe if new elements are put in the table + * as this could cause a rehash and we'd completely lose our place. Even + * without a rehash, it is undetermined if a new element added would + * appear in the enumeration. The spec says nothing about this, but + * the "Java Class Libraries" book implies that modifications to the + * hashtable during enumeration causes indeterminate results. Don't do it! + * + * @author Jon Zeppieri + * @author Fridjof Siebert + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private final class KeyEnumerator + implements Enumeration + { + /** + * This entry enumerator is used for most operations. Only + * nextElement() gives a different result, by returning just + * the key rather than the whole element. + */ + private EntryEnumerator enumerator; + + /** + * Construct a new KeyEnumerator + */ + KeyEnumerator() + { + enumerator = new EntryEnumerator(); + } + + + /** + * Returns true if the entry enumerator has more elements. + * + * @return true if there are more elements + * @throws ConcurrentModificationException if the hashtable was modified + */ + public boolean hasMoreElements() + { + return enumerator.hasMoreElements(); + } + + /** + * Returns the next element. + * @return the next element + * @throws NoSuchElementException if there is none. + */ + public K nextElement() + { + HashEntry entry = (HashEntry) enumerator.nextElement(); + K retVal = null; + if (entry != null) + retVal = entry.key; + return retVal; + } + } // class KeyEnumerator + + + /** + * Enumeration view of this Hashtable, providing sequential access to its + * values. + * + * NOTE: Enumeration is not safe if new elements are put in the table + * as this could cause a rehash and we'd completely lose our place. Even + * without a rehash, it is undetermined if a new element added would + * appear in the enumeration. The spec says nothing about this, but + * the "Java Class Libraries" book implies that modifications to the + * hashtable during enumeration causes indeterminate results. Don't do it! + * + * @author Jon Zeppieri + * @author Fridjof Siebert + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private final class ValueEnumerator + implements Enumeration + { + /** + * This entry enumerator is used for most operations. Only + * nextElement() gives a different result, by returning just + * the value rather than the whole element. + */ + private EntryEnumerator enumerator; + + /** + * Construct a new ValueEnumerator + */ + ValueEnumerator() + { + enumerator = new EntryEnumerator(); } - } // class Enumerator + + + /** + * Returns true if the entry enumerator has more elements. + * + * @return true if there are more elements + * @throws ConcurrentModificationException if the hashtable was modified + */ + public boolean hasMoreElements() + { + return enumerator.hasMoreElements(); + } + + /** + * Returns the next element. + * @return the next element + * @throws NoSuchElementException if there is none. + */ + public V nextElement() + { + HashEntry entry = (HashEntry) enumerator.nextElement(); + V retVal = null; + if (entry != null) + retVal = entry.value; + return retVal; + } + } // class ValueEnumerator + } // class Hashtable diff --git a/java/util/logging/LogManager.java b/java/util/logging/LogManager.java index 420c97e59..5897a12af 100644 --- a/java/util/logging/LogManager.java +++ b/java/util/logging/LogManager.java @@ -41,6 +41,7 @@ package java.util.logging; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; @@ -295,6 +296,28 @@ public class LogManager if (parent != logger.getParent()) logger.setParent(parent); + // The level of the newly added logger must be specified. + // The easiest case is if there is a level for exactly this logger + // in the properties. If no such level exists the level needs to be + // searched along the hirachy. So if there is a new logger 'foo.blah.blub' + // and an existing parent logger 'foo' the properties 'foo.blah.blub.level' + // and 'foo.blah.level' need to be checked. If both do not exist in the + // properties the level of the new logger is set to 'null' (i.e. it uses the + // level of its parent 'foo'). + Level logLevel = logger.getLevel(); + String searchName = name; + String parentName = parent != null ? parent.getName() : ""; + while (logLevel == null && ! searchName.equals(parentName)) + { + logLevel = getLevelProperty(searchName + ".level", logLevel); + int index = searchName.lastIndexOf('.'); + if(index > -1) + searchName = searchName.substring(0,index); + else + searchName = ""; + } + logger.setLevel(logLevel); + /* It can happen that existing loggers should be children of * the newly added logger. For example, assume that there * already exist loggers under the names "", "foo", and "foo.bar.baz". @@ -488,23 +511,37 @@ public class LogManager path = System.getProperty("java.util.logging.config.file"); if ((path == null) || (path.length() == 0)) { - String url = (System.getProperty("gnu.classpath.home.url") - + "/logging.properties"); - inputStream = new URL(url).openStream(); + String url = (System.getProperty("gnu.classpath.home.url") + + "/logging.properties"); + try + { + inputStream = new URL(url).openStream(); + } + catch (Exception e) + { + inputStream=null; + } + + // If no config file could be found use a default configuration. + if(inputStream == null) + { + String defaultConfig = "handlers = java.util.logging.ConsoleHandler \n" + + ".level=INFO \n"; + inputStream = new ByteArrayInputStream(defaultConfig.getBytes()); + } } else inputStream = new java.io.FileInputStream(path); try { - readConfiguration(inputStream); + readConfiguration(inputStream); } finally { - /* Close the stream in order to save - * resources such as file descriptors. - */ - inputStream.close(); + // Close the stream in order to save + // resources such as file descriptors. + inputStream.close(); } } diff --git a/java/util/logging/SimpleFormatter.java b/java/util/logging/SimpleFormatter.java index ff53db8c0..2ebb1a148 100644 --- a/java/util/logging/SimpleFormatter.java +++ b/java/util/logging/SimpleFormatter.java @@ -39,6 +39,8 @@ exception statement from your version. */ package java.util.logging; +import java.io.PrintWriter; +import java.io.StringWriter; import java.text.DateFormat; import java.util.Date; @@ -114,6 +116,14 @@ public class SimpleFormatter buf.append(lineSep); + Throwable throwable = record.getThrown(); + if (throwable != null) + { + StringWriter sink = new StringWriter(); + throwable.printStackTrace(new PrintWriter(sink, true)); + buf.append(sink.toString()); + } + return buf.toString(); } } diff --git a/java/util/regex/MatchResult.java b/java/util/regex/MatchResult.java new file mode 100644 index 000000000..c82d8cc99 --- /dev/null +++ b/java/util/regex/MatchResult.java @@ -0,0 +1,81 @@ +/* MatchResult.java -- Result of a regular expression match. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util.regex; + +/** + * This interface represents the result of a regular expression match. + * It can be used to query the contents of the match, but not to modify + * them. + * @since 1.5 + */ +public interface MatchResult +{ + /** Returns the index just after the last matched character. */ + int end(); + + /** + * Returns the index just after the last matched character of the + * given sub-match group. + * @param group the sub-match group + */ + int end(int group); + + /** Returns the substring of the input which was matched. */ + String group(); + + /** + * Returns the substring of the input which was matched by the + * given sub-match group. + * @param group the sub-match group + */ + String group(int group); + + /** Returns the number of sub-match groups in the matching pattern. */ + int groupCount(); + + /** Returns the index of the first character of the match. */ + int start(); + + /** + * Returns the index of the first character of the given sub-match + * group. + * @param group the sub-match group + */ + int start(int group); +} diff --git a/java/util/regex/Matcher.java b/java/util/regex/Matcher.java index 5d04bdbfc..98086bfdb 100644 --- a/java/util/regex/Matcher.java +++ b/java/util/regex/Matcher.java @@ -1,5 +1,5 @@ /* Matcher.java -- Instance of a regular expression applied to a char sequence. - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,7 @@ exception statement from your version. */ package java.util.regex; +import gnu.regexp.RE; import gnu.regexp.REMatch; /** @@ -45,7 +46,7 @@ import gnu.regexp.REMatch; * * @since 1.4 */ -public final class Matcher +public final class Matcher implements MatchResult { private Pattern pattern; private CharSequence input; @@ -74,7 +75,8 @@ public final class Matcher assertMatchOp(); sb.append(input.subSequence(appendPosition, match.getStartIndex()).toString()); - sb.append(match.substituteInto(replacement)); + sb.append(RE.getReplacement(replacement, match, + RE.REG_REPLACE_USE_BACKSLASHESCAPE)); appendPosition = match.getEndIndex(); return this; } @@ -189,7 +191,8 @@ public final class Matcher { reset(); // Semantics might not quite match - return pattern.getRE().substitute(input, replacement, position); + return pattern.getRE().substitute(input, replacement, position, + RE.REG_REPLACE_USE_BACKSLASHESCAPE); } /** @@ -198,7 +201,8 @@ public final class Matcher public String replaceAll (String replacement) { reset(); - return pattern.getRE().substituteAll(input, replacement, position); + return pattern.getRE().substituteAll(input, replacement, position, + RE.REG_REPLACE_USE_BACKSLASHESCAPE); } public int groupCount () @@ -233,10 +237,15 @@ public final class Matcher */ public boolean matches () { - if (lookingAt()) + match = pattern.getRE().getMatch(input, 0, RE.REG_TRY_ENTIRE_MATCH); + if (match != null) { - if (position == input.length()) - return true; + if (match.getStartIndex() == 0) + { + position = match.getEndIndex(); + if (position == input.length()) + return true; + } match = null; } return false; diff --git a/java/util/regex/PatternSyntaxException.java b/java/util/regex/PatternSyntaxException.java index 0c80e119c..41e650d32 100644 --- a/java/util/regex/PatternSyntaxException.java +++ b/java/util/regex/PatternSyntaxException.java @@ -41,6 +41,7 @@ package java.util.regex; * Indicates illegal pattern for regular expression. * Includes state to inspect the pattern and what and where the expression * was not valid regular expression. + * @since 1.4 */ public class PatternSyntaxException extends IllegalArgumentException { diff --git a/java/util/zip/ZipConstants.java b/java/util/zip/ZipConstants.java index 952a44def..6d664196a 100644 --- a/java/util/zip/ZipConstants.java +++ b/java/util/zip/ZipConstants.java @@ -1,5 +1,5 @@ /* java.util.zip.ZipConstants - Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,7 +41,7 @@ interface ZipConstants { /* The local file header */ int LOCHDR = 30; - int LOCSIG = 'P'|('K'<<8)|(3<<16)|(4<<24); + long LOCSIG = 'P'|('K'<<8)|(3<<16)|(4<<24); int LOCVER = 4; int LOCFLG = 6; @@ -54,7 +54,7 @@ interface ZipConstants int LOCEXT = 28; /* The Data descriptor */ - int EXTSIG = 'P'|('K'<<8)|(7<<16)|(8<<24); + long EXTSIG = 'P'|('K'<<8)|(7<<16)|(8<<24); int EXTHDR = 16; int EXTCRC = 4; @@ -62,7 +62,7 @@ interface ZipConstants int EXTLEN = 12; /* The central directory file header */ - int CENSIG = 'P'|('K'<<8)|(1<<16)|(2<<24); + long CENSIG = 'P'|('K'<<8)|(1<<16)|(2<<24); int CENHDR = 46; int CENVEM = 4; @@ -82,7 +82,7 @@ interface ZipConstants int CENOFF = 42; /* The entries in the end of central directory */ - int ENDSIG = 'P'|('K'<<8)|(5<<16)|(6<<24); + long ENDSIG = 'P'|('K'<<8)|(5<<16)|(6<<24); int ENDHDR = 22; /* The following two fields are missing in SUN JDK */ diff --git a/java/util/zip/ZipFile.java b/java/util/zip/ZipFile.java index 1bc66e267..75a466a5f 100644 --- a/java/util/zip/ZipFile.java +++ b/java/util/zip/ZipFile.java @@ -1,5 +1,5 @@ /* ZipFile.java -- - Copyright (C) 2001, 2002, 2003, 2004, 2005 + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,8 +41,6 @@ package java.util.zip; import gnu.java.util.EmptyEnumeration; -import java.io.BufferedInputStream; -import java.io.DataInput; import java.io.EOFException; import java.io.File; import java.io.IOException; @@ -141,23 +139,33 @@ public class ZipFile implements ZipConstants checkZipFile(); } - private void checkZipFile() throws IOException, ZipException + private void checkZipFile() throws ZipException { - byte[] magicBuf = new byte[4]; - boolean validRead = true; + boolean valid = false; try { - raf.readFully(magicBuf); - } - catch (EOFException eof) + byte[] buf = new byte[4]; + raf.readFully(buf); + int sig = buf[0] & 0xFF + | ((buf[1] & 0xFF) << 8) + | ((buf[2] & 0xFF) << 16) + | ((buf[3] & 0xFF) << 24); + valid = sig == LOCSIG; + } + catch (IOException _) { - validRead = false; } - if (validRead == false || readLeInt(magicBuf, 0) != LOCSIG) + if (!valid) { - raf.close(); + try + { + raf.close(); + } + catch (IOException _) + { + } throw new ZipException("Not a valid zip file"); } } @@ -171,69 +179,6 @@ public class ZipFile implements ZipConstants throw new IllegalStateException("ZipFile has closed: " + name); } - /** - * Read an unsigned short in little endian byte order from the given - * DataInput stream using the given byte buffer. - * - * @param di DataInput stream to read from. - * @param b the byte buffer to read in (must be at least 2 bytes long). - * @return The value read. - * - * @exception IOException if a i/o error occured. - * @exception EOFException if the file ends prematurely - */ - private int readLeShort(DataInput di, byte[] b) throws IOException - { - di.readFully(b, 0, 2); - return (b[0] & 0xff) | (b[1] & 0xff) << 8; - } - - /** - * Read an int in little endian byte order from the given - * DataInput stream using the given byte buffer. - * - * @param di DataInput stream to read from. - * @param b the byte buffer to read in (must be at least 4 bytes long). - * @return The value read. - * - * @exception IOException if a i/o error occured. - * @exception EOFException if the file ends prematurely - */ - private int readLeInt(DataInput di, byte[] b) throws IOException - { - di.readFully(b, 0, 4); - return ((b[0] & 0xff) | (b[1] & 0xff) << 8) - | ((b[2] & 0xff) | (b[3] & 0xff) << 8) << 16; - } - - /** - * Read an unsigned short in little endian byte order from the given - * byte buffer at the given offset. - * - * @param b the byte array to read from. - * @param off the offset to read from. - * @return The value read. - */ - private int readLeShort(byte[] b, int off) - { - return (b[off] & 0xff) | (b[off+1] & 0xff) << 8; - } - - /** - * Read an int in little endian byte order from the given - * byte buffer at the given offset. - * - * @param b the byte array to read from. - * @param off the offset to read from. - * @return The value read. - */ - private int readLeInt(byte[] b, int off) - { - return ((b[off] & 0xff) | (b[off+1] & 0xff) << 8) - | ((b[off+2] & 0xff) | (b[off+3] & 0xff) << 8) << 16; - } - - /** * Read the central directory of a zip file and fill the entries * array. This is called exactly once when first needed. It is called @@ -246,63 +191,48 @@ public class ZipFile implements ZipConstants { /* Search for the End Of Central Directory. When a zip comment is * present the directory may start earlier. - * FIXME: This searches the whole file in a very slow manner if the - * file isn't a zip file. + * Note that a comment has a maximum length of 64K, so that is the + * maximum we search backwards. */ + PartialInputStream inp = new PartialInputStream(raf, 4096); long pos = raf.length() - ENDHDR; - byte[] ebs = new byte[CENHDR]; - + long top = Math.max(0, pos - 65536); do { - if (pos < 0) + if (pos < top) throw new ZipException ("central directory not found, probably not a zip file: " + name); - raf.seek(pos--); + inp.seek(pos--); } - while (readLeInt(raf, ebs) != ENDSIG); + while (inp.readLeInt() != ENDSIG); - if (raf.skipBytes(ENDTOT - ENDNRD) != ENDTOT - ENDNRD) + if (inp.skip(ENDTOT - ENDNRD) != ENDTOT - ENDNRD) throw new EOFException(name); - int count = readLeShort(raf, ebs); - if (raf.skipBytes(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ) + int count = inp.readLeShort(); + if (inp.skip(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ) throw new EOFException(name); - int centralOffset = readLeInt(raf, ebs); + int centralOffset = inp.readLeInt(); entries = new HashMap (count+count/2); - raf.seek(centralOffset); + inp.seek(centralOffset); - byte[] buffer = new byte[16]; for (int i = 0; i < count; i++) { - raf.readFully(ebs); - if (readLeInt(ebs, 0) != CENSIG) + if (inp.readLeInt() != CENSIG) throw new ZipException("Wrong Central Directory signature: " + name); - int method = readLeShort(ebs, CENHOW); - int dostime = readLeInt(ebs, CENTIM); - int crc = readLeInt(ebs, CENCRC); - int csize = readLeInt(ebs, CENSIZ); - int size = readLeInt(ebs, CENLEN); - int nameLen = readLeShort(ebs, CENNAM); - int extraLen = readLeShort(ebs, CENEXT); - int commentLen = readLeShort(ebs, CENCOM); - - int offset = readLeInt(ebs, CENOFF); - - int needBuffer = Math.max(nameLen, commentLen); - if (buffer.length < needBuffer) - buffer = new byte[needBuffer]; - - raf.readFully(buffer, 0, nameLen); - String name; - try - { - name = new String(buffer, 0, nameLen, "UTF-8"); - } - catch (UnsupportedEncodingException uee) - { - throw new AssertionError(uee); - } + inp.skip(6); + int method = inp.readLeShort(); + int dostime = inp.readLeInt(); + int crc = inp.readLeInt(); + int csize = inp.readLeInt(); + int size = inp.readLeInt(); + int nameLen = inp.readLeShort(); + int extraLen = inp.readLeShort(); + int commentLen = inp.readLeShort(); + inp.skip(8); + int offset = inp.readLeInt(); + String name = inp.readString(nameLen); ZipEntry entry = new ZipEntry(name); entry.setMethod(method); @@ -313,20 +243,12 @@ public class ZipFile implements ZipConstants if (extraLen > 0) { byte[] extra = new byte[extraLen]; - raf.readFully(extra); + inp.readFully(extra); entry.setExtra(extra); } if (commentLen > 0) { - raf.readFully(buffer, 0, commentLen); - try - { - entry.setComment(new String(buffer, 0, commentLen, "UTF-8")); - } - catch (UnsupportedEncodingException uee) - { - throw new AssertionError(uee); - } + entry.setComment(inp.readString(commentLen)); } entry.offset = offset; entries.put(name, entry); @@ -429,42 +351,6 @@ public class ZipFile implements ZipConstants } } - - //access should be protected by synchronized(raf) - private byte[] locBuf = new byte[LOCHDR]; - - /** - * Checks, if the local header of the entry at index i matches the - * central directory, and returns the offset to the data. - * - * @param entry to check. - * @return the start offset of the (compressed) data. - * - * @exception IOException if a i/o error occured. - * @exception ZipException if the local header doesn't match the - * central directory header - */ - private long checkLocalHeader(ZipEntry entry) throws IOException - { - synchronized (raf) - { - raf.seek(entry.offset); - raf.readFully(locBuf); - - if (readLeInt(locBuf, 0) != LOCSIG) - throw new ZipException("Wrong Local header signature: " + name); - - if (entry.getMethod() != readLeShort(locBuf, LOCHOW)) - throw new ZipException("Compression method mismatch: " + name); - - if (entry.getName().length() != readLeShort(locBuf, LOCNAM)) - throw new ZipException("file name length mismatch: " + name); - - int extraLen = entry.getName().length() + readLeShort(locBuf, LOCEXT); - return entry.offset + LOCHDR + extraLen; - } - } - /** * Creates an input stream reading the given zip entry as * uncompressed data. Normally zip entry should be an entry @@ -497,16 +383,32 @@ public class ZipFile implements ZipConstants if (zipEntry == null) return null; - long start = checkLocalHeader(zipEntry); + PartialInputStream inp = new PartialInputStream(raf, 1024); + inp.seek(zipEntry.offset); + + if (inp.readLeInt() != LOCSIG) + throw new ZipException("Wrong Local header signature: " + name); + + inp.skip(4); + + if (zipEntry.getMethod() != inp.readLeShort()) + throw new ZipException("Compression method mismatch: " + name); + + inp.skip(16); + + int nameLen = inp.readLeShort(); + int extraLen = inp.readLeShort(); + inp.skip(nameLen + extraLen); + + inp.setLength(zipEntry.getCompressedSize()); + int method = zipEntry.getMethod(); - InputStream is = new BufferedInputStream(new PartialInputStream - (raf, start, zipEntry.getCompressedSize())); switch (method) { case ZipOutputStream.STORED: - return is; + return inp; case ZipOutputStream.DEFLATED: - return new InflaterInputStream(is, new Inflater(true)); + return new InflaterInputStream(inp, new Inflater(true)); default: throw new ZipException("Unknown compression method " + method); } @@ -562,21 +464,41 @@ public class ZipFile implements ZipConstants } } - private static class PartialInputStream extends InputStream + private static final class PartialInputStream extends InputStream { private final RandomAccessFile raf; - long filepos, end; + private final byte[] buffer; + private long bufferOffset; + private int pos; + private long end; - public PartialInputStream(RandomAccessFile raf, long start, long len) + public PartialInputStream(RandomAccessFile raf, int bufferSize) + throws IOException { this.raf = raf; - filepos = start; - end = start + len; + buffer = new byte[bufferSize]; + bufferOffset = -buffer.length; + pos = buffer.length; + end = raf.length(); + } + + void setLength(long length) + { + end = bufferOffset + pos + length; + } + + private void fillBuffer() throws IOException + { + synchronized (raf) + { + raf.seek(bufferOffset); + raf.readFully(buffer, 0, (int) Math.min(buffer.length, end - bufferOffset)); + } } public int available() { - long amount = end - filepos; + long amount = end - (bufferOffset + pos); if (amount > Integer.MAX_VALUE) return Integer.MAX_VALUE; return (int) amount; @@ -584,41 +506,130 @@ public class ZipFile implements ZipConstants public int read() throws IOException { - if (filepos == end) + if (bufferOffset + pos >= end) return -1; - synchronized (raf) - { - raf.seek(filepos++); - return raf.read(); - } + if (pos == buffer.length) + { + bufferOffset += buffer.length; + pos = 0; + fillBuffer(); + } + return buffer[pos++] & 0xFF; } public int read(byte[] b, int off, int len) throws IOException { - if (len > end - filepos) + if (len > end - (bufferOffset + pos)) { - len = (int) (end - filepos); + len = (int) (end - (bufferOffset + pos)); if (len == 0) return -1; } - synchronized (raf) - { - raf.seek(filepos); - int count = raf.read(b, off, len); - if (count > 0) - filepos += len; - return count; - } + + int totalBytesRead = Math.min(buffer.length - pos, len); + System.arraycopy(buffer, pos, b, off, totalBytesRead); + pos += totalBytesRead; + off += totalBytesRead; + len -= totalBytesRead; + + while (len > 0) + { + bufferOffset += buffer.length; + pos = 0; + fillBuffer(); + int remain = Math.min(buffer.length, len); + System.arraycopy(buffer, pos, b, off, remain); + pos += remain; + off += remain; + len -= remain; + totalBytesRead += remain; + } + + return totalBytesRead; } - public long skip(long amount) + public long skip(long amount) throws IOException { if (amount < 0) - throw new IllegalArgumentException(); - if (amount > end - filepos) - amount = end - filepos; - filepos += amount; + return 0; + if (amount > end - (bufferOffset + pos)) + amount = end - (bufferOffset + pos); + seek(bufferOffset + pos + amount); return amount; } + + void seek(long newpos) throws IOException + { + long offset = newpos - bufferOffset; + if (offset >= 0 && offset <= buffer.length) + { + pos = (int) offset; + } + else + { + bufferOffset = newpos; + pos = 0; + fillBuffer(); + } + } + + void readFully(byte[] buf) throws IOException + { + if (read(buf, 0, buf.length) != buf.length) + throw new EOFException(); + } + + void readFully(byte[] buf, int off, int len) throws IOException + { + if (read(buf, off, len) != len) + throw new EOFException(); + } + + int readLeShort() throws IOException + { + int b0 = read(); + int b1 = read(); + if (b1 == -1) + throw new EOFException(); + return (b0 & 0xff) | (b1 & 0xff) << 8; + } + + int readLeInt() throws IOException + { + int b0 = read(); + int b1 = read(); + int b2 = read(); + int b3 = read(); + if (b3 == -1) + throw new EOFException(); + return ((b0 & 0xff) | (b1 & 0xff) << 8) + | ((b2 & 0xff) | (b3 & 0xff) << 8) << 16; + } + + String readString(int length) throws IOException + { + if (length > end - (bufferOffset + pos)) + throw new EOFException(); + + try + { + if (buffer.length - pos >= length) + { + String s = new String(buffer, pos, length, "UTF-8"); + pos += length; + return s; + } + else + { + byte[] b = new byte[length]; + readFully(b); + return new String(b, 0, length, "UTF-8"); + } + } + catch (UnsupportedEncodingException uee) + { + throw new AssertionError(uee); + } + } } } diff --git a/java/util/zip/ZipOutputStream.java b/java/util/zip/ZipOutputStream.java index 5c593b2c4..d292f7d40 100644 --- a/java/util/zip/ZipOutputStream.java +++ b/java/util/zip/ZipOutputStream.java @@ -1,5 +1,5 @@ /* ZipOutputStream.java -- - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -160,6 +160,16 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant writeLeShort(value >> 16); } + /** + * Write a long value as an int. Some of the zip constants + * are declared as longs even though they fit perfectly well + * into integers. + */ + private void writeLeInt(long value) throws IOException + { + writeLeInt((int) value); + } + /** * Starts a new Zip entry. It automatically closes the previous * entry if present. If the compression method is stored, the entry diff --git a/javax/crypto/EncryptedPrivateKeyInfo.java b/javax/crypto/EncryptedPrivateKeyInfo.java index a52d7b15d..0fddd54bb 100644 --- a/javax/crypto/EncryptedPrivateKeyInfo.java +++ b/javax/crypto/EncryptedPrivateKeyInfo.java @@ -92,6 +92,9 @@ public class EncryptedPrivateKeyInfo /** The OID of the encryption algorithm. */ private OID algOid; + /** The encryption algorithm name. */ + private String algName; + /** The encryption algorithm's parameters. */ private AlgorithmParameters params; @@ -125,7 +128,8 @@ public class EncryptedPrivateKeyInfo throw new IllegalArgumentException("0-length encryptedData"); } this.params = params; - algOid = new OID(params.getAlgorithm()); + algName = params.getAlgorithm (); + algOid = getOid (algName); this.encryptedData = (byte[]) encryptedData.clone(); } @@ -168,10 +172,36 @@ public class EncryptedPrivateKeyInfo { throw new IllegalArgumentException("0-length encryptedData"); } - this.algOid = new OID(algName); + this.algName = algName.toString (); // do NP check + this.algOid = getOid (algName); this.encryptedData = (byte[]) encryptedData.clone(); } + /** + * Return the OID for the given cipher name. + * + * @param str The string. + * @throws NoSuchAlgorithmException If the OID is not known. + */ + private static OID getOid (final String str) + throws NoSuchAlgorithmException + { + if (str.equalsIgnoreCase ("DSA")) + { + return new OID ("1.2.840.10040.4.3"); + } + // FIXME add more + + try + { + return new OID (str); + } + catch (Throwable t) + { + } + throw new NoSuchAlgorithmException ("cannot determine OID for '" + str + "'"); + } + // Instance methods. // ------------------------------------------------------------------------ @@ -196,6 +226,7 @@ public class EncryptedPrivateKeyInfo } catch (NoSuchAlgorithmException ignore) { + // FIXME throw exception? } catch (IOException ignore) { @@ -272,7 +303,11 @@ public class EncryptedPrivateKeyInfo getAlgParameters(); if (params != null) { - algId.add(DERReader.read(params.getEncoded())); + algId.add (DERReader.read (params.getEncoded())); + } + else + { + algId.add (new DERValue (DER.NULL, null)); } List epki = new ArrayList(2); epki.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, algId)); diff --git a/javax/print/CancelablePrintJob.java b/javax/print/CancelablePrintJob.java index 94e9475e5..39a25440e 100644 --- a/javax/print/CancelablePrintJob.java +++ b/javax/print/CancelablePrintJob.java @@ -1,5 +1,5 @@ /* CancelablePrintJob.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,14 +39,29 @@ exception statement from your version. */ package javax.print; /** + * CancelablePrintJob represents a print job which can be + * canceled. + *

      + * It is implemented by DocPrintJobs which support to cancel + * a print job during processing. Clients need to explicitly test if a given + * DocPrintJob object from a print service implementes this + * interface and therefore supports cancelling. + *

      + * Implementor of java print services should implement this interface if + * cancelling is supported by the underlying print system. If implemented the + * corresponding print job event + * {@link javax.print.event.PrintJobEvent#JOB_CANCELED} should be delivered to + * registered clients. Implementations have to be thread-safe. + *

      + * * @author Michael Koch (konqueror@gmx.de) */ public interface CancelablePrintJob extends DocPrintJob { /** - * Cancel print job. + * Cancel the print job. * - * @exception PrintException if an error occured + * @exception PrintException if an error during cancellation occurs. */ void cancel() throws PrintException; } diff --git a/javax/print/Doc.java b/javax/print/Doc.java index 00e9dc986..c489de1b6 100644 --- a/javax/print/Doc.java +++ b/javax/print/Doc.java @@ -1,5 +1,5 @@ /* Doc.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,51 +45,102 @@ import java.io.Reader; import javax.print.attribute.DocAttributeSet; /** + * Doc specifies the interface for print services how to obtain + * the print data and document specific attributes for printing. + *

      + * The print data is always passed to a {@link javax.print.DocPrintJob} object + * as a Doc object which allows the print services to: + *

        + *
      • Determine the actual document format of the supplied print data. This + * is supplied as a {@link javax.print.DocFlavor} object with the MIME type + * and the representation class of the print data.
      • + *
      • Obtain the print data either in its representation class or depending + * on the document format through convenience methods as a + * {@link java.io.Reader} or an {@link java.io.InputStream}.
      • + *
      • Obtain the document's attribute set specifying the attributes which + * apply to this document instance.
      • + *
      + *

      + * Every method of a Doc implementation has to return always the + * same object on every method call. Therefore if the print job consumes the + * print data via a stream or a reader object it can read only once the + * supplied print data. Implementations of this interface have to be thread + * safe. + *

      + * * @author Michael Koch (konqueror@gmx.de) */ public interface Doc { /** - * Returns a set of attributes applying to this document. + * Returns the unmodifiable view of the attributes of this doc object. + *

      + * The attributes of this doc's attributes set overrides attributes of + * the same category in the print job's attribute set. If an attribute + * is not available in this doc's attributes set or null + * is returned the attributes of the same category of the print job are + * used. + *

      * - * @return the attributes + * @return The unmodifiable attributes set, or null. */ DocAttributeSet getAttributes(); /** - * Returns the flavor in which this document will provide its print data. - * - * @return the document flavor for printing + * Returns the flavor of this doc objects print data. + * + * @return The document flavor. */ DocFlavor getDocFlavor(); /** - * Returns the print data of this document represented in a format that supports - * the document flavor. - * - * @return the print data + * Returns the print data of this doc object. + *

      + * The returned object is an instance as described by the associated + * document flavor ({@link DocFlavor#getRepresentationClassName()}) + * and can be cast to this representation class. + *

      * - * @throws IOException if an error occurs + * @return The print data in the representation class. + * @throws IOException if representation class is a stream and I/O + * exception occures. */ Object getPrintData() throws IOException; /** * Returns a Reader object for extracting character print data * from this document. + *

      + * This method is supported if the document flavor is of type: + *

        + *
      • char[]
      • + *
      • java.lang.String
      • + *
      • java.io.Reader
      • + *
      + * otherwise this method returns null. + *

      * - * @return the Reader object + * @return The Reader object, or null. * - * @throws IOException if an error occurs + * @throws IOException if an error occurs. */ Reader getReaderForText() throws IOException; /** * Returns an InputStream object for extracting byte print data * from this document. + *

      + * This method is supported if the document flavor is of type: + *

        + *
      • byte[]
      • + *
      • java.io.InputStream
      • + *
      + * otherwise this method returns null. + *

      * - * @return the InputStream object + * @return The InputStream object, or null. * - * @throws IOException if an error occurs + * @throws IOException if an error occurs. */ InputStream getStreamForBytes() throws IOException; } \ No newline at end of file diff --git a/javax/print/DocFlavor.java b/javax/print/DocFlavor.java index 1e96a70c0..603059525 100644 --- a/javax/print/DocFlavor.java +++ b/javax/print/DocFlavor.java @@ -1,5 +1,5 @@ /* DocFlavor.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,17 +38,108 @@ exception statement from your version. */ package javax.print; +import java.io.IOException; +import java.io.ObjectInputStream; import java.io.Serializable; -import java.util.HashMap; +import java.io.StreamTokenizer; +import java.io.StringReader; +import java.nio.charset.Charset; import java.util.Iterator; import java.util.Map; +import java.util.TreeMap; /** + * DocFlavor provides a description of the format in which the + * print data will be supplied in a print job to the print service. + *

      + * A doc flavor consists of two parts: + *

        + *
      • + * The MIME type (Multipurpose Internet Mail Extensions types as described + * in RFC 2045/2046) specifying the media format of the print data. + *
      • + * The representation class name which is the fully qualified name of the + * class providing the print data to the print job. For example if the print + * data is supplied as a byte array the representation class name will be + * "[B" or for an input stream "java.io.InputStream". + *
      • + *
      + * The DocFlavor class is therefore used in several places in the + * Java Print Service API. A print service provides its supported document + * flavors as an array of DocFlavor objects and a print job gets the flavor of + * its data to print from the Doc object provided as a DocFlavor + * instance. + *

      + *

      + * It has to be differentiated between client formatted and service + * formatted print data. Client formatted print data is already provided + * formatted by the client e.g. in an image format or as postscript. For + * service formatted print data, the Java Print Service instance produces + * the formatted print data. Here the doc flavor's representation class name + * does specify an interface instead of the actual print data source. The + * print service will call the methods of the given implementation of this + * interface with a special Graphics object capable of producing formatted + * print data from the graphics routines inside the interface methods. + *

      + *

      + *

      Client formatted print data document flavors

      + * The print service uses the representation class of the doc flavor to know + * how to retrieve the print data. If the representation class is a + * URL it will open the URL to read the print data from it. If it is + * a byte[] it will directly use the array and send it to the + * printer. There are predefined doc flavor as inner class for the most common + * representation class types: + *
        + *
      • Character arrays (char[]): The characters of the array + * represent the print data.
      • + *
      • Character streams (java.io.Reader): The whole characters + * read from the stream represent the print data.
      • + *
      • String (java.lang.String): The characters of the String + * represent the print data.
      • + *
      • Byte arrays (byte[]): The bytes of the array represent the + * print data. Encoding if text content is given in the mime type.
      • + *
      • Byte streams (java.io.InputStream): The whole bytes read + * from the stream represent the print data. If text content the encoding is + * specified in the mime type.
      • + *
      • Uniform Resource Locator (java.net.URL): The bytes read + * from the stream through opening of the URL represent the print data. + * If text content the encoding is specified in the mime type.
      • + *
      + *

      + *

      + *

      Service formatted print data document flavors

      + * The print service uses the provided object implementing the interface + * specified by the representation class to produce the formatted print data. + * The mime type of service formatted data is always + * "application/x-java-jvm-local-objectref" to signal the local + * reference to the print data object implementing the interface. Predefined + * doc flavor classes exist as an inner class for the three available interface + * to produce print data: + *
        + *
      • Pageable object (java.awt.print.Pageable): A pageable object + * is supplied to the print service. The print service will call the methods of + * the interface with a Grahics object to produce the formatted print data.
      • + *
      • Printable object (java.awt.print.Printable): A printable object + * is supplied to the print service. The print service will call the methods of + * the interface with a Grahics object to produce the formatted print data.
      • + *
      • Renderable Image object + * (java.awt.image.renderable.RenderableImage): A renderable image + * object is supplied to the print service. The print service calls methods of + * this interface to obtain the image to be printed.
      • + *
      + *

      + * * @author Michael Koch (konqueror@gmx.de) + * @author Wolfgang Baer (WBaer@gmx.de) */ public class DocFlavor implements Cloneable, Serializable { /** + * Predefined static DocFlavor objects for document + * types which use a byte array for the print data representation. + *

      All the defined doc flavors have a print data representation + * classname of "[B" (byte array).

      + * * @author Michael Koch (konqueror@gmx.de) */ public static class BYTE_ARRAY @@ -56,26 +147,92 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = -9065578006593857475L; + /** + * Byte array doc flavor with a MIME Type of "application/octet-stream". + */ public static final BYTE_ARRAY AUTOSENSE = new BYTE_ARRAY("application/octet-stream"); + /** + * Byte array doc flavor with a MIME Type of "image/gif". + */ public static final BYTE_ARRAY GIF = new BYTE_ARRAY("image/gif"); + /** + * Byte array doc flavor with a MIME Type of "image/jpeg". + */ public static final BYTE_ARRAY JPEG = new BYTE_ARRAY("image/jpeg"); + /** + * Byte array doc flavor with a MIME Type of "application/vnd.hp-PCL". + */ public static final BYTE_ARRAY PCL = new BYTE_ARRAY("application/vnd.hp-PCL"); + /** + * Byte array doc flavor with a MIME Type of "application/pdf". + */ public static final BYTE_ARRAY PDF = new BYTE_ARRAY("application/pdf"); + /** + * Byte array doc flavor with a MIME Type of "image/png". + */ public static final BYTE_ARRAY PNG = new BYTE_ARRAY("image/png"); + /** + * Byte array doc flavor with a MIME Type of "application/postscript". + */ public static final BYTE_ARRAY POSTSCRIPT = new BYTE_ARRAY("application/postscript"); - public static final BYTE_ARRAY TEXT_HTML_HOST = new BYTE_ARRAY("text/html"); + /** + * Byte array doc flavor with a MIME Type of "text/html" in the host encoding. + */ + public static final BYTE_ARRAY TEXT_HTML_HOST = new BYTE_ARRAY("text/html; charset=" + hostEncoding); + /** + * Byte array doc flavor with a MIME Type of "text/html; charset=us-ascii". + */ public static final BYTE_ARRAY TEXT_HTML_US_ASCII = new BYTE_ARRAY("text/html; charset=us-ascii"); + /** + * Byte array doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final BYTE_ARRAY TEXT_HTML_UTF_16 = new BYTE_ARRAY("text/html; charset=utf-16"); + /** + * Byte array doc flavor with a MIME Type of "text/html; charset=utf-16be". + */ public static final BYTE_ARRAY TEXT_HTML_UTF_16BE = new BYTE_ARRAY("text/html; charset=utf-16be"); + /** + * Byte array doc flavor with a MIME Type of "text/html; charset=utf-16le". + */ public static final BYTE_ARRAY TEXT_HTML_UTF_16LE = new BYTE_ARRAY("text/html; charset=utf-16le"); + /** + * Byte array doc flavor with a MIME Type of "text/html; charset=utf-8". + */ public static final BYTE_ARRAY TEXT_HTML_UTF_8 = new BYTE_ARRAY("text/html; charset=utf-8"); - public static final BYTE_ARRAY TEXT_PLAIN_HOST = new BYTE_ARRAY("text/plain"); - public static final BYTE_ARRAY TEXT_PLAIN_US_ASCII = new BYTE_ARRAY("text/plain; charset=us-ascii"); + /** + * Byte array doc flavor with a MIME Type of "text/plain" in the host encoding. + */ + public static final BYTE_ARRAY TEXT_PLAIN_HOST = new BYTE_ARRAY("text/plain; charset=" + hostEncoding); + /** + * Byte array doc flavor with a MIME Type of "text/plain; charset=us-ascii". + */ + public static final BYTE_ARRAY TEXT_PLAIN_US_ASCII = new BYTE_ARRAY("text/plain; charset=us-ascii"); + /** + * Byte array doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final BYTE_ARRAY TEXT_PLAIN_UTF_16 = new BYTE_ARRAY("text/plain; charset=utf-16"); + /** + * Byte array doc flavor with a MIME Type of "text/plain; charset=utf-16be". + */ public static final BYTE_ARRAY TEXT_PLAIN_UTF_16BE = new BYTE_ARRAY("text/plain; charset=utf-16be"); + /** + * Byte array doc flavor with a MIME Type of "text/plain; charset=utf-16le". + */ public static final BYTE_ARRAY TEXT_PLAIN_UTF_16LE = new BYTE_ARRAY("text/plain; charset=utf-16le"); + /** + * Byte array doc flavor with a MIME Type of "text/plain; charset=utf-8". + */ public static final BYTE_ARRAY TEXT_PLAIN_UTF_8 = new BYTE_ARRAY("text/plain; charset=utf-8"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "[B". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is null. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public BYTE_ARRAY(String mimeType) { super(mimeType, "[B"); @@ -83,6 +240,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static DocFlavor objects for document + * types which use a char array for the print data representation. + *

      All the defined doc flavors have a print data representation + * classname of "[C" (char array).

      + * * @author Michael Koch (konqueror@gmx.de) */ public static class CHAR_ARRAY @@ -90,9 +252,24 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = -8720590903724405128L; + /** + * Char array doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final DocFlavor.CHAR_ARRAY TEXT_HTML = new CHAR_ARRAY("text/html; charset=utf-16"); + /** + * Char array doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final DocFlavor.CHAR_ARRAY TEXT_PLAIN = new CHAR_ARRAY("text/plain; charset=utf-16"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "[C". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is null. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public CHAR_ARRAY(String mimeType) { super(mimeType, "[C"); @@ -100,6 +277,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static DocFlavor objects for document + * types which use an InputStream to retrieve the print data. + *

      All the defined doc flavors have a print data representation + * classname of "java.io.InputStream".

      + * * @author Michael Koch (konqueror@gmx.de) */ public static class INPUT_STREAM @@ -107,26 +289,92 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = -7045842700749194127L; + /** + * InputStream doc flavor with a MIME Type of "application/octet-stream". + */ public static final INPUT_STREAM AUTOSENSE = new INPUT_STREAM("application/octet-stream"); + /** + * InputStream doc flavor with a MIME Type of "image/gif". + */ public static final INPUT_STREAM GIF = new INPUT_STREAM("image/gif"); + /** + * InputStream doc flavor with a MIME Type of "image/jpeg". + */ public static final INPUT_STREAM JPEG = new INPUT_STREAM("image/jpeg"); + /** + * InputStream doc flavor with a MIME Type of "application/vnd.hp-PCL". + */ public static final INPUT_STREAM PCL = new INPUT_STREAM("application/vnd.hp-PCL"); + /** + * InputStream doc flavor with a MIME Type of "application/pdf". + */ public static final INPUT_STREAM PDF = new INPUT_STREAM("application/pdf"); + /** + * InputStream doc flavor with a MIME Type of "image/png". + */ public static final INPUT_STREAM PNG = new INPUT_STREAM("image/png"); + /** + * InputStream doc flavor with a MIME Type of "application/postscript". + */ public static final INPUT_STREAM POSTSCRIPT = new INPUT_STREAM("application/postscript"); - public static final INPUT_STREAM TEXT_HTML_HOST = new INPUT_STREAM("text/html"); + /** + * InputStream doc flavor with a MIME Type of "text/html" in the host encoding. + */ + public static final INPUT_STREAM TEXT_HTML_HOST = new INPUT_STREAM("text/html; charset=" + hostEncoding); + /** + * InputStream doc flavor with a MIME Type of "text/html; charset=us-ascii". + */ public static final INPUT_STREAM TEXT_HTML_US_ASCII = new INPUT_STREAM("text/html; charset=us-ascii"); + /** + * InputStream doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final INPUT_STREAM TEXT_HTML_UTF_16 = new INPUT_STREAM("text/html; charset=utf-16"); + /** + * InputStream doc flavor with a MIME Type of "text/html; charset=utf-16be". + */ public static final INPUT_STREAM TEXT_HTML_UTF_16BE = new INPUT_STREAM("text/html; charset=utf-16be"); + /** + * InputStream doc flavor with a MIME Type of "text/html; charset=utf-16le". + */ public static final INPUT_STREAM TEXT_HTML_UTF_16LE = new INPUT_STREAM("text/html; charset=utf-16le"); + /** + * InputStream doc flavor with a MIME Type of "text/html; charset=utf-8". + */ public static final INPUT_STREAM TEXT_HTML_UTF_8 = new INPUT_STREAM("text/html; charset=utf-8"); - public static final INPUT_STREAM TEXT_PLAIN_HOST = new INPUT_STREAM("text/plain"); + /** + * InputStream doc flavor with a MIME Type of "text/plain" in the host encoding. + */ + public static final INPUT_STREAM TEXT_PLAIN_HOST = new INPUT_STREAM("text/plain; charset=" + hostEncoding); + /** + * InputStream doc flavor with a MIME Type of "text/plain; charset=us-ascii". + */ public static final INPUT_STREAM TEXT_PLAIN_US_ASCII = new INPUT_STREAM("text/plain; charset=us-ascii"); + /** + * InputStream doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final INPUT_STREAM TEXT_PLAIN_UTF_16 = new INPUT_STREAM("text/plain; charset=utf-16"); + /** + * InputStream doc flavor with a MIME Type of "text/plain; charset=utf-16be". + */ public static final INPUT_STREAM TEXT_PLAIN_UTF_16BE = new INPUT_STREAM("text/plain; charset=utf-16be"); + /** + * InputStream doc flavor with a MIME Type of "text/plain; charset=utf-16le". + */ public static final INPUT_STREAM TEXT_PLAIN_UTF_16LE = new INPUT_STREAM("text/plain; charset=utf-16le"); + /** + * InputStream doc flavor with a MIME Type of "text/plain; charset=utf-8". + */ public static final INPUT_STREAM TEXT_PLAIN_UTF_8 = new INPUT_STREAM("text/plain; charset=utf-8"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "java.io.InputStream". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is null. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public INPUT_STREAM(String mimeType) { super(mimeType, "java.io.InputStream"); @@ -134,6 +382,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static DocFlavor objects for document + * types which use an Reader to retrieve the print data. + *

      All the defined doc flavors have a print data representation + * classname of "java.io.Reader".

      + * * @author Michael Koch (konqueror@gmx.de) */ public static class READER @@ -141,9 +394,24 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = 7100295812579351567L; + /** + * Reader doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final DocFlavor.READER TEXT_HTML = new READER("text/html; charset=utf-16"); + /** + * Reader doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final DocFlavor.READER TEXT_PLAIN = new READER("text/plain; charset=utf-16"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "java.io.Reader". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is null. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public READER(String mimeType) { super(mimeType, "java.io.Reader"); @@ -151,6 +419,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static DocFlavor objects for document + * types which use service formatted print data. + *

      All the defined doc flavors have a MIME type of + * "application/x-java-jvm-local-objectref".

      + * * @author Michael Koch (konqueror@gmx.de) */ public static class SERVICE_FORMATTED @@ -158,10 +431,31 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = 6181337766266637256L; + /** + * Service formatted doc flavor with a representation class of + * "java.awt.print.Pageable". + */ public static final DocFlavor.SERVICE_FORMATTED PAGEABLE = new SERVICE_FORMATTED("java.awt.print.Pageable"); + /** + * Service formatted doc flavor with a representation class of + * "java.awt.print.Printable". + */ public static final DocFlavor.SERVICE_FORMATTED PRINTABLE = new SERVICE_FORMATTED("java.awt.print.Printable"); + /** + * Service formatted doc flavor with a representation class of + * "java.awt.image.renderable.RenderableImage". + */ public static final DocFlavor.SERVICE_FORMATTED RENDERABLE_IMAGE = new SERVICE_FORMATTED("java.awt.image.renderable.RenderableImage"); + /** + * Constructor for doc flavor objects with a MIME type of + * "application/x-java-jvm-local-objectref" and the given + * print data representation classname. + * + * @param className the representation classname + * + * @throws NullPointerException if className is null. + */ public SERVICE_FORMATTED(String className) { super("application/x-java-jvm-local-objectref", className); @@ -169,6 +463,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static DocFlavor objects for document + * types which use a String for the print data representation. + *

      All the defined doc flavors have a print data representation + * classname of "java.lang.String".

      + * * @author Michael Koch (konqueror@gmx.de) */ public static class STRING @@ -176,9 +475,24 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = 4414407504887034035L; + /** + * String doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final DocFlavor.STRING TEXT_HTML = new STRING("text/html; charset=utf-16"); + /** + * String doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final DocFlavor.STRING TEXT_PLAIN = new STRING("text/plain; charset=utf-16"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "java.lang.String". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is null. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public STRING(String mimeType) { super(mimeType, "java.lang.String"); @@ -186,6 +500,11 @@ public class DocFlavor implements Cloneable, Serializable } /** + * Predefined static DocFlavor objects for document + * types which have an URL where to retrieve the print data. + *

      All the defined doc flavors have a print data representation + * classname of "java.net.URL".

      + * * @author Michael Koch (konqueror@gmx.de) */ public static class URL @@ -193,26 +512,92 @@ public class DocFlavor implements Cloneable, Serializable { private static final long serialVersionUID = 2936725788144902062L; + /** + * URL doc flavor with a MIME Type of "application/octet-stream". + */ public static final DocFlavor.URL AUTOSENSE = new URL("application/octet-stream"); + /** + * URL doc flavor with a MIME Type of "image/gif". + */ public static final DocFlavor.URL GIF = new URL("image/gif"); + /** + * URL doc flavor with a MIME Type of "image/jpeg". + */ public static final DocFlavor.URL JPEG = new URL("image/jpeg"); + /** + * URL doc flavor with a MIME Type of "application/vnd.hp-PCL". + */ public static final DocFlavor.URL PCL = new URL("application/vnd.hp-PCL"); + /** + * URL doc flavor with a MIME Type of "application/pdf". + */ public static final DocFlavor.URL PDF = new URL("application/pdf"); + /** + * URL doc flavor with a MIME Type of "image/png". + */ public static final DocFlavor.URL PNG = new URL("image/png"); + /** + * URL doc flavor with a MIME Type of "application/postscript". + */ public static final DocFlavor.URL POSTSCRIPT = new URL("application/postscript"); - public static final DocFlavor.URL TEXT_HTML_HOST = new URL("text/html"); + /** + * URL doc flavor with a MIME Type of "text/html" in the host encoding. + */ + public static final DocFlavor.URL TEXT_HTML_HOST = new URL("text/html; charset=" + hostEncoding); + /** + * URL doc flavor with a MIME Type of "text/html; charset=us-ascii". + */ public static final DocFlavor.URL TEXT_HTML_US_ASCII = new URL("text/html; charset=us-ascii"); + /** + * URL doc flavor with a MIME Type of "text/html; charset=utf-16". + */ public static final DocFlavor.URL TEXT_HTML_UTF_16 = new URL("text/html; charset=utf-16"); + /** + * URL doc flavor with a MIME Type of "text/html; charset=utf-16be". + */ public static final DocFlavor.URL TEXT_HTML_UTF_16BE = new URL("text/html; charset=utf-16be"); + /** + * URL doc flavor with a MIME Type of "text/html; charset=utf-16le". + */ public static final DocFlavor.URL TEXT_HTML_UTF_16LE = new URL("text/html; charset=utf-16le"); + /** + * URL doc flavor with a MIME Type of "text/html; charset=utf-8". + */ public static final DocFlavor.URL TEXT_HTML_UTF_8 = new URL("text/html; charset=utf-8"); - public static final DocFlavor.URL TEXT_PLAIN_HOST = new URL("text/plain"); + /** + * URL doc flavor with a MIME Type of "text/plain" in the host encoding. + */ + public static final DocFlavor.URL TEXT_PLAIN_HOST = new URL("text/plain; charset=" + hostEncoding); + /** + * URL doc flavor with a MIME Type of "text/plain; charset=us-ascii". + */ public static final DocFlavor.URL TEXT_PLAIN_US_ASCII = new URL("text/plain; charset=us-ascii"); + /** + * URL doc flavor with a MIME Type of "text/plain; charset=utf-16". + */ public static final DocFlavor.URL TEXT_PLAIN_UTF_16 = new URL("text/plain; charset=utf-16"); + /** + * URL doc flavor with a MIME Type of "text/plain; charset=utf-16be". + */ public static final DocFlavor.URL TEXT_PLAIN_UTF_16BE = new URL("text/plain; charset=utf-16be"); + /** + * URL doc flavor with a MIME Type of "text/plain; charset=utf-16le". + */ public static final DocFlavor.URL TEXT_PLAIN_UTF_16LE = new URL("text/plain; charset=utf-16le"); + /** + * URL doc flavor with a MIME Type of "text/plain; charset=utf-8". + */ public static final DocFlavor.URL TEXT_PLAIN_UTF_8 = new URL("text/plain; charset=utf-8"); + /** + * Constructor for doc flavor objects with the given MIME type + * and a print data representation class name of "java.net.URL". + * + * @param mimeType the mime type string + * + * @throws NullPointerException if mimeType is null. + * @throws IllegalArgumentException if mimeType has the wrong syntax. + */ public URL(String mimeType) { super(mimeType, "java.net.URL"); @@ -221,47 +606,191 @@ public class DocFlavor implements Cloneable, Serializable private static final long serialVersionUID = -4512080796965449721L; - // FIXME: Get the host encoding from somewhere. Note that the new String is to make - // sure the field won't be a compile time constant. - public static final String hostEncoding = new String("US-ASCII"); - - private String mediaSubtype; - private String mediaType; - private String className; - private HashMap params = new HashMap(); + /** + * The string representing the host encoding. This is the encoding + * used in the predefined HOST doc flavors + * (e.g. {@link BYTE_ARRAY#TEXT_HTML_HOST}). + */ + public static final String hostEncoding = Charset.defaultCharset().name(); + + private transient String mediaSubtype; + private transient String mediaType; + private transient TreeMap params; + // name as defined in Serialized Form JDK 1.4 + private String myClassName; + + /** + * Constructs a DocFlavor object with the given MIME type and + * representation class name. + * + * @param mimeType the MIME type string. + * @param className the fully-qualified name of the representation class. + * + * @throws NullPointerException if mimeType or className are null. + * @throws IllegalArgumentException if given mimeType has syntax errors. + */ public DocFlavor(String mimeType, String className) { if (mimeType == null || className == null) throw new NullPointerException(); + params = new TreeMap(); parseMimeType(mimeType); - this.className = className; + + myClassName = className; } - + + /** + * Parses the given string as MIME type. + * The mediatype, mediasubtype and all parameter/value + * combinations are extracted, comments are dropped. + * + * @param mimeType the string to parse + * @throws IllegalArgumentException if not conformant. + */ private void parseMimeType(String mimeType) { - // FIXME: This method is know to be not completely correct, but it works for now. + int MEDIA = 1; + int MEDIASUB = 2; + int PARAM_NAME = 3; + int PARAM_VALUE = 4; + int COMMENT_START = 5; - int pos = mimeType.indexOf(';'); - - if (pos != -1) + int state = 0; + int lastState = 0; // keeps track of state before comment + int tok; + + try { - String tmp = mimeType.substring(pos + 2); - mimeType = mimeType.substring(0, pos); - pos = tmp.indexOf('='); - params.put(tmp.substring(0, pos), tmp.substring(pos + 1)); + String paramName = null; + StreamTokenizer in = new StreamTokenizer(new StringReader(mimeType)); + in.resetSyntax(); + // Allowed characters are anything except: + // SPACE, CTLs (= Unicode characters U+0000 - U+001F and U+007F) + // and tspecials ( ) < > @ , ; : \ " / [ ] ? = + in.whitespaceChars(0x00, 0x20); + in.whitespaceChars(0x7F, 0x7F); + in.wordChars('A', 'Z'); + in.wordChars('a', 'z'); + in.wordChars('0', '9'); + in.wordChars(0xA0, 0xFF); + in.wordChars(0x21, 0x21); + in.wordChars(0x23, 0x27); + in.wordChars(0x2A, 0x2B); + in.wordChars(0x2D, 0x2E); + in.wordChars(0x5E, 0x60); + in.wordChars(0x7B, 0x7E); + in.quoteChar('"'); + + while ((tok = in.nextToken()) != StreamTokenizer.TT_EOF) + { + switch (tok) + { + case StreamTokenizer.TT_WORD: + if (state == 0) + { + mediaType = in.sval.toLowerCase(); + state = MEDIA; + break; + } + if (state == MEDIA) + { + mediaSubtype = in.sval.toLowerCase(); + state = MEDIASUB; + break; + } + // begin of parameters is either after mediasub or a parameter value + if (state == MEDIASUB || state == PARAM_VALUE) + { + paramName = in.sval.toLowerCase(); + state = PARAM_NAME; + break; + } + // a parameter always needs to follow a value + if (state == PARAM_NAME) + { + String paramValue = in.sval; + // if a charset param the value needs to be stored lowercase + if (paramName.equals("charset")) + paramValue = paramValue.toLowerCase(); + + state = PARAM_VALUE; + params.put(paramName, paramValue); + break; + } + if (state == COMMENT_START) + { + // ignore; + break; + } + break; + case '/': + // may only occur after the mediatype + if (state != MEDIA) + throw new IllegalArgumentException(); + + break; + case '=': + // may only occur after a parameter + if (state != PARAM_NAME) + throw new IllegalArgumentException(); + + break; + case ';': + // differentiates mime type and parameters/value combinations + if (state != MEDIASUB && state != PARAM_VALUE) + throw new IllegalArgumentException(); + + break; + case '(': // begin comment + lastState = state; + state = COMMENT_START; + break; + case ')': // end comment + state = lastState; + break; + // a parameter always needs to follow a value / or quoted value + case '"': + if (state == PARAM_NAME) + { + String paramValue = in.sval; + // if a charset param the value needs to be stored lowercase + if (paramName.equals("charset")) + paramValue = paramValue.toLowerCase(); + + state = PARAM_VALUE; + params.put(paramName, paramValue); + break; + } + + // only values may be quoted + throw new IllegalArgumentException(); + default: + // if any other char is observed its not allowed + throw new IllegalArgumentException(); + } + } + } + catch (IOException e) + { + // should not happen as mimetype str cannot be null + throw new InternalError("IOException during parsing String " + mimeType); } - - pos = mimeType.indexOf('/'); - - if (pos == -1) - throw new IllegalArgumentException(); - - mediaType = mimeType.substring(0, pos); - mediaSubtype = mimeType.substring(pos + 1); } + /** + * Checks if this doc flavor object is equal to the given object. + *

      + * Two doc flavor objects are considered equal if the provided object is not + * null and an instance of DocFlavor. The MIME + * types has to be equal in their media type, media subtype, their + * paramter/value combinations and the representation classname. + *

      + * + * @param obj the object to test. + * @return true if equal, false otherwise. + */ public boolean equals(Object obj) { if (! (obj instanceof DocFlavor)) @@ -273,20 +802,39 @@ public class DocFlavor implements Cloneable, Serializable && getRepresentationClassName().equals(tmp.getRepresentationClassName())); } + /** + * Returns the media subtype of this flavor object. + * A mimetype of "text/html; charset=us-ascii" will + * return "html" as the media subtype. + * + * @return The media subtype. + */ public String getMediaSubtype() { return mediaSubtype; } + /** + * Returns the media type of this flavor object. + * A mimetype of "text/html; charset=us-ascii" will + * return "text" as the media type. + * + * @return The media type. + */ public String getMediaType() { return mediaType; } + /** + * Returns the mime type of this flavor object. + * The mimetype will have every parameter value + * enclosed in quotes. + * + * @return The mime type. + */ public String getMimeType() { - // FIXME: Check if this algorithm is correct. - String mimeType = getMediaType() + "/" + getMediaSubtype(); Iterator it = params.entrySet().iterator(); @@ -299,28 +847,69 @@ public class DocFlavor implements Cloneable, Serializable return mimeType; } + /** + * Returns the value for an optional parameter of the mime type of this + * flavor object. + * + * @param paramName the name of the parameter + * @return The value for the parameter, or null if none bound. + * @throws NullPointerException if paramName is null. + */ public String getParameter(String paramName) { if (paramName == null) throw new NullPointerException(); - return (String) params.get(paramName); + return (String) params.get(paramName.toLowerCase()); } + /** + * Returns the name of the representation class of this flavor object. + * + * @return The representation classname. + */ public String getRepresentationClassName() { - return className; + return myClassName; } + /** + * Returns a hash code for this doc flavor object. + * + * @return The hashcode. + */ public int hashCode() { return ((mediaType.hashCode() * mediaSubtype.hashCode() - * className.hashCode()) ^ params.hashCode()); + * myClassName.hashCode()) ^ params.hashCode()); } + /** + * Returns a string representation of this doc flavor object. + * The returned string is of the form + * getMimeType() + "; class=\"" + getRepresentationClassName() + "\""; + * + * @return The constructed string representation. + */ public String toString() { - return getMimeType(); + return getMimeType() + "; class=\"" + getRepresentationClassName() + "\""; + } + + // needs special treatment for serialization + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + params = new TreeMap(); + myClassName = (String) stream.readObject(); + parseMimeType((String) stream.readObject()); + } + + private void writeObject(java.io.ObjectOutputStream stream) + throws IOException + { + stream.writeObject(myClassName); + stream.writeObject(getMimeType()); } } diff --git a/javax/print/DocPrintJob.java b/javax/print/DocPrintJob.java index f7d361594..eec4e2afc 100644 --- a/javax/print/DocPrintJob.java +++ b/javax/print/DocPrintJob.java @@ -1,5 +1,5 @@ /* DocPrintJob.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,61 +44,105 @@ import javax.print.event.PrintJobAttributeListener; import javax.print.event.PrintJobListener; /** + * DocPrintJob represents a print job which supports printing + * of a single document. + *

      + * An instance can be obtained from every PrintService available + * by calling the {@link javax.print.PrintService#createPrintJob()} method. + * A print job is bound to the print service it is created from. + *

      + * * @author Michael Koch (konqueror@gmx.de) */ public interface DocPrintJob { /** - * Registers a listener for changes in the specified attributes. + * Registers a listener for changes in the specified attribute set + * during processing of this print job. + *

      + * If the given attribute set is empty no changes will be reported. + * If the set is null all attributes are monitored. + *

      * - * @param listener the listener to add - * @param attributes the attributes to observe + * @param listener the listener to register. + * @param attributes the attributes to observe. + * + * @see #removePrintJobAttributeListener(PrintJobAttributeListener) */ void addPrintJobAttributeListener(PrintJobAttributeListener listener, PrintJobAttributeSet attributes); /** - * Registers a listener for events occuring during this print job. + * Registers a listener for events occuring during processing + * of this print job. + * + * @param listener the listener to add, if null nothing is done. * - * @param listener the listener to add + * @see #removePrintJobListener(PrintJobListener) */ void addPrintJobListener(PrintJobListener listener); /** - * Returns the print job's attributes. + * Returns the print job's attributes. + *

      + * The returned set of attributes is a snapshot at the time of calling this + * method and will not be updated if changes to the print job's attributes + * happens. To monitor changes register a print job listener. + *

      * - * @return the attributes of this print job + * @return The attributes of this print job, + * may be empty but never null. */ PrintJobAttributeSet getAttributes(); /** * Returns the PrintService object this print job is bound to. * - * @return the print service + * @return The print service. */ PrintService getPrintService(); /** * Prints a document with the specified print job attributes. * + *

      + * If the doc flavor provided by the Doc implementation is + * not supported by this print service a PrintException + * implementing the FlavorException interface will be thrown. + *

      + * * @param doc the document to print - * @param attributes the attributes to use + * @param attributes the job attributes to use. If null the + * default attribute values of the print service will be used. + * + * @throws PrintException if an error occurs. The thrown exception may + * implement refining print exception interface to provide more detail of + * the error. * - * @throws PrintException if an error occurs + * @see AttributeException + * @see FlavorException */ void print(Doc doc, PrintRequestAttributeSet attributes) throws PrintException; /** - * De-registers an attribute listener. + * Removes the given listener from the listeners registered for changes + * in their provided attribute set during processing of this print job. * - * @param listener the listener to remove - */ + * @param listener the listener to remove, if null or not + * registered nothing will be done. + * + * @see #addPrintJobAttributeListener(PrintJobAttributeListener, PrintJobAttributeSet) + */ void removePrintJobAttributeListener(PrintJobAttributeListener listener); /** - * De-registers a print job listener. + * Removes the given listener from the listeners registered for events + * occuring during processing of this print job. + * + * @param listener the listener to remove, if null or not + * registered nothing will be done. * - * @param listener the listener to remove + * @see #addPrintJobListener(PrintJobListener) */ void removePrintJobListener(PrintJobListener listener); } \ No newline at end of file diff --git a/javax/print/PrintService.java b/javax/print/PrintService.java index 1a9953166..125d27083 100644 --- a/javax/print/PrintService.java +++ b/javax/print/PrintService.java @@ -1,5 +1,5 @@ /* PrintService.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,14 +45,25 @@ import javax.print.attribute.PrintServiceAttributeSet; import javax.print.event.PrintServiceAttributeListener; /** + * A PrintService represents a printer available for printing. + *

      + * The print service hereby may be a real physical printer device, a printer + * group with same capabilities or a logical print service (like for example + * a PDF writer). The print service is used to query the capabilities of the + * represented printer instance. If a suitable print service is found it is + * used to create a print job for the actual printing process. + *

      + * @see javax.print.DocPrintJob + * * @author Michael Koch (konqueror@gmx.de) */ public interface PrintService { /** - * Returns a new print job capable to handle all supported document flavors. + * Creates and returns a new print job which is capable to handle all + * the document flavors supported by this print service. * - * @return the new print job + * @return The created print job object. */ DocPrintJob createPrintJob(); @@ -61,39 +72,54 @@ public interface PrintService * * @param obj the service to check against * - * @return true if both services refer to the sam underlying - * service, false otherwise + * @return true if both services refer to the same underlying + * service, false otherwise. */ boolean equals(Object obj); /** - * Returns the value of a single specified attribute. + * Returns the value of the single specified attribute. * * @param category the category of a PrintServiceAttribute * - * @return the value of the attribute + * @return The value of the attribute, or null if the attribute + * category is not supported by this print service implementation. * - * @throws NullPointerException if category is null + * @throws NullPointerException if category is null. * @throws IllegalArgumentException if category is not a class that - * implements PrintServiceAttribute + * implements PrintServiceAttribute. */ T getAttribute(Class category); /** - * Returns all attributes of this printer service - * - * @return all attributes of this print service + * Returns the attributes describing this print service. The returned + * attributes set is unmodifiable and represents the current state of + * the print service. As some print service attributes may change + * (depends on the print service implementation) a subsequent call to + * this method may return a different set. To monitor changes a + * PrintServiceAttributeListener may be registered. + * + * @return All the description attributes of this print service. + * @see #addPrintServiceAttributeListener(PrintServiceAttributeListener) */ PrintServiceAttributeSet getAttributes(); /** - * Returns the service's default value for a given attribute. + * Determines and returns the default value for a given attribute category + * of this print service. + *

      + * A return value of null means either that the print service + * does not support the attribute category or there is no default value + * available for this category. To distinguish these two case one can test + * with {@link #isAttributeCategorySupported(Class)} if the category is + * supported. + *

      * * @param category the category of the attribute * - * @return the default value + * @return The default value, or null. * - * @throws NullPointerException if category is null + * @throws NullPointerException if category is null * @throws IllegalArgumentException if category is a class * not implementing Attribute */ @@ -101,36 +127,50 @@ public interface PrintService /** * Returns the name of this print service. + * This may be the value of the PrinterName attribute. * - * @return the name + * @return The print service name. */ String getName(); /** - * Returns a factory for UI components. + * Returns a factory for UI components if supported by the print service. * - * @return the factory + * @return A factory for UI components or null. */ ServiceUIFactory getServiceUIFactory(); /** * Returns all supported attribute categories. * - * @return an array of all supported attribute categories + * @return The class array of all supported attribute categories. */ Class[] getSupportedAttributeCategories(); /** - * Returns all supported attribute values a client can use when setting up - * a print job with this service. + * Determines and returns all supported attribute values of a given + * attribute category a client can use when setting up a print job + * for this print service. + *

      + * The returned object may be one of the following types: + *

        + *
      • A single instance of the attribute category to indicate that any + * value will be supported.
      • + *
      • An array of the same type as the attribute category to test, + * containing all the supported values for this category.
      • + *
      • A single object (of any other type than the attribute category) + * which indicates bounds on the supported values.
      • + *
      + *

      * * @param category the attribute category to test - * @param flavor the document flavor to use, or null - * @param attributes set of printing attributes for a supposed job, or null + * @param flavor the document flavor to use, or null + * @param attributes set of attributes for a supposed job, + * or null * - * @return object indicating supported values for category, - * or null if this print service doesnt support specifying doc-level or - * job-level attribute in a print request. + * @return A object (as defined above) indicating the supported values + * for the given attribute category, or null if this print + * service doesn't support the given attribute category at all. * * @throws NullPointerException if category is null * @throws IllegalArgumentException if category is a class not @@ -142,73 +182,101 @@ public interface PrintService AttributeSet attributes); /** - * Returns an array of all supproted document flavors. + * Determines and returns an array of all supported document flavors which + * can be used to supply print data to this print service. + *

      + * The supported attribute categories may differ between the supported + * document flavors. To test for supported attributes one can use the + * {@link #getUnsupportedAttributes(DocFlavor, AttributeSet)} method with + * the specific doc flavor and attributes set. + *

      * * @return the supported document flavors */ DocFlavor[] getSupportedDocFlavors(); /** - * Returns all attributes that are unsupported for a print request in the - * context of a particular document flavor. - * - * @param flavor document flavor to test, or null + * Identifies all the unsupported attributes of the given set of attributes + * in the context of the specified document flavor. + *

      + * The given flavor has to be supported by the print service (use + * {@link #isDocFlavorSupported(DocFlavor)} to verify). The method will + * return null if all given attributes are supported. Otherwise + * a set of unsupported attributes are returned. The attributes in the + * returned set may be completely unsupported or only the specific requested + * value. If flavor is null the default document flavor of the + * print service is used in the identification process. + *

      + * + * @param flavor document flavor to test, or null. * @param attributes set of printing attributes for a supposed job * - * @return null if this PrintService supports the print request - * specification, else the unsupported attributes + * @return null if this print service supports all the given + * attributes for the specified doc flavor. Otherwise the set of unsupported + * attributes are returned. * * @throws IllegalArgumentException if flavor is unsupported */ AttributeSet getUnsupportedAttributes(DocFlavor flavor, AttributeSet attributes); + /** - * Returns a hashcode for this printer service. + * Returns a hashcode for this print service. * - * @return the hashcode + * @return The hashcode. */ int hashCode(); /** - * Determines a given attribute category is supported or not. + * Determines a given attribute category is supported by this + * print service implementation. This only tests for the category + * not for any specific values of this category nor in the context + * of a specific document flavor. * * @param category the category to check * * @return true if category is supported, - * false otherwise + * false otherwise. * - * @throws NullPointerException if category is null + * @throws NullPointerException if category is null * @throws IllegalArgumentException if category is a class not * implementing Attribute. */ boolean isAttributeCategorySupported(Class category); /** - * Determines a given attribute value is supported when creating a print job - * for this print service. + * Determines if a given attribute value is supported when creating a print + * job for this print service. + *

      + * If either the document flavor or the provided attributes are + * null it is determined if the given attribute value is + * supported in some combination of the available document flavors and + * attributes of the print service. Otherwise it is checked for the + * specific context of the given document flavor/attributes set. + *

      * * @param attrval the attribute value to check - * @param flavor the document flavor to use, or null - * @param attributes set of printing attributes to use, or null + * @param flavor the document flavor to use, or null. + * @param attributes set of attributes to use, or null. * - * @return true if the attribute value is supported, - * false otherwise + * @return true if the attribute value is supported in the + * requested context, false otherwise. * - * @throws NullPointerException if attrval is null + * @throws NullPointerException if attrval is null. * @throws IllegalArgumentException if flavor is not supported * by this print service */ boolean isAttributeValueSupported(Attribute attrval, DocFlavor flavor, AttributeSet attributes); /** - * Determines a given document flavor is supported or not. + * Determines if a given document flavor is supported or not. * * @param flavor the document flavor to check * * @return true if flavor is supported, - * false otherwise + * false otherwise. * - * @throws NullPointerException if flavor is null + * @throws NullPointerException if flavor is null. */ boolean isDocFlavorSupported(DocFlavor flavor); diff --git a/javax/print/SimpleDoc.java b/javax/print/SimpleDoc.java new file mode 100644 index 000000000..a49406bcb --- /dev/null +++ b/javax/print/SimpleDoc.java @@ -0,0 +1,223 @@ +/* SimpleDoc.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.print; + +import java.io.ByteArrayInputStream; +import java.io.CharArrayReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; + +import javax.print.attribute.AttributeSetUtilities; +import javax.print.attribute.DocAttributeSet; + +/** + * Simple implementation of the Doc interface capable of handling + * the predefined document flavors of DocFlavor. + *

      + * This implementation can construct a reader or stream for the service from + * the print data and ensures that always the same object is returned on each + * method call. It does simple checks that the supplied data matches the + * specified flavor of the doc object and supports thread safe access. + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class SimpleDoc implements Doc +{ + private final Object printData; + private final DocFlavor flavor; + private final DocAttributeSet attributes; + + private InputStream stream; + private Reader reader; + + /** + * Constructs a SimpleDoc with the specified print data, doc flavor and doc attribute set. + * @param printData the object with the data to print. + * @param flavor the document flavor of the print data. + * @param attributes the attributes of the doc (may be null). + * + * @throws IllegalArgumentException if either printData or + * flavor are null, or the print data is not + * supplied in the document format specified by the given flavor object. + */ + public SimpleDoc(Object printData, DocFlavor flavor, + DocAttributeSet attributes) + { + if (printData == null || flavor == null) + throw new IllegalArgumentException("printData/flavor may not be null"); + + if (! (printData.getClass().getName().equals( + flavor.getRepresentationClassName()) + || flavor.getRepresentationClassName().equals("java.io.Reader") + && printData instanceof Reader + || flavor.getRepresentationClassName().equals("java.io.InputStream") + && printData instanceof InputStream)) + { + throw new IllegalArgumentException("data is not of declared flavor type"); + } + + this.printData = printData; + this.flavor = flavor; + + if (attributes != null) + this.attributes = AttributeSetUtilities.unmodifiableView(attributes); + else + this.attributes = null; + + stream = null; + reader = null; + } + + /** + * Returns the unmodifiable view of the attributes of this doc object. + *

      + * The attributes of this doc's attributes set overrides attributes of + * the same category in the print job's attribute set. If an attribute + * is not available in this doc's attributes set or null + * is returned the attributes of the same category of the print job are + * used. + *

      + * + * @return The unmodifiable attributes set, or null. + */ + public DocAttributeSet getAttributes() + { + return attributes; + } + + /** + * Returns the flavor of this doc objects print data. + * + * @return The document flavor. + */ + public DocFlavor getDocFlavor() + { + return flavor; + } + + /** + * Returns the print data of this doc object. + *

      + * The returned object is an instance as described by the associated + * document flavor ({@link DocFlavor#getRepresentationClassName()}) + * and can be cast to this representation class. + *

      + * + * @return The print data in the representation class. + * @throws IOException if representation class is a stream and I/O + * exception occures. + */ + public Object getPrintData() throws IOException + { + return printData; + } + + /** + * Returns a Reader object for extracting character print data + * from this document. + *

      + * This method is supported if the document flavor is of type: + *

        + *
      • char[]
      • + *
      • java.lang.String
      • + *
      • java.io.Reader
      • + *
      + * otherwise this method returns null. + *

      + * + * @return The Reader object, or null. + * + * @throws IOException if an error occurs. + */ + public Reader getReaderForText() throws IOException + { + synchronized (this) + { + // construct the reader if applicable on request + if (reader == null) + { + if (flavor instanceof DocFlavor.CHAR_ARRAY) + reader = new CharArrayReader((char[]) printData); + else if (flavor instanceof DocFlavor.STRING) + reader = new StringReader((String) printData); + else if (flavor instanceof DocFlavor.READER) + reader = (Reader) printData; + } + + return reader; + } + } + + /** + * Returns an InputStream object for extracting byte print data + * from this document. + *

      + * This method is supported if the document flavor is of type: + *

        + *
      • byte[]
      • + *
      • java.io.InputStream
      • + *
      + * otherwise this method returns null. + *

      + * + * @return The InputStream object, or null. + * + * @throws IOException if an error occurs. + */ + public InputStream getStreamForBytes() throws IOException + { + synchronized (this) + { + // construct the stream if applicable on request + if (stream == null) + { + if (flavor instanceof DocFlavor.BYTE_ARRAY) + stream = new ByteArrayInputStream((byte[]) printData); + else if (flavor instanceof DocFlavor.INPUT_STREAM) + stream = (InputStream) printData; + } + + return stream; + } + } + +} diff --git a/javax/print/StreamPrintService.java b/javax/print/StreamPrintService.java index 9246ea47e..8398a734c 100644 --- a/javax/print/StreamPrintService.java +++ b/javax/print/StreamPrintService.java @@ -1,5 +1,5 @@ /* StreamPrintService.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,6 +42,15 @@ import java.io.OutputStream; /** + * StreamPrintService is a special print service capable of + * printing into a supplied output stream. + *

      + * Beside providing the same functionality as a print service it additionally + * allows to specify the output stream for the print data. A stream print + * service is obtained via the {@link javax.print.StreamPrintServiceFactory} + * by looking for services supporting a given output format type. + *

      + * * @author Michael Koch (konqueror@gmx.de) */ public abstract class StreamPrintService implements PrintService @@ -68,16 +77,18 @@ public abstract class StreamPrintService implements PrintService } /** - * Returns the document format emited by this print service. + * Returns the document format emitted by this print service. + * The returned string is a MIME type compatible with the + * {@link DocFlavor} class. * - * @return the document format + * @return The document format of the output. */ public abstract String getOutputFormat(); /** * Returns the OutputStream of this object. * - * @return the OutputStream + * @return The OutputStream */ public OutputStream getOutputStream() { diff --git a/javax/print/StreamPrintServiceFactory.java b/javax/print/StreamPrintServiceFactory.java new file mode 100644 index 000000000..90496b36a --- /dev/null +++ b/javax/print/StreamPrintServiceFactory.java @@ -0,0 +1,130 @@ +/* StreamPrintServiceFactory.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.print; + +import gnu.classpath.ServiceFactory; + +import java.io.OutputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; + +/** + * StreamPrintServiceFactory provides a static method to lookup + * registered factories to construct StreamPrintService instances. + *

      + * StreamPrintService are used to print into a provided output + * stream in the document format provided by the stream print service + * implementation. + *

      + * Implementations are located and loaded automatically through the SPI JAR + * file specification. Therefore implementation classes must provide a default + * constructor for instantiation. + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public abstract class StreamPrintServiceFactory +{ + /** + * Default public constructor. + * Used for automatic loading and instantiation through + * the SPI jar file specification. + */ + public StreamPrintServiceFactory() + { + // nothing to do + } + + /** + * Searches for matching factories providing stream print services that + * support the printing of documents with the given document flavor into + * the given output mime type. + * + * @param flavor the document flavor needed, null doesn't + * constrain the lookup result. + * @param outputMimeType the mime type needed, null doesn't + * constrain the lookup result. + * + * @return The matching StreamPrintServiceFactory instances. + */ + public static StreamPrintServiceFactory[] lookupStreamPrintServiceFactories( + DocFlavor flavor, String outputMimeType) + { + HashSet set = new HashSet(); + + Iterator it = + ServiceFactory.lookupProviders(StreamPrintServiceFactory.class); + + while (it.hasNext()) + { + StreamPrintServiceFactory tmp = (StreamPrintServiceFactory) it.next(); + if (tmp.getOutputFormat().equals(outputMimeType) + && Arrays.asList(tmp.getSupportedDocFlavors()).contains(flavor)) + set.add(tmp); + } + + StreamPrintServiceFactory[] tmp = new StreamPrintServiceFactory[set.size()]; + return (StreamPrintServiceFactory[]) set.toArray(tmp); + } + + /** + * Returns the output format supported by this factory. + * + * @return The mime type of the output format as string representation. + */ + public abstract String getOutputFormat(); + + /** + * Returns the document flavors this factory supports as flavors + * for the input documents. + * + * @return The array of supported document flavors. + */ + public abstract DocFlavor[] getSupportedDocFlavors(); + + /** + * Constructs a StreamPrintService which directs its output + * the given output stream. + * + * @param out the output stream for the produced document. + * @return The constructed stream print service. + */ + public abstract StreamPrintService getPrintService(OutputStream out); +} diff --git a/javax/print/attribute/AttributeSetUtilities.java b/javax/print/attribute/AttributeSetUtilities.java index 95b4cc553..95c11a6ed 100644 --- a/javax/print/attribute/AttributeSetUtilities.java +++ b/javax/print/attribute/AttributeSetUtilities.java @@ -1,5 +1,5 @@ /* AttributeSetUtilities.java -- - Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -78,14 +78,14 @@ public final class AttributeSetUtilities private static class UnmodifiableAttributeSet implements AttributeSet, Serializable { - private AttributeSet set; + private AttributeSet attrset; public UnmodifiableAttributeSet(AttributeSet attributeSet) { if (attributeSet == null) throw new NullPointerException("attributeSet may not be null"); - this.set = attributeSet; + this.attrset = attributeSet; } public boolean add(Attribute attribute) @@ -105,32 +105,32 @@ public final class AttributeSetUtilities public boolean containsKey(Class category) { - return set.containsKey(category); + return attrset.containsKey(category); } public boolean containsValue(Attribute attribute) { - return set.containsValue(attribute); + return attrset.containsValue(attribute); } public boolean equals(Object obj) { - return set.equals(obj); + return attrset.equals(obj); } public Attribute get(Class interfaceName) { - return set.get(interfaceName); + return attrset.get(interfaceName); } public int hashCode() { - return set.hashCode(); + return attrset.hashCode(); } public boolean isEmpty() { - return set.isEmpty(); + return attrset.isEmpty(); } public boolean remove(Class category) @@ -145,12 +145,12 @@ public final class AttributeSetUtilities public int size() { - return set.size(); + return attrset.size(); } public Attribute[] toArray() { - return set.toArray(); + return attrset.toArray(); } } @@ -197,79 +197,79 @@ public final class AttributeSetUtilities private static class SynchronizedAttributeSet implements AttributeSet, Serializable { - private AttributeSet set; + private AttributeSet attrset; public SynchronizedAttributeSet(AttributeSet attributeSet) { if (attributeSet == null) throw new NullPointerException("attributeSet may not be null"); - this.set = attributeSet; + attrset = attributeSet; } public synchronized boolean add(Attribute attribute) { - return set.add(attribute); + return attrset.add(attribute); } public synchronized boolean addAll(AttributeSet attributes) { - return set.addAll(attributes); + return attrset.addAll(attributes); } public synchronized void clear() { - set.clear(); + attrset.clear(); } public synchronized boolean containsKey(Class category) { - return set.containsKey(category); + return attrset.containsKey(category); } public synchronized boolean containsValue(Attribute attribute) { - return set.containsValue(attribute); + return attrset.containsValue(attribute); } public synchronized boolean equals(Object obj) { - return set.equals(obj); + return attrset.equals(obj); } public synchronized Attribute get(Class interfaceName) { - return set.get(interfaceName); + return attrset.get(interfaceName); } public synchronized int hashCode() { - return set.hashCode(); + return attrset.hashCode(); } public synchronized boolean isEmpty() { - return set.isEmpty(); + return attrset.isEmpty(); } public synchronized boolean remove(Class category) { - return set.remove(category); + return attrset.remove(category); } public synchronized boolean remove(Attribute attribute) { - return set.remove(attribute); + return attrset.remove(attribute); } public synchronized int size() { - return set.size(); + return attrset.size(); } public synchronized Attribute[] toArray() { - return set.toArray(); + return attrset.toArray(); } } diff --git a/javax/print/attribute/DateTimeSyntax.java b/javax/print/attribute/DateTimeSyntax.java index d59193265..8cff70219 100644 --- a/javax/print/attribute/DateTimeSyntax.java +++ b/javax/print/attribute/DateTimeSyntax.java @@ -102,4 +102,14 @@ public abstract class DateTimeSyntax implements Cloneable, Serializable { return value.hashCode(); } + + /** + * Returns the string representation for this object. + * + * @return The string representation. + */ + public String toString() + { + return value.toString(); + } } diff --git a/javax/print/attribute/HashAttributeSet.java b/javax/print/attribute/HashAttributeSet.java index cdf333a27..0f6b00730 100644 --- a/javax/print/attribute/HashAttributeSet.java +++ b/javax/print/attribute/HashAttributeSet.java @@ -1,5 +1,5 @@ /* HashAttributeSet.java -- - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,6 +37,9 @@ exception statement from your version. */ package javax.print.attribute; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; @@ -49,8 +52,8 @@ public class HashAttributeSet implements AttributeSet, Serializable { private static final long serialVersionUID = 5311560590283707917L; - private Class interfaceName; - private HashMap attributeMap = new HashMap(); + private Class myInterface; + private transient HashMap attributeMap = new HashMap(); /** * Creates an empty HashAttributeSet object. @@ -112,7 +115,7 @@ public class HashAttributeSet implements AttributeSet, Serializable if (interfaceName == null) throw new NullPointerException("interfaceName may not be null"); - this.interfaceName = interfaceName; + myInterface = interfaceName; } /** @@ -192,7 +195,7 @@ public class HashAttributeSet implements AttributeSet, Serializable */ public boolean add(Attribute attribute) { - return addInternal(attribute, interfaceName); + return addInternal(attribute, myInterface); } private boolean addInternal(Attribute attribute, Class interfaceName) @@ -201,7 +204,7 @@ public class HashAttributeSet implements AttributeSet, Serializable throw new NullPointerException("attribute may not be null"); AttributeSetUtilities.verifyAttributeCategory(interfaceName, - this.interfaceName); + myInterface); Object old = attributeMap.put (attribute.getCategory(), AttributeSetUtilities.verifyAttributeValue @@ -220,7 +223,7 @@ public class HashAttributeSet implements AttributeSet, Serializable */ public boolean addAll(AttributeSet attributes) { - return addAllInternal(attributes, interfaceName); + return addAllInternal(attributes, myInterface); } private boolean addAllInternal(AttributeSet attributes, Class interfaceName) @@ -393,4 +396,24 @@ public class HashAttributeSet implements AttributeSet, Serializable return array; } + + // Implemented as specified in serialized form + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException + { + myInterface = (Class) s.readObject(); + int size = s.readInt(); + attributeMap = new HashMap(size); + for (int i=0; i < size; i++) + add((Attribute) s.readObject()); + } + + private void writeObject(ObjectOutputStream s) throws IOException + { + s.writeObject(myInterface); + s.writeInt(size()); + Iterator it = attributeMap.values().iterator(); + while (it.hasNext()) + s.writeObject(it.next()); + } } diff --git a/javax/print/attribute/standard/Compression.java b/javax/print/attribute/standard/Compression.java index 388281216..f2f4f1cc1 100644 --- a/javax/print/attribute/standard/Compression.java +++ b/javax/print/attribute/standard/Compression.java @@ -1,5 +1,5 @@ /* Compression.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -102,7 +102,7 @@ public class Compression extends EnumSyntax * * @return The name "compression". */ - public String getName() + public final String getName() { return "compression"; } diff --git a/javax/print/attribute/standard/Finishings.java b/javax/print/attribute/standard/Finishings.java index 78ca3f454..cd8f6753b 100644 --- a/javax/print/attribute/standard/Finishings.java +++ b/javax/print/attribute/standard/Finishings.java @@ -1,5 +1,5 @@ /* Finishings.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -249,7 +249,7 @@ public class Finishings extends EnumSyntax * * @return The name "finishings". */ - public String getName() + public final String getName() { return "finishings"; } diff --git a/javax/print/attribute/standard/JobMediaSheets.java b/javax/print/attribute/standard/JobMediaSheets.java index 2b5e12d24..17cf96f33 100644 --- a/javax/print/attribute/standard/JobMediaSheets.java +++ b/javax/print/attribute/standard/JobMediaSheets.java @@ -1,5 +1,5 @@ /* JobMediaSheets.java -- - Copyright (C) 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -118,7 +118,7 @@ public class JobMediaSheets extends IntegerSyntax * * @return The name "job-media-sheets". */ - public String getName() + public final String getName() { return "job-media-sheets"; } diff --git a/javax/print/attribute/standard/JobSheets.java b/javax/print/attribute/standard/JobSheets.java index 59460ab25..a930f63cf 100644 --- a/javax/print/attribute/standard/JobSheets.java +++ b/javax/print/attribute/standard/JobSheets.java @@ -1,5 +1,5 @@ /* JobSheets.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -99,7 +99,7 @@ public class JobSheets extends EnumSyntax * * @return The name "job-sheets". */ - public String getName() + public final String getName() { return "job-sheets"; } diff --git a/javax/print/attribute/standard/JobState.java b/javax/print/attribute/standard/JobState.java index 8304b8b30..fa769bbf3 100644 --- a/javax/print/attribute/standard/JobState.java +++ b/javax/print/attribute/standard/JobState.java @@ -1,5 +1,5 @@ /* JobState.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -148,7 +148,7 @@ public class JobState extends EnumSyntax * * @return The name "job-state". */ - public String getName() + public final String getName() { return "job-state"; } diff --git a/javax/print/attribute/standard/JobStateReason.java b/javax/print/attribute/standard/JobStateReason.java index 3981d94a2..b8420b180 100644 --- a/javax/print/attribute/standard/JobStateReason.java +++ b/javax/print/attribute/standard/JobStateReason.java @@ -1,5 +1,5 @@ /* JobStateReason.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -272,7 +272,7 @@ public class JobStateReason extends EnumSyntax * * @return The name "job-state-reason". */ - public String getName() + public final String getName() { return "job-state-reason"; } diff --git a/javax/print/attribute/standard/Media.java b/javax/print/attribute/standard/Media.java index 5ac204bf6..4c0af0ed1 100644 --- a/javax/print/attribute/standard/Media.java +++ b/javax/print/attribute/standard/Media.java @@ -1,5 +1,5 @@ /* Media.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -116,7 +116,7 @@ public abstract class Media extends EnumSyntax * * @return The name "media". */ - public String getName() + public final String getName() { return "media"; } diff --git a/javax/print/attribute/standard/MediaPrintableArea.java b/javax/print/attribute/standard/MediaPrintableArea.java index 6ef0de109..84ebd61ce 100644 --- a/javax/print/attribute/standard/MediaPrintableArea.java +++ b/javax/print/attribute/standard/MediaPrintableArea.java @@ -1,5 +1,5 @@ /* MediaPrintableArea.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -96,9 +96,9 @@ public final class MediaPrintableArea /** y in micrometers. */ private int y; /** width in micrometers. */ - private int width; + private int w; /** height in micrometers. */ - private int height; + private int h; /** * Creates a new MediaPrintableArea object with the given @@ -120,8 +120,8 @@ public final class MediaPrintableArea this.x = (int) (x * units + 0.5f); this.y = (int) (y * units + 0.5f); - this.width = (int) (w * units + 0.5f); - this.height = (int) (h * units + 0.5f); + this.w = (int) (w * units + 0.5f); + this.h = (int) (h * units + 0.5f); } /** @@ -144,8 +144,8 @@ public final class MediaPrintableArea this.x = x * units; this.y = y * units; - this.width = w * units; - this.height = h * units; + this.w = w * units; + this.h = h * units; } /** @@ -181,7 +181,7 @@ public final class MediaPrintableArea if (units < 1) throw new IllegalArgumentException("units may not be less than 1"); - return height / ((float)units); + return h / ((float)units); } /** @@ -197,7 +197,7 @@ public final class MediaPrintableArea if (units < 1) throw new IllegalArgumentException("units may not be less than 1"); - return width / ((float)units); + return w / ((float)units); } /** @@ -249,7 +249,7 @@ public final class MediaPrintableArea MediaPrintableArea tmp = (MediaPrintableArea) obj; return (x == tmp.getX(1) && y == tmp.getY(1) - && width == tmp.getWidth(1) && height == tmp.getHeight(1)); + && w == tmp.getWidth(1) && h == tmp.getHeight(1)); } /** @@ -271,7 +271,7 @@ public final class MediaPrintableArea */ public int hashCode() { - return x ^ y + width ^ height; + return x ^ y + w ^ h; } /** diff --git a/javax/print/attribute/standard/MediaSize.java b/javax/print/attribute/standard/MediaSize.java index bf17d3cd3..be3f15678 100644 --- a/javax/print/attribute/standard/MediaSize.java +++ b/javax/print/attribute/standard/MediaSize.java @@ -1,5 +1,5 @@ /* MediaSize.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -73,6 +73,13 @@ public class MediaSize extends Size2DSyntax { mediaCache = new ArrayList(); + // We call one instance of every container class to make sure it gets + // loaded during class initialization and therefore all other static + // fields of this container class also. + + // This is needed to put all MediaSize instance into the mediaCache + // for use by the static methods in this class. + MediaSize tmp = MediaSize.ISO.A0; tmp = MediaSize.JIS.B0; tmp = MediaSize.Engineering.A; @@ -80,16 +87,21 @@ public class MediaSize extends Size2DSyntax tmp = MediaSize.Other.EXECUTIVE; } - private MediaSizeName media; + private MediaSizeName mediaName; /** - * Creates a MediaSize object. + * Creates a MediaSize object. The created object will be added + * to an internal cache used in the static methods of this class for lookup + * of available MediaSize instances. * * @param x the size in x direction * @param y the size in y direction * @param units the units to use for the sizes * * @exception IllegalArgumentException if x or y < 0 or units < 1 + * + * @see #findMedia(float, float, int) + * @see #getMediaSizeForName(MediaSizeName) */ public MediaSize(float x, float y, int units) { @@ -99,7 +111,9 @@ public class MediaSize extends Size2DSyntax /** * Creates a MediaSize object associated with the given - * media name. + * media name. The created object will be added to an internal cache used + * in the static methods of this class for lookup of available + * MediaSize instances. * * @param x the size in x direction * @param y the size in y direction @@ -107,22 +121,30 @@ public class MediaSize extends Size2DSyntax * @param media the media name to associate * * @exception IllegalArgumentException if x or y < 0 or units < 1 + * + * @see #findMedia(float, float, int) + * @see #getMediaSizeForName(MediaSizeName) */ public MediaSize(float x, float y, int units, MediaSizeName media) { super(x, y, units); - this.media = media; + mediaName = media; mediaCache.add(this); } /** - * Creates a MediaSize object. + * Creates a MediaSize object. The created object will be added + * to an internal cache used in the static methods of this class for lookup + * of available MediaSize instances. * * @param x the size in x direction * @param y the size in y direction * @param units the units to use for the sizes * * @exception IllegalArgumentException if x or y < 0 or units < 1 + * + * @see #findMedia(float, float, int) + * @see #getMediaSizeForName(MediaSizeName) */ public MediaSize(int x, int y, int units) { @@ -132,7 +154,9 @@ public class MediaSize extends Size2DSyntax /** * Creates a MediaSize object associated with the given - * media name. + * media name. The created object will be added to an internal cache used + * in the static methods of this class for lookup of available + * MediaSize instances. * * @param x the size in x direction * @param y the size in y direction @@ -140,11 +164,14 @@ public class MediaSize extends Size2DSyntax * @param media the media name to associate * * @exception IllegalArgumentException if x or y < 0 or units < 1 + * + * @see #findMedia(float, float, int) + * @see #getMediaSizeForName(MediaSizeName) */ public MediaSize(int x, int y, int units, MediaSizeName media) { super(x, y, units); - this.media = media; + mediaName = media; mediaCache.add(this); } @@ -247,7 +274,7 @@ public class MediaSize extends Size2DSyntax */ public MediaSizeName getMediaSizeName() { - return media; + return mediaName; } /** @@ -255,7 +282,7 @@ public class MediaSize extends Size2DSyntax * * @return The name "media-size". */ - public String getName() + public final String getName() { return "media-size"; } @@ -267,7 +294,11 @@ public class MediaSize extends Size2DSyntax */ public static final class ISO { - + private ISO() + { + // prevent instantiation + } + /** * ISO A0 paper, 841 mm x 1189 mm. */ @@ -416,6 +447,11 @@ public class MediaSize extends Size2DSyntax */ public static final class NA { + private NA() + { + // prevent instantiation + } + /** * US Legal paper size, 8.5 inch x 14 inch */ @@ -531,6 +567,11 @@ public class MediaSize extends Size2DSyntax */ public static final class Engineering { + private Engineering() + { + // prevent instantiation + } + /** * ANSI A paper size. 8.5 inch x 11 inch */ @@ -569,6 +610,11 @@ public class MediaSize extends Size2DSyntax */ public static final class JIS { + private JIS() + { + // prevent instantiation + } + /** * JIS B0 paper. 1030 mm x 1456 mm * Note: The JIS B-series is not identical to the ISO B-series. @@ -763,6 +809,11 @@ public class MediaSize extends Size2DSyntax */ public static final class Other { + private Other() + { + // prevent instantiation + } + /** * US Executive paper size, 7.25 inch x 10.5 inch */ @@ -821,6 +872,13 @@ public class MediaSize extends Size2DSyntax * Japanese double postcard, 148 mm x 200 mm */ public static final MediaSize JAPANESE_DOUBLE_POSTCARD = new MediaSize(148, 200, MediaSize.MM, MediaSizeName.JAPANESE_DOUBLE_POSTCARD); + + /** + * Tabloid size, 11 inch x 17 inch. + * @since 1.5 + */ + public static final MediaSize TABLOID = + new MediaSize(11, 17, Size2DSyntax.INCH, MediaSizeName.TABLOID); } } diff --git a/javax/print/attribute/standard/MultipleDocumentHandling.java b/javax/print/attribute/standard/MultipleDocumentHandling.java index 4da904398..3ee1b4126 100644 --- a/javax/print/attribute/standard/MultipleDocumentHandling.java +++ b/javax/print/attribute/standard/MultipleDocumentHandling.java @@ -1,5 +1,5 @@ /* MultipleDocumentHandling.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -119,7 +119,7 @@ public class MultipleDocumentHandling extends EnumSyntax * * @return The name "multiple-document-handling". */ - public String getName() + public final String getName() { return "multiple-document-handling"; } diff --git a/javax/print/attribute/standard/PDLOverrideSupported.java b/javax/print/attribute/standard/PDLOverrideSupported.java index 6e5ab11d4..02c9c198c 100644 --- a/javax/print/attribute/standard/PDLOverrideSupported.java +++ b/javax/print/attribute/standard/PDLOverrideSupported.java @@ -1,5 +1,5 @@ /* PDLOverrideSupported.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -102,7 +102,7 @@ public class PDLOverrideSupported extends EnumSyntax * * @return The name "pdl-override-supported". */ - public String getName() + public final String getName() { return "pdl-override-supported"; } diff --git a/javax/print/attribute/standard/PrintQuality.java b/javax/print/attribute/standard/PrintQuality.java index af7ec8f50..bc94d532b 100644 --- a/javax/print/attribute/standard/PrintQuality.java +++ b/javax/print/attribute/standard/PrintQuality.java @@ -1,5 +1,5 @@ /* PrintQuality.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -103,7 +103,7 @@ public class PrintQuality extends EnumSyntax * * @return The name "print-quality". */ - public String getName() + public final String getName() { return "print-quality"; } diff --git a/javax/print/attribute/standard/PrinterIsAcceptingJobs.java b/javax/print/attribute/standard/PrinterIsAcceptingJobs.java index d87bf784e..1c9c39930 100644 --- a/javax/print/attribute/standard/PrinterIsAcceptingJobs.java +++ b/javax/print/attribute/standard/PrinterIsAcceptingJobs.java @@ -56,7 +56,7 @@ import javax.print.attribute.PrintServiceAttribute; * @author Michael Koch (konqueror@gmx.de) * @author Wolfgang Baer (WBaer@gmx.de) */ -public class PrinterIsAcceptingJobs extends EnumSyntax +public final class PrinterIsAcceptingJobs extends EnumSyntax implements PrintServiceAttribute { private static final long serialVersionUID = -5052010680537678061L; diff --git a/javax/print/attribute/standard/PrinterStateReason.java b/javax/print/attribute/standard/PrinterStateReason.java index 754e448ce..1abb7c6aa 100644 --- a/javax/print/attribute/standard/PrinterStateReason.java +++ b/javax/print/attribute/standard/PrinterStateReason.java @@ -1,5 +1,5 @@ /* PrinterStateReason.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -303,7 +303,7 @@ public class PrinterStateReason extends EnumSyntax * * @return The name "printer-state-reason". */ - public String getName() + public final String getName() { return "printer-state-reason"; } diff --git a/javax/print/attribute/standard/PrinterStateReasons.java b/javax/print/attribute/standard/PrinterStateReasons.java index d8e9f9fc1..c58dd5379 100644 --- a/javax/print/attribute/standard/PrinterStateReasons.java +++ b/javax/print/attribute/standard/PrinterStateReasons.java @@ -178,7 +178,7 @@ public final class PrinterStateReasons if (severity == null) throw new NullPointerException("severity is null"); - return put((PrinterStateReason) reason, (Severity) severity); + return super.put((PrinterStateReason) reason, (Severity) severity); } /** diff --git a/javax/print/attribute/standard/ReferenceUriSchemesSupported.java b/javax/print/attribute/standard/ReferenceUriSchemesSupported.java index 59afa667a..9d2354bd6 100644 --- a/javax/print/attribute/standard/ReferenceUriSchemesSupported.java +++ b/javax/print/attribute/standard/ReferenceUriSchemesSupported.java @@ -1,5 +1,5 @@ /* ReferenceUriSchemesSupported.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -138,7 +138,7 @@ public class ReferenceUriSchemesSupported extends EnumSyntax * * @return The name "reference-uri-schemes-supported". */ - public String getName() + public final String getName() { return "reference-uri-schemes-supported"; } diff --git a/javax/security/auth/login/AppConfigurationEntry.java b/javax/security/auth/login/AppConfigurationEntry.java index ce0db2ee6..3c8b64d4c 100644 --- a/javax/security/auth/login/AppConfigurationEntry.java +++ b/javax/security/auth/login/AppConfigurationEntry.java @@ -1,5 +1,5 @@ /* AppConfigurationEntry.java - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,7 +44,6 @@ import java.util.Map; public class AppConfigurationEntry { - // Fields. // ------------------------------------------------------------------------- @@ -61,13 +60,16 @@ public class AppConfigurationEntry { if (loginModuleName == null || loginModuleName.length() == 0) throw new IllegalArgumentException ("module name cannot be null nor empty"); + if (LoginModuleControlFlag.OPTIONAL != controlFlag && LoginModuleControlFlag.REQUIRED != controlFlag && LoginModuleControlFlag.REQUISITE != controlFlag && LoginModuleControlFlag.SUFFICIENT != controlFlag) throw new IllegalArgumentException ("invalid controlFlag"); + if (options == null) throw new IllegalArgumentException ("options cannot be null"); + this.loginModuleName = loginModuleName; this.controlFlag = controlFlag; this.options = Collections.unmodifiableMap (new HashMap (options)); @@ -91,7 +93,17 @@ public class AppConfigurationEntry return options; } - // Inner class. + // Object methods ---------------------------------------------------------- + + public String toString() + { + + return loginModuleName + "\t" + + String.valueOf(controlFlag) + "\t" + + String.valueOf(options); + } + + // Inner class. // ------------------------------------------------------------------------- public static class LoginModuleControlFlag @@ -117,19 +129,15 @@ public class AppConfigurationEntry public String toString() { - StringBuffer buf = new StringBuffer (LoginModuleControlFlag.class.getName()); - buf.append ('.'); - if (this == OPTIONAL) - buf.append ("OPTIONAL"); - else if (this == REQUIRED) - buf.append ("REQUIRED"); - else if (this == REQUISITE) - buf.append ("REQUISITE"); - else if (this == SUFFICIENT) - buf.append ("SUFFICIENT"); - else - buf.append ("HARVEY_THE_RABBIT"); - return buf.toString(); + if (this == LoginModuleControlFlag.REQUIRED) + return "REQUIRED"; + if (this == LoginModuleControlFlag.REQUISITE) + return "REQUISITE"; + if (this == LoginModuleControlFlag.SUFFICIENT) + return "SUFFICIENT"; + if (this == LoginModuleControlFlag.OPTIONAL) + return "OPTIONAL"; + return "???"; } } } diff --git a/javax/security/auth/login/Configuration.java b/javax/security/auth/login/Configuration.java index eb5e4a819..fe56f8a59 100644 --- a/javax/security/auth/login/Configuration.java +++ b/javax/security/auth/login/Configuration.java @@ -1,5 +1,5 @@ /* Configuration.java - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.security.auth.login; +import gnu.javax.security.auth.login.GnuConfiguration; + import java.security.AccessController; import java.security.PrivilegedAction; import java.security.Security; @@ -46,7 +48,6 @@ import javax.security.auth.AuthPermission; public abstract class Configuration { - // Fields. // ------------------------------------------------------------------------- @@ -108,11 +109,11 @@ public abstract class Configuration if (conf != null) config = (Configuration) Class.forName (conf).newInstance(); else - config = new NullConfiguration(); + config = new GnuConfiguration(); } catch (Exception x) { - config = new NullConfiguration(); + config = new GnuConfiguration(); } } return config; diff --git a/javax/sound/sampled/LineEvent.java b/javax/sound/sampled/LineEvent.java index 7bba2cd1d..db925935b 100644 --- a/javax/sound/sampled/LineEvent.java +++ b/javax/sound/sampled/LineEvent.java @@ -38,16 +38,24 @@ exception statement from your version. */ package javax.sound.sampled; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.EventObject; -// FIXME: attempts to serialize this should fail - /** * This class holds information about a state change of a Line. + * @specnote This class is not really serializable, and attempts to + * serialize it will throw {@link NotSerializableException}. * @since 1.3 */ public class LineEvent extends EventObject { + // We define this even though this class can't be serialized, in + // order to placate the compiler. + private static final long serialVersionUID = -1274246333383880410L; + /** * This class represents the kinds of state changes that can occur * to a Line. The standard states are availabe as static instances. @@ -147,4 +155,16 @@ public class LineEvent extends EventObject return ("type=" + type + "; framePosition=" + framePosition + "line=" + line); } + + private void readObject(ObjectInputStream ois) + throws IOException + { + throw new NotSerializableException("LineEvent is not serializable"); + } + + private void writeObject(ObjectOutputStream oos) + throws IOException + { + throw new NotSerializableException("LineEvent is not serializable"); + } } diff --git a/javax/swing/AbstractAction.java b/javax/swing/AbstractAction.java index bd3167e1e..25db58ed0 100644 --- a/javax/swing/AbstractAction.java +++ b/javax/swing/AbstractAction.java @@ -1,5 +1,5 @@ /* AbstractAction.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -74,12 +74,11 @@ public abstract class AbstractAction private transient HashMap store = new HashMap(); /** - * Creates a new action with an empty string for the name. All other - * properties are initialised to null + * Creates a new action with no properties set. */ public AbstractAction() { - this(null); + // Nothing to do. } /** @@ -90,7 +89,7 @@ public abstract class AbstractAction */ public AbstractAction(String name) { - this(name, null); + putValue(NAME, name); } /** @@ -174,7 +173,7 @@ public abstract class AbstractAction public void putValue(String key, Object value) { Object old = getValue(key); - if (old == null || !old.equals(value)) + if ((old == null && value != null) || (old != null && !old.equals(value))) { store.put(key, value); firePropertyChange(key, old, value); diff --git a/javax/swing/AbstractButton.java b/javax/swing/AbstractButton.java index 376b3a056..3d289084e 100644 --- a/javax/swing/AbstractButton.java +++ b/javax/swing/AbstractButton.java @@ -158,6 +158,14 @@ public abstract class AbstractButton extends JComponent { private static final long serialVersionUID = 1471056094226600578L; + /** + * The spec has no public/protected constructor for this class, so do we. + */ + ButtonChangeListener() + { + // Nothing to do here. + } + /** * Notified when the target of the listener changes its state. * diff --git a/javax/swing/CellRendererPane.java b/javax/swing/CellRendererPane.java index c59afd318..6d7b42a12 100644 --- a/javax/swing/CellRendererPane.java +++ b/javax/swing/CellRendererPane.java @@ -169,24 +169,32 @@ public class CellRendererPane extends Container implements Accessible addImpl(c, null, 0); Rectangle oldClip = graphics.getClipBounds(); - // translate to (x,y) - graphics.translate(x, y); - graphics.clipRect(0, 0, w, h); - // set bounds of c - c.setBounds(0, 0, w, h); - - // validate if necessary - if (shouldValidate) + boolean translated = false; + try { - c.validate(); + // translate to (x,y) + graphics.translate(x, y); + translated = true; + graphics.clipRect(0, 0, w, h); + // set bounds of c + c.setBounds(0, 0, w, h); + + // validate if necessary + if (shouldValidate) + { + c.validate(); + } + + // paint component + c.paint(graphics); + } + finally + { + // untranslate g + if (translated) + graphics.translate(-x, -y); + graphics.setClip(oldClip); } - - // paint component - c.paint(graphics); - - // untranslate g - graphics.translate(-x, -y); - graphics.setClip(oldClip); } /** diff --git a/javax/swing/DefaultCellEditor.java b/javax/swing/DefaultCellEditor.java index 39e48551e..5c692f91e 100644 --- a/javax/swing/DefaultCellEditor.java +++ b/javax/swing/DefaultCellEditor.java @@ -59,8 +59,7 @@ import javax.swing.tree.TreeCellEditor; * some standard object types. * * @author Andrew Selkirk - * - * @status mostly unimplemented + * @author Audrius Meskauskas */ public class DefaultCellEditor extends AbstractCellEditor @@ -69,17 +68,26 @@ public class DefaultCellEditor private static final long serialVersionUID = 3564035141373880027L; /** - * Delegates a couple of method calls (such as {@link #isCellEditable} - * to the component it contains and listens for events that indicate - * that editing has stopped. + * This changeable module access the editor component in the component + * specific way. For instance, to set the value for JTextField, we need to + * call setText(String), and for JCheckBox we need to call + * setSelected(boolean). Each default editor has the component specific + * derivative of this class. These derivatives are private inner classes of + * the DefaultCellEditor. + * + * The editor delegate is also set for the editor component as the action + * listener. It listens for the events that indicate that editing has stopped. */ protected class EditorDelegate implements ActionListener, ItemListener, Serializable { + /** + * Use the serial version UID for interoperability. + */ private static final long serialVersionUID = -1420007406015481933L; /** - * value + * The object value (updated when getting and setting the value). */ protected Object value; @@ -90,35 +98,38 @@ public class DefaultCellEditor { // Nothing to do here. } - + /** - * setValue + * Set the value for the editor component. This method is normally + * overridden to set the value in the way, specific for the text + * component, check box or combo box. * - * @param value TODO + * @param aValue the value to set (String, Boolean or Number). */ - public void setValue(Object value) + public void setValue(Object aValue) { - // TODO: should be setting the value in the editorComp - this.value = value; + value = aValue; } - /** - * getCellEditorValue - * - * @returns Object + /** + * Get the value for the editor component. This method is normally + * overridden to obtain the value in the way, specific for the text + * component, check box or combo box. + * + * @return value the value of the component (String, Boolean or Number). */ public Object getCellEditorValue() { - // TODO: should be getting the updated value from the editorComp return value; - } // getCellEditorValue() + } /** - * isCellEditable + * The default method returns true for the {@link MouseEvent} and false + * for any other events. * - * @param event TODO + * @param event the event to check * - * @returns boolean + * @returns true if the passed event is the mouse event and false otherwise */ public boolean isCellEditable(EventObject event) { @@ -129,20 +140,25 @@ public class DefaultCellEditor } // isCellEditable() /** - * shouldSelectCell + * Returns true to indicate that the editing cell can be selected. + * + * The default method returns true without action but may be overridden + * in derived classes for more specific behavior. * - * @param event TODO + * @param event unused in default method * - * @returns boolean + * @returns true always */ public boolean shouldSelectCell(EventObject event) { // return true to indicate that the editing cell may be selected return true; - } // shouldSelectCell() + } /** - * stopCellEditing + * Finish the cell editing session. This method notifies the registered + * cell editor listeners (including the table) that the editing has been + * stopped. * * @returns boolean */ @@ -153,7 +169,11 @@ public class DefaultCellEditor } // stopCellEditing() /** - * cancelCellEditing + * Cancel the cell editing session. This method notifies the registered + * cell editor listeners (including the table) that the editing has been + * canceled. + * + * @returns boolean */ public void cancelCellEditing() { @@ -161,11 +181,11 @@ public class DefaultCellEditor } // cancelCellEditing() /** - * startCellEditing + * Start editing session and returns true to indicate the editing has begun. + * The default method returns true without action but may be overridden + * in derived classes for more specific behavior. * - * @param event TODO - * - * @returns boolean + * @returns true, always */ public boolean startCellEditing(EventObject event) { @@ -174,9 +194,11 @@ public class DefaultCellEditor } // startCellEditing() /** - * actionPerformed + * This event is fired by the editor component (for instance, by pressing + * ENTER in the {@link JTextField}. The default method delegates call to + * the {@link #stopCellEditing}, finishing the editing session. * - * @param event TODO + * @param event unused in default method */ public void actionPerformed(ActionEvent event) { @@ -184,15 +206,20 @@ public class DefaultCellEditor } // actionPerformed() /** - * itemStateChanged + * This event is fired by the editor component.The default method delegates + * call to the {@link #stopCellEditing}, finishing the editing session. * - * @param event TODO + * @param event unused in default method */ public void itemStateChanged(ItemEvent event) { stopCellEditing(); } // itemStateChanged() + /** + * Notify the registered listeners (including the table) that the editing + * has been completed. + */ void fireEditingStopped() { CellEditorListener[] listeners = getCellEditorListeners(); @@ -201,6 +228,10 @@ public class DefaultCellEditor } + /** + * Notify the registered listeners (including the table) that the editing + * has been canceled. + */ void fireEditingCanceled() { CellEditorListener[] listeners = getCellEditorListeners(); @@ -208,59 +239,185 @@ public class DefaultCellEditor listeners[index].editingCanceled(changeEvent); } } // EditorDelegate + + /** + * Provides getter and setter methods to work with the text component. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ + private class JTextFieldDelegate extends EditorDelegate + { + /** + * Use the serial version UID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Set the value for the editor component. + * + * @param aValue the value to set (toString() will be called). + */ + public void setValue(Object aValue) + { + value = aValue; + JTextField f = (JTextField) editorComponent; + if (value == null) + f.setText(""); + else + f.setText(value.toString()); + } + + /** + * Get the value for the editor component. + * + * @return value the value of the component (String) + */ + public Object getCellEditorValue() + { + JTextField f = (JTextField) editorComponent; + return value = f.getText(); + } + } + + /** + * Provides getter and setter methods to work with the combo box. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ + private class JComboBoxDelegate extends EditorDelegate + { + /** + * Use the serial version UID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Set the value for the editor component. + * + * @param aValue the value to set. + */ + public void setValue(Object aValue) + { + value = aValue; + JComboBox c = (JComboBox) editorComponent; + if (value != null) + c.setSelectedItem(value); + } + + /** + * Get the value for the editor component. + * + * @return value the value of the component (as String) + */ + public Object getCellEditorValue() + { + JComboBox c = (JComboBox) editorComponent; + return value = c.getSelectedItem(); + } + } + + /** + * Provides getter and setter methods to work with the check box. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ + private class JCheckBoxDelegate extends EditorDelegate + { + /** + * Use the serial version UID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Set the value for the editor component. + * + * @param value the value to set (must be Boolean). + */ + public void setValue(Object value) + { + JCheckBox c = (JCheckBox) editorComponent; + + if (value == null) + c.setSelected(false); + else + c.setSelected( ((Boolean) value).booleanValue()); + } - /** - * editorComponent + /** + * Get the value for the editor component. + * + * @return value the value of the component (must be CharSequence) + */ + public Object getCellEditorValue() + { + JCheckBox c = (JCheckBox) editorComponent; + value = c.isSelected() ? Boolean.TRUE : Boolean.FALSE; + return value; + } + } + + /** + * The Swing JComponent, performing the editing session. */ protected JComponent editorComponent; /** - * delegate + * The editor delegate, responsible for listening the {@link #editorComponent} + * events and getting/setting its value. */ protected EditorDelegate delegate; /** - * clickCountToStart + * The number of the mouse clicks, required to start the editing session. */ protected int clickCountToStart; /** - * Constructor DefaultCellEditor + * Create the DefaultCellEditor that uses the text field as its editor + * component (appropriate for the text content) * - * @param textfield TODO + * @param textfield the text field as will be used as the editor component */ public DefaultCellEditor(JTextField textfield) { editorComponent = textfield; - clickCountToStart = 3; + clickCountToStart = 2; + delegate = new JTextFieldDelegate(); + textfield.addActionListener(delegate); } // DefaultCellEditor() /** - * Constructor DefaultCellEditor + * Constructor DefaultCellEditor that uses the checkbox (appropriate + * for boolean values) * - * @param checkbox TODO + * @param checkbox the checkbox that will be used with this editor. */ public DefaultCellEditor(JCheckBox checkbox) { editorComponent = checkbox; clickCountToStart = 1; + delegate = new JCheckBoxDelegate(); + checkbox.addActionListener(delegate); } // DefaultCellEditor() /** - * Constructor DefaultCellEditor + * Constructor DefaultCellEditor that uses the combo box. * - * @param combobox TODO + * @param combobox the combo box that will be used with this editor. */ public DefaultCellEditor(JComboBox combobox) { editorComponent = combobox; clickCountToStart = 1; + delegate = new JComboBoxDelegate(); + combobox.addActionListener(delegate); } // DefaultCellEditor() /** - * getComponent + * Get the component that performs the editing sessions. It is the same + * component that was passed in constructor. * - * @returns Component + * @returns the component, performing the editing sessions. */ public Component getComponent() { @@ -268,9 +425,9 @@ public class DefaultCellEditor } // getComponent() /** - * getClickCountToStart + * Get the number of mouse clicks, required to start the editing session. * - * @returns int + * @returns int the number of mouse clicks, required to start the session */ public int getClickCountToStart() { @@ -278,9 +435,9 @@ public class DefaultCellEditor } // getClickCountToStart() /** - * setClickCountToStart + * Set the number of mouse clicks, required to start the editing session. * - * @param count TODO + * @param count the number of clicks, required to start the session */ public void setClickCountToStart(int count) { @@ -288,9 +445,10 @@ public class DefaultCellEditor } // setClickCountToStart() /** - * getCellEditorValue + * Get the value, currently being displayed by the editor component. The + * call is forwarded to the {@link #delegate}. * - * @returns Object + * @returns Object the value (class depends on the editor component) */ public Object getCellEditorValue() { @@ -298,11 +456,11 @@ public class DefaultCellEditor } // getCellEditorValue() /** - * isCellEditable + * Forwards call to the {@link #delegate}. * - * @param event TODO + * @param event forwarded to the delegate. * - * @returns boolean + * @returns boolean returned by delegate */ public boolean isCellEditable(EventObject event) { @@ -310,11 +468,11 @@ public class DefaultCellEditor } // isCellEditable() /** - * shouldSelectCell + * Forwards call to the {@link #delegate}. * - * @param event TODO + * @param event forwarded to the delegate. * - * @returns boolean + * @returns boolean returned by delegate */ public boolean shouldSelectCell(EventObject event) { @@ -322,9 +480,9 @@ public class DefaultCellEditor } // shouldSelectCell() /** - * stopCellEditing + * Forwards call to the {@link #delegate}. * - * @returns boolean + * @returns boolean returned by delegate */ public boolean stopCellEditing() { @@ -332,7 +490,7 @@ public class DefaultCellEditor } // stopCellEditing() /** - * cancelCellEditing + * Forwards call to the {@link #delegate}. */ public void cancelCellEditing() { @@ -363,38 +521,23 @@ public class DefaultCellEditor boolean expanded, boolean leaf, int row) { - if (editorComponent instanceof JTextField) - { - ((JTextField)editorComponent).setText(value.toString()); - delegate = new EditorDelegate(); - ((JTextField)editorComponent).addActionListener(delegate); - } - else if (editorComponent instanceof JCheckBox) - { - ((JCheckBox)editorComponent).setText(value.toString()); - delegate = new EditorDelegate(); - ((JCheckBox)editorComponent).addActionListener(delegate); - } - else if (editorComponent instanceof JComboBox) - { - ((JComboBox)editorComponent).setSelectedItem(value.toString()); - delegate = new EditorDelegate(); - ((JComboBox)editorComponent).addActionListener(delegate); - } - + delegate.setValue(value); return editorComponent; } // getTreeCellEditorComponent() /** - * getTableCellEditorComponent + * Get the cell editor component that will perform the editing session. If + * returned once, the same component is also returned on the repetetive calls + * again (reused). * - * @param table TODO - * @param value TODO - * @param isSelected TODO - * @param row TODO - * @param column TODO - * - * @returns Component + * @param table the table where the editing is performed + * @param value the current value of the table. It is set as the initial + * component value. + * @param isSelected if true, the cell is currently selected + * @param row the row of the cell being edited + * @param column the column of the cell being edited + * + * @returns Component the component that will perform the editing session */ public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, @@ -402,24 +545,9 @@ public class DefaultCellEditor { // NOTE: as specified by Sun, we don't call new() everytime, we return // editorComponent on each call to getTableCellEditorComponent or - // getTreeCellEditorComponent. However, currently JTextFields have a - // problem with getting rid of old text, so without calling new() there - // are some strange results. If you edit more than one cell in the table - // text from previously edited cells may unexpectedly show up in the - // cell you are currently editing. This will be fixed automatically - // when JTextField is fixed. - if (editorComponent instanceof JTextField) - { - ((JTextField)editorComponent).setText(value.toString()); - delegate = new EditorDelegate(); - ((JTextField)editorComponent).addActionListener(delegate); - } - else - { - // TODO - } + // getTreeCellEditorComponent. + delegate.setValue(value); return editorComponent; } // getTableCellEditorComponent() - } diff --git a/javax/swing/DefaultListCellRenderer.java b/javax/swing/DefaultListCellRenderer.java index 9a8e07071..598627fac 100644 --- a/javax/swing/DefaultListCellRenderer.java +++ b/javax/swing/DefaultListCellRenderer.java @@ -93,7 +93,7 @@ public class DefaultListCellRenderer extends JLabel int index, boolean isSelected, boolean cellHasFocus) { - String s = value.toString(); + String s = value != null ? value.toString() : ""; setText(s); setOpaque(true); setHorizontalAlignment(LEFT); diff --git a/javax/swing/ImageIcon.java b/javax/swing/ImageIcon.java index b6ed949d8..9e6265830 100644 --- a/javax/swing/ImageIcon.java +++ b/javax/swing/ImageIcon.java @@ -205,13 +205,13 @@ public class ImageIcon private static final long serialVersionUID = 532615968316031794L; /** A dummy Component that is used in the MediaTracker. */ - protected static Component component = new Component() + protected static final Component component = new Component() { // No need to implement this. }; /** The MediaTracker used to monitor the loading of images. */ - protected static MediaTracker tracker = new MediaTracker(component); + protected static final MediaTracker tracker = new MediaTracker(component); /** The ID that is used in the tracker. */ private static int id; diff --git a/javax/swing/JApplet.java b/javax/swing/JApplet.java index e90c45189..68eb983dd 100644 --- a/javax/swing/JApplet.java +++ b/javax/swing/JApplet.java @@ -66,7 +66,7 @@ public class JApplet extends Applet /** * Creates a new instance of AccessibleJApplet. */ - public AccessibleJApplet() + protected AccessibleJApplet() { super(); // Nothing to do here. diff --git a/javax/swing/JCheckBox.java b/javax/swing/JCheckBox.java index 74fda8f6d..26f9f6ca5 100644 --- a/javax/swing/JCheckBox.java +++ b/javax/swing/JCheckBox.java @@ -67,7 +67,7 @@ public class JCheckBox extends JToggleButton implements Accessible /** * Creates a new instance of AccessibleJCheckBox. */ - public AccessibleJCheckBox() + protected AccessibleJCheckBox() { // Nothing to do here. } diff --git a/javax/swing/JComponent.java b/javax/swing/JComponent.java index b1ad855f2..7ba643090 100644 --- a/javax/swing/JComponent.java +++ b/javax/swing/JComponent.java @@ -1,5 +1,5 @@ /* JComponent.java -- Every component in swing inherits from this class. - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -64,10 +64,10 @@ import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; -import java.awt.geom.Rectangle2D; import java.awt.peer.LightweightPeer; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.io.Serializable; @@ -88,7 +88,6 @@ import javax.swing.border.TitledBorder; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import javax.swing.event.EventListenerList; -import javax.swing.event.SwingPropertyChangeSupport; import javax.swing.plaf.ComponentUI; /** @@ -165,11 +164,11 @@ public abstract class JComponent extends Container implements Serializable /** * Manages the property change listeners; */ - private SwingPropertyChangeSupport changeSupport; + private PropertyChangeSupport changeSupport; protected AccessibleJComponent() { - changeSupport = new SwingPropertyChangeSupport(this); + changeSupport = new PropertyChangeSupport(this); } /** @@ -527,14 +526,6 @@ public abstract class JComponent extends Container implements Serializable */ protected EventListenerList listenerList = new EventListenerList(); - /** - * Support for {@link PropertyChangeEvent} events. This is constructed - * lazily when the component gets its first {@link - * PropertyChangeListener} subscription; until then it's an empty slot. - */ - private SwingPropertyChangeSupport changeSupport; - - /** * Storage for "client properties", which are key/value pairs associated * with this component by a "client", such as a user application or a @@ -563,7 +554,7 @@ public abstract class JComponent extends Container implements Serializable * so that it doesn't get modified in another context within the same * method call chain. */ - private static transient Rectangle rectCache; + private transient Rectangle rectCache; /** * The default locale of the component. @@ -696,36 +687,6 @@ public abstract class JComponent extends Container implements Serializable listenerList.remove(AncestorListener.class, listener); } - /** - * Unregister a PropertyChangeListener. - * - * @param listener The listener to register - * - * @see #addPropertyChangeListener(PropertyChangeListener) - * @see #changeSupport - */ - public void removePropertyChangeListener(PropertyChangeListener listener) - { - if (changeSupport != null) - changeSupport.removePropertyChangeListener(listener); - } - - /** - * Unregister a PropertyChangeListener. - * - * @param propertyName The property name to unregister the listener from - * @param listener The listener to unregister - * - * @see #addPropertyChangeListener(String, PropertyChangeListener) - * @see #changeSupport - */ - public void removePropertyChangeListener(String propertyName, - PropertyChangeListener listener) - { - if (changeSupport != null) - changeSupport.removePropertyChangeListener(propertyName, listener); - } - /** * Unregister a VetoableChangeChangeListener. * @@ -750,24 +711,6 @@ public abstract class JComponent extends Container implements Serializable listenerList.add(AncestorListener.class, listener); } - /** - * Register a PropertyChangeListener. This listener will - * receive any PropertyChangeEvent, regardless of property name. To - * listen to a specific property name, use {@link - * #addPropertyChangeListener(String,PropertyChangeListener)} instead. - * - * @param listener The listener to register - * - * @see #removePropertyChangeListener(PropertyChangeListener) - * @see #changeSupport - */ - public void addPropertyChangeListener(PropertyChangeListener listener) - { - if (changeSupport == null) - changeSupport = new SwingPropertyChangeSupport(this); - changeSupport.addPropertyChangeListener(listener); - } - /** * Register a PropertyChangeListener for a specific, named * property. To listen to all property changes, regardless of name, use @@ -819,7 +762,10 @@ public abstract class JComponent extends Container implements Serializable */ public T[] getListeners(Class listenerType) { - return listenerList.getListeners(listenerType); + if (listenerType == PropertyChangeListener.class) + return (T[]) getPropertyChangeListeners(); + else + return listenerList.getListeners(listenerType); } /** @@ -844,135 +790,49 @@ public abstract class JComponent extends Container implements Serializable return (VetoableChangeListener[]) getListeners(VetoableChangeListener.class); } - /** - * Return all PropertyChangeListener objects registered to listen - * for a particular property. - * - * @param property The property to return the listeners of - * - * @return The set of PropertyChangeListener objects in - * {@link #changeSupport} registered to listen on the specified property - */ - public PropertyChangeListener[] getPropertyChangeListeners(String property) - { - return changeSupport == null ? new PropertyChangeListener[0] - : changeSupport.getPropertyChangeListeners(property); - } - /** * A variant of {@link #firePropertyChange(String,Object,Object)} * for properties with boolean values. + * + * @specnote It seems that in JDK1.5 all property related methods have been + * moved to java.awt.Component, except this and 2 others. We call + * super here. I guess this will also be removed in one of the next + * releases. */ public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, Boolean.valueOf(oldValue), - Boolean.valueOf(newValue)); - } - - /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with byte values. - */ - public void firePropertyChange(String propertyName, byte oldValue, - byte newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Byte(oldValue), - new Byte(newValue)); + super.firePropertyChange(propertyName, oldValue, newValue); } /** * A variant of {@link #firePropertyChange(String,Object,Object)} * for properties with char values. + * + * @specnote It seems that in JDK1.5 all property related methods have been + * moved to java.awt.Component, except this and 2 others. We call + * super here. I guess this will also be removed in one of the next + * releases. */ public void firePropertyChange(String propertyName, char oldValue, char newValue) { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Character(oldValue), - new Character(newValue)); - } - - /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with double values. - */ - public void firePropertyChange(String propertyName, double oldValue, - double newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Double(oldValue), - new Double(newValue)); - } - - /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with float values. - */ - public void firePropertyChange(String propertyName, float oldValue, - float newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Float(oldValue), - new Float(newValue)); + super.firePropertyChange(propertyName, oldValue, newValue); } /** * A variant of {@link #firePropertyChange(String,Object,Object)} * for properties with int values. + * + * @specnote It seems that in JDK1.5 all property related methods have been + * moved to java.awt.Component, except this and 2 others. We call + * super here. I guess this will also be removed in one of the next + * releases. */ public void firePropertyChange(String propertyName, int oldValue, int newValue) { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Integer(oldValue), - new Integer(newValue)); - } - - /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with long values. - */ - public void firePropertyChange(String propertyName, long oldValue, - long newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Long(oldValue), - new Long(newValue)); - } - - /** - * Call {@link PropertyChangeListener#propertyChange} on all listeners - * registered to listen to a given property. Any method which changes - * the specified property of this component should call this method. - * - * @param propertyName The property which changed - * @param oldValue The old value of the property - * @param newValue The new value of the property - * - * @see #changeSupport - * @see #addPropertyChangeListener(PropertyChangeListener) - * @see #removePropertyChangeListener(PropertyChangeListener) - */ - protected void firePropertyChange(String propertyName, Object oldValue, - Object newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, oldValue, newValue); - } - - /** - * A variant of {@link #firePropertyChange(String,Object,Object)} - * for properties with short values. - */ - public void firePropertyChange(String propertyName, short oldValue, - short newValue) - { - if (changeSupport != null) - changeSupport.firePropertyChange(propertyName, new Short(oldValue), - new Short(newValue)); + super.firePropertyChange(propertyName, oldValue, newValue); } /** @@ -1518,9 +1378,8 @@ public abstract class JComponent extends Container implements Serializable { ((JComponent) c).computeVisibleRect(rect); rect.translate(-getX(), -getY()); - Rectangle2D.intersect(rect, - new Rectangle(0, 0, getWidth(), getHeight()), - rect); + rect = SwingUtilities.computeIntersection(0, 0, getWidth(), + getHeight(), rect); } else rect.setRect(0, 0, getWidth(), getHeight()); @@ -1536,9 +1395,10 @@ public abstract class JComponent extends Container implements Serializable */ public Rectangle getVisibleRect() { - Rectangle r = new Rectangle(); - computeVisibleRect(r); - return r; + if (rectCache == null) + rectCache = new Rectangle(); + computeVisibleRect(rectCache); + return rectCache; } /** @@ -1691,7 +1551,10 @@ public abstract class JComponent extends Container implements Serializable // screen. if (!isPaintingDoubleBuffered && isDoubleBuffered() && rm.isDoubleBufferingEnabled()) - paintDoubleBuffered(g); + { + Rectangle clip = g.getClipBounds(); + paintDoubleBuffered(clip); + } else { if (g.getClip() == null) @@ -1755,11 +1618,10 @@ public abstract class JComponent extends Container implements Serializable // optimizedDrawingEnabled (== it tiles its children). if (! isOptimizedDrawingEnabled()) { - Rectangle clip = g.getClipBounds(); for (int i = 0; i < children.length; i++) { Rectangle childBounds = children[i].getBounds(); - if (children[i].isOpaque() + if (children[i].isOpaque() && children[i].isVisible() && SwingUtilities.isRectangleContainingRectangle(childBounds, g.getClipBounds())) { @@ -1892,33 +1754,29 @@ public abstract class JComponent extends Container implements Serializable void paintImmediately2(Rectangle r) { RepaintManager rm = RepaintManager.currentManager(this); - Graphics g = getGraphics(); - g.setClip(r.x, r.y, r.width, r.height); if (rm.isDoubleBufferingEnabled() && isDoubleBuffered()) - paintDoubleBuffered(g); + paintDoubleBuffered(r); else - paintSimple(g); - g.dispose(); + paintSimple(r); } /** * Performs double buffered repainting. - * - * @param g the graphics context to paint to */ - void paintDoubleBuffered(Graphics g) + private void paintDoubleBuffered(Rectangle r) { - - Rectangle r = g.getClipBounds(); - if (r == null) - r = new Rectangle(0, 0, getWidth(), getHeight()); RepaintManager rm = RepaintManager.currentManager(this); // Paint on the offscreen buffer. - Image buffer = rm.getOffscreenBuffer(this, getWidth(), getHeight()); + Component root = SwingUtilities.getRoot(this); + Image buffer = rm.getOffscreenBuffer(this, root.getWidth(), + root.getHeight()); + //Rectangle targetClip = SwingUtilities.convertRectangle(this, r, root); + Point translation = SwingUtilities.convertPoint(this, 0, 0, root); Graphics g2 = buffer.getGraphics(); - g2 = getComponentGraphics(g2); + g2.translate(translation.x, translation.y); g2.setClip(r.x, r.y, r.width, r.height); + g2 = getComponentGraphics(g2); isPaintingDoubleBuffered = true; try { @@ -1929,20 +1787,27 @@ public abstract class JComponent extends Container implements Serializable isPaintingDoubleBuffered = false; g2.dispose(); } - + // Paint the buffer contents on screen. - g.drawImage(buffer, 0, 0, this); + rm.commitBuffer(root, new Rectangle(translation.x + r.x, + translation.y + r.y, r.width, + r.height)); } /** * Performs normal painting without double buffering. * - * @param g the graphics context to use + * @param r the area that should be repainted */ - void paintSimple(Graphics g) + void paintSimple(Rectangle r) { + Graphics g = getGraphics(); Graphics g2 = getComponentGraphics(g); + g2.setClip(r); paint(g2); + g2.dispose(); + if (g != g2) + g.dispose(); } /** @@ -2339,12 +2204,12 @@ public abstract class JComponent extends Container implements Serializable */ public void repaint(long tm, int x, int y, int width, int height) { - Rectangle dirty = new Rectangle(x, y, width, height); - Rectangle vis = getVisibleRect(); - dirty = dirty.intersection(vis); - RepaintManager.currentManager(this).addDirtyRegion(this, dirty.x, dirty.y, - dirty.width, - dirty.height); + // TODO: Maybe add this visibleRect stuff to RepaintManager. + Rectangle r = getVisibleRect(); + Rectangle dirty = SwingUtilities.computeIntersection(x, y, width, height, r); + RepaintManager.currentManager(this).addDirtyRegion(this, dirty.x, dirty.y, + dirty.width, + dirty.height); } /** @@ -2356,8 +2221,7 @@ public abstract class JComponent extends Container implements Serializable */ public void repaint(Rectangle r) { - repaint((long) 0, (int) r.getX(), (int) r.getY(), (int) r.getWidth(), - (int) r.getHeight()); + repaint(0, r.x, r.y, r.width, r.height); } /** @@ -2879,7 +2743,7 @@ public abstract class JComponent extends Container implements Serializable * * @since 1.4 */ - public boolean requestFocusInWindow(boolean temporary) + protected boolean requestFocusInWindow(boolean temporary) { return super.requestFocusInWindow(temporary); } @@ -3045,19 +2909,6 @@ public abstract class JComponent extends Container implements Serializable return super.getWidth(); } - /** - * Return all PropertyChangeListener objects registered. - * - * @return The set of PropertyChangeListener objects - */ - public PropertyChangeListener[] getPropertyChangeListeners() - { - if (changeSupport == null) - return new PropertyChangeListener[0]; - else - return changeSupport.getPropertyChangeListeners(); - } - /** * Prints this component to the given Graphics context. A call to this * method results in calls to the methods {@link #printComponent}, @@ -3098,7 +2949,7 @@ public abstract class JComponent extends Container implements Serializable * * @since 1.3 */ - public void printComponent(Graphics g) + protected void printComponent(Graphics g) { paintComponent(g); } @@ -3112,7 +2963,7 @@ public abstract class JComponent extends Container implements Serializable * * @since 1.3 */ - public void printChildren(Graphics g) + protected void printChildren(Graphics g) { paintChildren(g); } @@ -3126,7 +2977,7 @@ public abstract class JComponent extends Container implements Serializable * * @since 1.3 */ - public void printBorder(Graphics g) + protected void printBorder(Graphics g) { paintBorder(g); } @@ -3245,62 +3096,25 @@ public abstract class JComponent extends Container implements Serializable while (parent != null && !(parent instanceof Window)) { Container newParent = parent.getParent(); - if (newParent == null) + if (newParent == null || newParent instanceof Window) break; // If the parent is optimizedDrawingEnabled, then its children are // tiled and cannot have an overlapping child. Go directly to next // parent. - if (newParent instanceof JComponent - && ((JComponent) newParent).isOptimizedDrawingEnabled()) + if ((newParent instanceof JComponent + && ((JComponent) newParent).isOptimizedDrawingEnabled())) + { parent = newParent; continue; } - - // First we must check if the new parent itself somehow clips the - // target rectangle. This can happen in JViewports. - Rectangle parRect = new Rectangle(0, 0, newParent.getWidth(), - newParent.getHeight()); + // If the parent is not optimizedDrawingEnabled, we must paint the + // parent. Rectangle target = SwingUtilities.convertRectangle(found, currentClip, newParent); - if (! target.intersection(parRect).equals(target)) - { - found = newParent; - currentClip = target; - parent = newParent; - continue; - } - - // Otherwise we must check if one of the children of this parent - // overlaps with the current component. - Component[] children = newParent.getComponents(); - // This flag is used to skip components that are 'below' the component - // in question. - boolean skip = true; - for (int i = children.length - 1; i >= 0; i--) - { - boolean nextSkip = skip; - if (children[i] == parent) - nextSkip = false; - if (skip) - continue; - skip = nextSkip; - Component c = children[i]; - Rectangle compBounds = c.getBounds(); - // If the component completely overlaps the clip in question, we - // don't need to repaint. Return null. - if (compBounds.contains(target)) - return null; - if (compBounds.intersects(target)) - { - // We found a parent whose children overlap with our current - // component. Make this the current component. - found = newParent; - currentClip = target; - break; - } - } + found = newParent; + currentClip = target; parent = newParent; } return found; diff --git a/javax/swing/JDialog.java b/javax/swing/JDialog.java index b3f7c011f..08dada2fd 100644 --- a/javax/swing/JDialog.java +++ b/javax/swing/JDialog.java @@ -74,7 +74,7 @@ public class JDialog extends Dialog implements Accessible, WindowConstants, /** * Creates a new instance of AccessibleJDialog. */ - public AccessibleJDialog() + protected AccessibleJDialog() { super(); // Nothing to do here. @@ -107,7 +107,7 @@ public class JDialog extends Dialog implements Accessible, WindowConstants, */ public JDialog() { - this(SwingUtilities.getOwnerFrame(), "", false, null); + this((Frame) SwingUtilities.getOwnerFrame(null), "", false, null); } /** @@ -234,8 +234,7 @@ public class JDialog extends Dialog implements Accessible, WindowConstants, public JDialog(Frame owner, String title, boolean modal, GraphicsConfiguration gc) { - super((owner == null) ? SwingUtilities.getOwnerFrame() : owner, - title, modal, gc); + super((Frame) SwingUtilities.getOwnerFrame(owner), title, modal, gc); dialogInit(); } diff --git a/javax/swing/JEditorPane.java b/javax/swing/JEditorPane.java index 3560ffd57..9264c8dd8 100644 --- a/javax/swing/JEditorPane.java +++ b/javax/swing/JEditorPane.java @@ -38,6 +38,7 @@ exception statement from your version. */ package javax.swing; +import java.awt.Container; import java.awt.Dimension; import java.io.IOException; import java.io.InputStream; @@ -682,27 +683,59 @@ public class JEditorPane extends JTextComponent } /** - * Returns the preferred size for the JEditorPane. + * Returns the preferred size for the JEditorPane. This is implemented to + * return the super's preferred size, unless one of + * {@link #getScrollableTracksViewportHeight()} or + * {@link #getScrollableTracksViewportWidth()} returns true, + * in which case the preferred width and/or height is replaced by the UI's + * minimum size. + * + * @return the preferred size for the JEditorPane */ public Dimension getPreferredSize() { - return super.getPreferredSize(); + Dimension pref = super.getPreferredSize(); + if (getScrollableTracksViewportWidth()) + pref.width = getUI().getMinimumSize(this).width; + if (getScrollableTracksViewportHeight()) + pref.height = getUI().getMinimumSize(this).height; + return pref; } + /** + * Returns true when a Viewport should force the height of + * this component to match the viewport height. This is implemented to return + * true when the parent is an instance of JViewport and + * the viewport height > the UI's minimum height. + * + * @return true when a Viewport should force the height of + * this component to match the viewport height + */ public boolean getScrollableTracksViewportHeight() { - /* Container parent = getParent(); - return (parent instanceof JViewport && - parent.isValid());*/ - return isValid(); + // Tests show that this returns true when the parent is a JViewport + // and has a height > minimum UI height. + Container parent = getParent(); + return parent instanceof JViewport + && parent.getHeight() > getUI().getMinimumSize(this).height; } + /** + * Returns true when a Viewport should force the width of + * this component to match the viewport width. This is implemented to return + * true when the parent is an instance of JViewport and + * the viewport width > the UI's minimum width. + * + * @return true when a Viewport should force the width of + * this component to match the viewport width + */ public boolean getScrollableTracksViewportWidth() { - /*Container parent = getParent(); - return (parent instanceof JViewport && - parent.isValid());*/ - return isValid(); + // Tests show that this returns true when the parent is a JViewport + // and has a width > minimum UI width. + Container parent = getParent(); + return parent != null && parent instanceof JViewport + && parent.getWidth() > getUI().getMinimumSize(this).width; } public URL getPage() diff --git a/javax/swing/JFileChooser.java b/javax/swing/JFileChooser.java index 3a9d6a01f..72bd2bb28 100644 --- a/javax/swing/JFileChooser.java +++ b/javax/swing/JFileChooser.java @@ -40,7 +40,6 @@ package javax.swing; import java.awt.Component; import java.awt.Frame; import java.awt.HeadlessException; -import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; @@ -658,8 +657,7 @@ public class JFileChooser extends JComponent implements Accessible retval = ERROR_OPTION; - Insets i = d.getInsets(); - d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height); + d.pack(); d.show(); return retval; } @@ -683,8 +681,7 @@ public class JFileChooser extends JComponent implements Accessible retval = ERROR_OPTION; - Insets i = d.getInsets(); - d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height); + d.pack(); d.show(); return retval; } @@ -710,8 +707,7 @@ public class JFileChooser extends JComponent implements Accessible retval = ERROR_OPTION; - Insets i = d.getInsets(); - d.setSize(500 + i.top + i.bottom, d.getPreferredSize().height); + d.pack(); d.show(); return retval; } @@ -729,7 +725,7 @@ public class JFileChooser extends JComponent implements Accessible { Frame toUse = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, parent); if (toUse == null) - toUse = SwingUtilities.getOwnerFrame(); + toUse = (Frame) SwingUtilities.getOwnerFrame(null); JDialog dialog = new JDialog(toUse); setSelectedFile(null); diff --git a/javax/swing/JFrame.java b/javax/swing/JFrame.java index 8d4dcb53b..d25120560 100644 --- a/javax/swing/JFrame.java +++ b/javax/swing/JFrame.java @@ -76,7 +76,7 @@ public class JFrame extends Frame /** * Creates a new instance of AccessibleJFrame. */ - public AccessibleJFrame() + protected AccessibleJFrame() { super(); // Nothing to do here. @@ -150,6 +150,15 @@ public class JFrame extends Frame super.setLayout(new BorderLayout(1, 1)); enableEvents(AWTEvent.WINDOW_EVENT_MASK); getRootPane(); // will do set/create + + // Setup the defaultLookAndFeelDecoration if requested. + if (isDefaultLookAndFeelDecorated() + && UIManager.getLookAndFeel().getSupportsWindowDecorations()) + { + setUndecorated(true); + getRootPane().setWindowDecorationStyle(JRootPane.FRAME); + } + // We're now done the init stage. setRootPaneCheckingEnabled(true); } diff --git a/javax/swing/JInternalFrame.java b/javax/swing/JInternalFrame.java index 948988c24..1e4fad767 100644 --- a/javax/swing/JInternalFrame.java +++ b/javax/swing/JInternalFrame.java @@ -616,7 +616,7 @@ public class JInternalFrame extends JComponent implements Accessible, */ public void dispose() { - hide(); + setVisible(false); JDesktopPane pane = getDesktopPane(); if (pane != null) pane.setSelectedFrame(null); @@ -647,11 +647,11 @@ public class JInternalFrame extends JComponent implements Accessible, switch (getDefaultCloseOperation()) { case HIDE_ON_CLOSE: - hide(); - break; + setVisible(false); + break; case DISPOSE_ON_CLOSE: - dispose(); - break; + dispose(); + break; } } @@ -1257,13 +1257,14 @@ public class JInternalFrame extends JComponent implements Accessible, { if (b && ! isClosed()) { - fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING); - fireVetoableChange(IS_CLOSED_PROPERTY, false, true); + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING); + fireVetoableChange(IS_CLOSED_PROPERTY, false, true); - isClosed = b; + isClosed = b; + dispose(); - firePropertyChange(IS_CLOSED_PROPERTY, false, true); - fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED); + firePropertyChange(IS_CLOSED_PROPERTY, false, true); + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED); } } diff --git a/javax/swing/JLayeredPane.java b/javax/swing/JLayeredPane.java index b087637b1..84cd8322f 100644 --- a/javax/swing/JLayeredPane.java +++ b/javax/swing/JLayeredPane.java @@ -43,11 +43,7 @@ import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.awt.Rectangle; -import java.awt.Shape; import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; -import java.util.TreeMap; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; @@ -119,6 +115,7 @@ import javax.accessibility.AccessibleRole; * component indexing and position order

      * * @author Graydon Hoare (graydon@redhat.com) + * @author Roman Kennke (kennke@aicas.com) */ public class JLayeredPane extends JComponent implements Accessible { @@ -131,7 +128,7 @@ public class JLayeredPane extends JComponent implements Accessible /** * Creates a new instance of AccessibleJLayeredPane. */ - public AccessibleJLayeredPane() + protected AccessibleJLayeredPane() { // Nothing to do here. } @@ -150,22 +147,18 @@ public class JLayeredPane extends JComponent implements Accessible public static final String LAYER_PROPERTY = "layeredContainerLayer"; - public static Integer FRAME_CONTENT_LAYER = new Integer (-30000); + public static final Integer FRAME_CONTENT_LAYER = new Integer (-30000); - public static Integer DEFAULT_LAYER = new Integer (0); - public static Integer PALETTE_LAYER = new Integer (100); - public static Integer MODAL_LAYER = new Integer (200); - public static Integer POPUP_LAYER = new Integer (300); - public static Integer DRAG_LAYER = new Integer (400); + public static final Integer DEFAULT_LAYER = new Integer (0); + public static final Integer PALETTE_LAYER = new Integer (100); + public static final Integer MODAL_LAYER = new Integer (200); + public static final Integer POPUP_LAYER = new Integer (300); + public static final Integer DRAG_LAYER = new Integer (400); - TreeMap layers; // Layer Number (Integer) -> Layer Size (Integer) - Hashtable componentToLayer; // Component -> Layer Number (Integer) + private Hashtable componentToLayer; // Component -> Layer Number (Integer) - private transient Rectangle rectCache; - public JLayeredPane() { - layers = new TreeMap (); componentToLayer = new Hashtable (); setLayout(null); } @@ -173,47 +166,50 @@ public class JLayeredPane extends JComponent implements Accessible /** * Looks up the layer a child component is currently assigned to. * + * If c is an instance of {@link JComponent}, then the layer + * is fetched from the client property with the key {@link #LAYER_PROPERTY}. + * Otherwise it is looked up in an internal hashtable that maps + * non-JComponent components to layers. If the components cannot be found + * in either way, the {@link #DEFAULT_LAYER} is returned. + * * @param c the component to look up. - * @return the layer the component is currently assigned to, in this container. - * @throws IllegalArgumentException if the component is not a child of this container. + * + * @return the layer the component is currently assigned to; if the component + * is not in this layered pane, then 0 (DEFAULT_LAYER) is returned */ public int getLayer(Component c) { - Component myComp = c; - while(! componentToLayer.containsKey(myComp)) + Integer layerObj; + if (c instanceof JComponent) { - myComp = myComp.getParent(); - if (myComp == null) - break; + JComponent jc = (JComponent) c; + layerObj = (Integer) jc.getClientProperty(LAYER_PROPERTY); } - if (myComp == null) - throw new IllegalArgumentException - ("component is not in this JLayeredPane"); - Integer layerObj = (Integer) componentToLayer.get(myComp); + else + layerObj = (Integer) componentToLayer.get(c); + + if (layerObj == null) + layerObj = DEFAULT_LAYER; + return layerObj.intValue(); } /** - * Looks up the layer of comp in the component's nearest - * JLayeredPane ancestor. If comp is not contained - * in a JLayeredPane, the value 0 (default layer) is returned. - * + * Looks up the layer in the client property with the key + * {@link #LAYER_PROPERTY} of comp. If no such property can be + * found, we return 0 ({@link #DEFAULT_LAYER}). + * * @param comp the component for which the layer is looked up * - * @return the layer of comp in its nearest JLayeredPane - * ancestor + * @return the layer of comp as stored in the corresponding + * client property, or 0 if there is no such property */ public static int getLayer(JComponent comp) { - JLayeredPane lp = (JLayeredPane) SwingUtilities.getAncestorOfClass - (JLayeredPane.class, comp); - if (lp == null) - return 0; - else - // The cast here forces the call to the instance method getLayer() - // instead of the static method (this would lead to infinite - // recursion). - return lp.getLayer((Component) comp); + Integer layerObj = (Integer) comp.getClientProperty(LAYER_PROPERTY); + if (layerObj == null) + layerObj = DEFAULT_LAYER; + return layerObj.intValue(); } /** @@ -235,106 +231,50 @@ public class JLayeredPane extends JComponent implements Accessible return lp; } - /** - *

      Returns a pair of ints representing a half-open interval - * [top, bottom), which is the range of component indices - * the provided layer number corresponds to.

      - * - *

      Note that "bottom" is not included in the interval of - * component indices in this layer: a layer with 0 elements in it has - * ret[0] == ret[1].

      - * - * @param layer the layer to look up. - * @return the half-open range of indices this layer spans. - * @throws IllegalArgumentException if layer does not refer to an active layer - * in this container. - */ - private int[] layerToRange (Integer layer) - { - int[] ret = new int[2]; - ret[1] = getComponents ().length; - Iterator i = layers.entrySet ().iterator (); - while (i.hasNext()) - { - Map.Entry pair = (Map.Entry) i.next(); - Integer layerNum = (Integer) pair.getKey (); - Integer layerSz = (Integer) pair.getValue (); - int layerInt = layerNum.intValue(); - if (layerInt == layer.intValue()) - { - ret[0] = ret[1] - layerSz.intValue (); - break; - } - // In the following case there exists no layer with the specified - // number, so we return an empty interval here with the index at which - // such a layer would be inserted - else if (layerInt > layer.intValue()) - { - ret[1] = ret[0]; - break; - } - else - { - ret[1] -= layerSz.intValue (); - } - } - return ret; - } - - /** - * Increments the recorded size of a given layer. - * - * @param layer the layer number to increment. - * @see #incrLayer - */ - private void incrLayer(Integer layer) - { - int sz = 1; - if (layers.containsKey (layer)) - sz += ((Integer)(layers.get (layer))).intValue (); - layers.put (layer, new Integer(sz)); - } - - /** - * Decrements the recorded size of a given layer. - * - * @param layer the layer number to decrement. - * @see #incrLayer - */ - private void decrLayer(Integer layer) - { - int sz = 0; - if (layers.containsKey (layer)) - sz = ((Integer)(layers.get (layer))).intValue () - 1; - layers.put (layer, new Integer(sz)); - } - /** * Return the greatest layer number currently in use, in this container. * This number may legally be positive or negative. * - * @return the least layer number. + * @return the highest layer number + * * @see #lowestLayer() */ public int highestLayer() { - if (layers.size() == 0) - return 0; - return ((Integer)(layers.lastKey ())).intValue (); + Component[] components = getComponents(); + int highest; + if (components.length == 0) + highest = 0; + else + { + highest = Integer.MIN_VALUE; + for (int i = 0; i < components.length; i++) + highest = Math.max(highest, getLayer(components[i])); + } + return highest; } /** * Return the least layer number currently in use, in this container. * This number may legally be positive or negative. * - * @return the least layer number. + * @return the least layer number + * * @see #highestLayer() */ public int lowestLayer() { - if (layers.size() == 0) - return 0; - return ((Integer)(layers.firstKey ())).intValue (); + Component[] components = getComponents(); + int lowest; + if (components.length == 0) + lowest = 0; + else + { + lowest = Integer.MAX_VALUE; + for (int i = 0; i < components.length; i++) + lowest = Math.max(lowest, getLayer(components[i])); + } + return lowest; } /** @@ -343,9 +283,8 @@ public class JLayeredPane extends JComponent implements Accessible * layer, so is usually the component which occludes the most other * components in its layer. * - * @param c the component to move to the front of its layer. - * @throws IllegalArgumentException if the component is not a child of - * this container. + * @param c the component to move to the front of its layer + * * @see #moveToBack */ public void moveToFront(Component c) @@ -363,8 +302,7 @@ public class JLayeredPane extends JComponent implements Accessible * other components in its layer.

      * * @param c the component to move to the back of its layer. - * @throws IllegalArgumentException if the component is not a child of - * this container. + * * @see #moveToFront */ public void moveToBack(Component c) @@ -377,25 +315,30 @@ public class JLayeredPane extends JComponent implements Accessible * from the "front" (position 0) to the "back" (position N-1), and drawn from * the back towards the front. * - * @param c the component to get the position of. - * @throws IllegalArgumentException if the component is not a child of - * this container. + * @param c the component to get the position of + * + * @return the position of c within its layer or -1 if + * c is not a child of this layered pane + * * @see #setPosition */ public int getPosition(Component c) { - int layer = getLayer (c); - int[] range = layerToRange(new Integer(layer)); - int top = range[0]; - int bot = range[1]; - Component[] comps = getComponents (); - for (int i = top; i < bot; ++i) - { - if (comps[i] == c) - return i - top; - } - // should have found it - throw new IllegalArgumentException (); + int pos = -1; + int index = getIndexOf(c); + Component[] components = getComponents(); + int layer = getLayer(c); + if (index >= 0) + { + for (int i = index; i >= 0; --i) + { + if (layer == getLayer(components[i])) + pos++; + else + break; + } + } + return pos; } /** @@ -403,47 +346,16 @@ public class JLayeredPane extends JComponent implements Accessible * from the "front" (position 0) to the "back" (position N-1), and drawn from * the back towards the front. * - * @param c the component to change the position of. - * @param position the position to assign the component to. - * @throws IllegalArgumentException if the component is not a child of - * this container. + * @param c the component to change the position of + * @param position the position to assign the component to + * * @see #getPosition */ public void setPosition(Component c, int position) { - int layer = getLayer (c); - int[] range = layerToRange(new Integer(layer)); - if (range[0] == range[1]) - throw new IllegalArgumentException (); - - int top = range[0]; - int bot = range[1]; - if (position == -1) - position = (bot - top) - 1; - int targ = Math.min(top + position, bot-1); - int curr = -1; - - Component[] comps = getComponents(); - for (int i = top; i < bot; ++i) - { - if (comps[i] == c) - { - curr = i; - break; - } - } - if (curr == -1) - // should have found it - throw new IllegalArgumentException(); - - if (curr == 0) - super.swapComponents(curr, targ); - else - while (curr > 0) - super.swapComponents (curr, --curr); - - revalidate(); - repaint(); + int layer = getLayer(c); + int index = insertIndexForLayer(layer, position); + setComponentZOrder(c, index); } /** @@ -451,39 +363,44 @@ public class JLayeredPane extends JComponent implements Accessible * container. Components are ordered front-to-back, with the "front" * element (which draws last) at position 0 of the returned array. * - * @param layer the layer to return components from. - * @return the components in the layer. + * @param layer the layer to return components from + * + * @return the components in the layer */ public Component[] getComponentsInLayer(int layer) { - int[] range = layerToRange (getObjectForLayer (layer)); - if (range[0] == range[1]) - return new Component[0]; - else - { - Component[] comps = getComponents (); - int sz = range[1] - range[0]; - Component[] nc = new Component[sz]; - for (int i = 0; i < sz; ++i) - nc[i] = comps[range[0] + i]; - return nc; - } + Component[] inLayer = new Component[getComponentCountInLayer(layer)]; + Component[] components = getComponents(); + int j = 0; + for (int i = 0; i < components.length; ++i) + { + if (layer == getLayer(components[i])) + { + inLayer[j] = components[i]; + j++; + } + } + return inLayer; } /** * Return the number of components within a layer of this * container. * - * @param layer the layer count components in. - * @return the number of components in the layer. + * @param layer the layer count components in + * + * @return the number of components in the layer */ public int getComponentCountInLayer(int layer) { - int[] range = layerToRange (getObjectForLayer (layer)); - if (range[0] == range[1]) - return 0; - else - return (range[1] - range[0]); + Component[] components = getComponents(); + int count = 0; + for (int i = components.length - 1; i >= 0; --i) + { + if (getLayer(components[i]) == layer) + count++; + } + return count; } /** @@ -502,23 +419,14 @@ public class JLayeredPane extends JComponent implements Accessible * drawing order of all children of the container. * * @param c the component to look up. - * @return the external index of the component. - * @throws IllegalArgumentException if the component is not a child of - * this container. + * + * @return the external index of the component or -1 if + * c is not a child of this layered pane */ public int getIndexOf(Component c) { - int layer = getLayer (c); - int[] range = layerToRange(new Integer(layer)); - Component[] comps = getComponents(); - for (int i = range[0]; i < range[1]; ++i) - { - if (comps[i] == c) - return i; - } - // should have found the component during iteration - throw new IllegalArgumentException (); - } + return getComponentZOrder(c); + } /** * Return an Integer object which holds the same int value as the @@ -526,6 +434,7 @@ public class JLayeredPane extends JComponent implements Accessible * identical Integer objects which we allocate. * * @param layer the layer number as an int. + * * @return the layer number as an Integer, possibly shared. */ protected Integer getObjectForLayer(int layer) @@ -564,25 +473,39 @@ public class JLayeredPane extends JComponent implements Accessible * * @param layer the layer in which to insert a component. * @param position the position in the layer at which to insert a component. + * * @return the index at which to insert the component. */ protected int insertIndexForLayer(int layer, int position) { + // position < 0 means insert at greatest position within layer. + if (position < 0) + position = Integer.MAX_VALUE; - Integer lobj = getObjectForLayer (layer); - if (! layers.containsKey(lobj)) - layers.put (lobj, new Integer (0)); - int[] range = layerToRange (lobj); - if (range[0] == range[1]) - return range[0]; - - int top = range[0]; - int bot = range[1]; - - if (position == -1 || position > (bot - top)) - return bot; - else - return top + position; + Component[] components = getComponents(); + int index = 0; + + // Try to find the start index of the specified layer. + int p = -1; + for (int i = 0; i < components.length; i++) + { + int l = getLayer(components[i]); + if (l > layer) + index++; + // If we are in the layer we look for, try to find the position. + else if (l == layer) + { + p++; + if (p < position) + index++; + else + break; + } + // No need to look further if the layer at i is smaller than layer. + else + break; + } + return index; } /** @@ -594,12 +517,20 @@ public class JLayeredPane extends JComponent implements Accessible public void remove(int index) { Component c = getComponent(index); - int layer = getLayer(c); - decrLayer(new Integer(layer)); - componentToLayer.remove(c); + if (! (c instanceof JComponent)) + componentToLayer.remove(c); super.remove(index); - // FIXME: Figure out if this call is correct. - revalidate(); + } + + /** + * Removes all components from this container. + * + * @since 1.5 + */ + public void removeAll() + { + componentToLayer.clear(); + super.removeAll(); } /** @@ -615,7 +546,7 @@ public class JLayeredPane extends JComponent implements Accessible */ public void setLayer(Component c, int layer) { - componentToLayer.put (c, getObjectForLayer (layer)); + setLayer(c, layer, -1); } /** @@ -625,15 +556,20 @@ public class JLayeredPane extends JComponent implements Accessible * @param layer the layer number to assign to the component. * @param position the position number to assign to the component. */ - public void setLayer(Component c, - int layer, - int position) + public void setLayer(Component c, int layer, int position) { - remove(c); - add(c, getObjectForLayer (layer)); - setPosition(c, position); - revalidate(); - repaint(); + Integer layerObj = getObjectForLayer(layer); + if (c instanceof JComponent) + { + JComponent jc = (JComponent) c; + jc.putClientProperty(LAYER_PROPERTY, layerObj); + } + else + componentToLayer.put (c, layerObj); + + // Set position only of component is already added to this layered pane. + if (getIndexOf(c) != -1) + setPosition(c, position); } /** @@ -642,26 +578,27 @@ public class JLayeredPane extends JComponent implements Accessible * Integer}, specifying the layer to which the component will be added * (at the bottom position). * - * @param comp the component to add. - * @param layerConstraint an integer specifying the layer to add the component to. - * @param index an ignored parameter, for compatibility. + * The argument index specifies the position within the layer + * at which the component should be added, where 0 is the top + * position greater values specify positions below that and -1 + * specifies the bottom position. + * + * @param comp the component to add + * @param layerConstraint an integer specifying the layer to add the + * component to + * @param index the position within the layer */ protected void addImpl(Component comp, Object layerConstraint, int index) { - Integer layer; + int layer; if (layerConstraint != null && layerConstraint instanceof Integer) - layer = (Integer) layerConstraint; - else if (componentToLayer.containsKey (comp)) - layer = (Integer) componentToLayer.remove (comp); + layer = ((Integer) layerConstraint).intValue(); else - layer = DEFAULT_LAYER; - - int newIdx = insertIndexForLayer(layer.intValue (), index); + layer = getLayer(comp); - componentToLayer.put (comp, layer); - incrLayer (layer); - - super.addImpl(comp, null, newIdx); + int newIdx = insertIndexForLayer(layer, index); + setLayer(comp, layer); + super.addImpl(comp, layerConstraint, newIdx); } /** @@ -672,7 +609,7 @@ public class JLayeredPane extends JComponent implements Accessible */ public static void putLayer(JComponent component, int layer) { - getLayeredPaneAbove(component).setLayer(component, layer); + component.putClientProperty(LAYER_PROPERTY, new Integer(layer)); } /** @@ -711,13 +648,42 @@ public class JLayeredPane extends JComponent implements Accessible } /** - * Overridden to return false, since JLayeredPane - * cannot guarantee that its children don't overlap. + * Returns false if components in this layered pane can overlap, + * otherwise true. * - * @return false + * @return false if components in this layered pane can overlap, + * otherwise true */ public boolean isOptimizedDrawingEnabled() { - return false; + int numChildren = getComponentCount(); + boolean result = true; + for (int i = 0; i < numChildren; ++i) + { + Component c1 = getComponent(i); + if (! c1.isVisible()) + continue; + Rectangle r1 = c1.getBounds(); + if (r1.isEmpty()) + continue; + + for (int j = i + 1; j < numChildren; ++j) + { + Component c2 = getComponent(j); + if (! c2.isVisible()) + continue; + Rectangle r2 = c2.getBounds(); + if (r2.isEmpty()) + continue; + if (r1.intersects(r2)) + { + result = false; + break; + } + if (result == false) + break; + } + } + return result; } } diff --git a/javax/swing/JMenu.java b/javax/swing/JMenu.java index 369c44d40..a160dd448 100644 --- a/javax/swing/JMenu.java +++ b/javax/swing/JMenu.java @@ -906,7 +906,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement /** * This class listens to PropertyChangeEvents occuring in menu's action */ - protected class ActionChangedListener implements PropertyChangeListener + private class ActionChangedListener implements PropertyChangeListener { /** menu item associated with the action */ private JMenuItem menuItem; diff --git a/javax/swing/JMenuBar.java b/javax/swing/JMenuBar.java index f018daabf..60726fb39 100644 --- a/javax/swing/JMenuBar.java +++ b/javax/swing/JMenuBar.java @@ -1,5 +1,5 @@ /* JMenuBar.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -51,6 +51,8 @@ import javax.accessibility.AccessibleSelection; import javax.accessibility.AccessibleStateSet; import javax.swing.plaf.MenuBarUI; +import javax.swing.border.Border; + /** * JMenuBar is a container for menu's. For a menu bar to be seen on the * screen, at least one menu should be added to it. Just like adding @@ -437,8 +439,12 @@ public class JMenuBar extends JComponent implements Accessible, MenuElement protected void paintBorder(Graphics g) { if (borderPainted) - getBorder().paintBorder(this, g, 0, 0, getSize(null).width, - getSize(null).height); + { + Border border = getBorder(); + if (border != null) + getBorder().paintBorder(this, g, 0, 0, getSize(null).width, + getSize(null).height); + } } /** diff --git a/javax/swing/JOptionPane.java b/javax/swing/JOptionPane.java index 057326cd2..705eca832 100644 --- a/javax/swing/JOptionPane.java +++ b/javax/swing/JOptionPane.java @@ -197,7 +197,7 @@ public class JOptionPane extends JComponent implements Accessible public static final String WANTS_INPUT_PROPERTY = "wantsInput"; /** The value returned when the inputValue is uninitialized. */ - public static Object UNINITIALIZED_VALUE = "uninitializedValue"; + public static final Object UNINITIALIZED_VALUE = "uninitializedValue"; /** The icon displayed in the dialog/internal frame. */ protected Icon icon; @@ -236,7 +236,7 @@ public class JOptionPane extends JComponent implements Accessible protected boolean wantsInput; /** The common frame used when no parent is provided. */ - private static Frame privFrame = SwingUtilities.getOwnerFrame(); + private static Frame privFrame = (Frame) SwingUtilities.getOwnerFrame(null); /** * Creates a new JOptionPane object using a message of "JOptionPane diff --git a/javax/swing/JPanel.java b/javax/swing/JPanel.java index c02a9cfad..815e452dc 100644 --- a/javax/swing/JPanel.java +++ b/javax/swing/JPanel.java @@ -63,7 +63,7 @@ public class JPanel extends JComponent implements Accessible /** * Creates a new instance of AccessibleJPanel. */ - public AccessibleJPanel() + protected AccessibleJPanel() { // Nothing to do here. } diff --git a/javax/swing/JPopupMenu.java b/javax/swing/JPopupMenu.java index 1f2282e23..74f733e92 100644 --- a/javax/swing/JPopupMenu.java +++ b/javax/swing/JPopupMenu.java @@ -866,7 +866,7 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement /* This class resizes popup menu and repaints popup menu appropriately if one of item's action has changed */ - protected class ActionChangeListener implements PropertyChangeListener + private class ActionChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { diff --git a/javax/swing/JProgressBar.java b/javax/swing/JProgressBar.java index abca3e7ae..e7ee8004c 100644 --- a/javax/swing/JProgressBar.java +++ b/javax/swing/JProgressBar.java @@ -1,5 +1,5 @@ /* JProgressBar.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -174,8 +174,8 @@ public class JProgressBar extends JComponent implements SwingConstants, /** Whether the ProgressBar is determinate. */ private transient boolean indeterminate = false; - /** The orientation of the ProgressBar */ - protected int orientation = HORIZONTAL; + /** The orientation of the ProgressBar. Always set by constructor. */ + protected int orientation; /** Whether borders should be painted. */ protected boolean paintBorder = true; @@ -245,8 +245,9 @@ public class JProgressBar extends JComponent implements SwingConstants, { model = new DefaultBoundedRangeModel(minimum, 0, minimum, maximum); if (orientation != HORIZONTAL && orientation != VERTICAL) - throw new IllegalArgumentException(orientation + " is not a legal orientation"); - setOrientation(orientation); + throw new IllegalArgumentException(orientation + + " is not a legal orientation"); + this.orientation = orientation; changeListener = createChangeListener(); model.addChangeListener(changeListener); updateUI(); @@ -316,11 +317,14 @@ public class JProgressBar extends JComponent implements SwingConstants, * JProgressBar can be either horizontal or vertical. * * @param orientation The orientation of the JProgressBar. + * @throws IllegalArgumentException if orientation is not + * either {@link #HORIZONTAL} or {@link #VERTICAL}. */ public void setOrientation(int orientation) { if (orientation != VERTICAL && orientation != HORIZONTAL) - throw new IllegalArgumentException("orientation must be one of VERTICAL or HORIZONTAL"); + throw new IllegalArgumentException(orientation + + " is not a legal orientation"); if (this.orientation != orientation) { int oldOrientation = this.orientation; diff --git a/javax/swing/JRootPane.java b/javax/swing/JRootPane.java index dea4ee4b1..dec43956c 100644 --- a/javax/swing/JRootPane.java +++ b/javax/swing/JRootPane.java @@ -119,11 +119,6 @@ public class JRootPane extends JComponent implements Accessible */ private Rectangle menuBarBounds; - /** - * The cached preferred size. - */ - private Dimension prefSize; - /** * Creates a new RootLayout object. */ @@ -191,7 +186,6 @@ public class JRootPane extends JComponent implements Accessible layeredPaneBounds = null; contentPaneBounds = null; menuBarBounds = null; - prefSize = null; } } @@ -251,7 +245,7 @@ public class JRootPane extends JComponent implements Accessible layeredPane.setBounds(layeredPaneBounds); if (menuBar != null) menuBar.setBounds(menuBarBounds); - contentPane.setBounds(contentPaneBounds); + getContentPane().setBounds(contentPaneBounds); } /** @@ -287,29 +281,20 @@ public class JRootPane extends JComponent implements Accessible */ public Dimension preferredLayoutSize(Container c) { - // We must synchronize here, otherwise we cannot guarantee that the - // prefSize is still non-null when returning. - synchronized (this) + Dimension prefSize = new Dimension(); + Insets i = getInsets(); + prefSize = new Dimension(i.left + i.right, i.top + i.bottom); + Dimension contentPrefSize = getContentPane().getPreferredSize(); + prefSize.width += contentPrefSize.width; + prefSize.height += contentPrefSize.height; + if (menuBar != null) { - if (prefSize == null) - { - Insets i = getInsets(); - prefSize = new Dimension(i.left + i.right, i.top + i.bottom); - Dimension contentPrefSize = contentPane.getPreferredSize(); - prefSize.width += contentPrefSize.width; - prefSize.height += contentPrefSize.height; - if (menuBar != null) - { - Dimension menuBarSize = menuBar.getPreferredSize(); - if (menuBarSize.width > contentPrefSize.width) - prefSize.width += menuBarSize.width - contentPrefSize.width; - prefSize.height += menuBarSize.height; - } - } - // Return a copy here so the cached value won't get trashed by some - // other component. - return new Dimension(prefSize); - } + Dimension menuBarSize = menuBar.getPreferredSize(); + if (menuBarSize.width > contentPrefSize.width) + prefSize.width += menuBarSize.width - contentPrefSize.width; + prefSize.height += menuBarSize.height; + } + return prefSize; } /** @@ -541,6 +526,7 @@ public class JRootPane extends JComponent implements Accessible getGlassPane(); getLayeredPane(); getContentPane(); + setOpaque(true); updateUI(); } @@ -674,4 +660,18 @@ public class JRootPane extends JComponent implements Accessible windowDecorationStyle = style; firePropertyChange("windowDecorationStyle", oldStyle, style); } + + /** + * This returns true if the glassPane is not + * visible because then the root pane can guarantee to tile its children + * (the only other direct child is a JLayeredPane which must figure its + * optimizeDrawingEnabled state on its own). + * + * @return true if the glassPane is not + * visible + */ + public boolean isOptimizedDrawingEnable() + { + return ! glassPane.isVisible(); + } } diff --git a/javax/swing/JSpinner.java b/javax/swing/JSpinner.java index af34d9cf6..882d216e1 100644 --- a/javax/swing/JSpinner.java +++ b/javax/swing/JSpinner.java @@ -1,5 +1,5 @@ /* JSpinner.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,7 +45,9 @@ import java.awt.Insets; import java.awt.LayoutManager; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.text.DateFormat; import java.text.DecimalFormat; +import java.text.NumberFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -53,10 +55,15 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.SpinnerUI; import javax.swing.text.DateFormatter; +import javax.swing.text.DefaultFormatterFactory; +import javax.swing.text.NumberFormatter; /** - * A JSpinner is a component which typically contains a numeric value and a - * way to manipulate the value. + * A JSpinner is a component that displays a single value from + * a sequence of values, and provides a convenient means for selecting the + * previous and next values in the sequence. Typically the spinner displays + * a numeric value, but it is possible to display dates or arbitrary items + * from a list. * * @author Ka-Hing Cheung * @@ -65,12 +72,15 @@ import javax.swing.text.DateFormatter; public class JSpinner extends JComponent { /** - * DOCUMENT ME! + * The base class for the editor used by the {@link JSpinner} component. + * The editor is in fact a panel containing a {@link JFormattedTextField} + * component. */ - public static class DefaultEditor extends JPanel implements ChangeListener, - PropertyChangeListener, - LayoutManager + public static class DefaultEditor + extends JPanel + implements ChangeListener, PropertyChangeListener, LayoutManager { + /** The spinner that the editor is allocated to. */ private JSpinner spinner; /** The JFormattedTextField that backs the editor. */ @@ -82,7 +92,8 @@ public class JSpinner extends JComponent private static final long serialVersionUID = -5317788736173368172L; /** - * Creates a new DefaultEditor object. + * Creates a new DefaultEditor object. The editor is + * registered with the spinner as a {@link ChangeListener} here. * * @param spinner the JSpinner associated with this editor */ @@ -94,11 +105,15 @@ public class JSpinner extends JComponent ftf = new JFormattedTextField(); add(ftf); ftf.setValue(spinner.getValue()); + ftf.addPropertyChangeListener(this); spinner.addChangeListener(this); } /** - * Returns the JSpinner object for this editor. + * Returns the JSpinner component that the editor is assigned + * to. + * + * @return The spinner that the editor is assigned to. */ public JSpinner getSpinner() { @@ -114,9 +129,10 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Removes the editor from the {@link ChangeListener} list maintained by + * the specified spinner. * - * @param spinner DOCUMENT ME! + * @param spinner the spinner (null not permitted). */ public void dismiss(JSpinner spinner) { @@ -124,9 +140,10 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Returns the text field used to display and edit the current value in + * the spinner. * - * @return DOCUMENT ME! + * @return The text field. */ public JFormattedTextField getTextField() { @@ -134,9 +151,10 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Sets the bounds for the child components in this container. In this + * case, the text field is the only component to be laid out. * - * @param parent DOCUMENT ME! + * @param parent the parent container. */ public void layoutContainer(Container parent) { @@ -148,11 +166,13 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Calculates the minimum size for this component. In this case, the + * text field is the only subcomponent, so the return value is the minimum + * size of the text field plus the insets of this component. * - * @param parent DOCUMENT ME! + * @param parent the parent container. * - * @return DOCUMENT ME! + * @return The minimum size. */ public Dimension minimumLayoutSize(Container parent) { @@ -163,11 +183,13 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Calculates the preferred size for this component. In this case, the + * text field is the only subcomponent, so the return value is the + * preferred size of the text field plus the insets of this component. * - * @param parent DOCUMENT ME! + * @param parent the parent container. * - * @return DOCUMENT ME! + * @return The preferred size. */ public Dimension preferredLayoutSize(Container parent) { @@ -178,35 +200,51 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Receives notification of property changes. If the text field's 'value' + * property changes, the spinner's model is updated accordingly. * - * @param event DOCUMENT ME! + * @param event the event. */ public void propertyChange(PropertyChangeEvent event) { - // TODO: Implement this properly. + if (event.getSource() == ftf) + { + if (event.getPropertyName().equals("value")) + spinner.getModel().setValue(event.getNewValue()); + } } /** - * DOCUMENT ME! + * Receives notification of changes in the state of the {@link JSpinner} + * that the editor belongs to - the content of the text field is updated + * accordingly. * - * @param event DOCUMENT ME! + * @param event the change event. */ public void stateChanged(ChangeEvent event) { - // TODO: Implement this properly. + ftf.setValue(spinner.getValue()); } + /** + * This method does nothing. It is required by the {@link LayoutManager} + * interface, but since this component has a single child, there is no + * need to use this method. + * + * @param child the child component to remove. + */ public void removeLayoutComponent(Component child) { // Nothing to do here. } /** - * DOCUMENT ME! - * - * @param name DOCUMENT ME! - * @param child DOCUMENT ME! + * This method does nothing. It is required by the {@link LayoutManager} + * interface, but since this component has a single child, there is no + * need to use this method. + * + * @param name the name. + * @param child the child component to add. */ public void addLayoutComponent(String name, Component child) { @@ -215,7 +253,11 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * A panel containing a {@link JFormattedTextField} that is configured for + * displaying and editing numbers. The panel is used as a subcomponent of + * a {@link JSpinner}. + * + * @see JSpinner#createEditor(SpinnerModel) */ public static class NumberEditor extends DefaultEditor { @@ -225,40 +267,72 @@ public class JSpinner extends JComponent private static final long serialVersionUID = 3791956183098282942L; /** - * Creates a new NumberEditor object. + * Creates a new NumberEditor object for the specified + * spinner. The editor is registered with the spinner as a + * {@link ChangeListener}. * - * @param spinner DOCUMENT ME! + * @param spinner the component the editor will be used with. */ public NumberEditor(JSpinner spinner) { super(spinner); + NumberEditorFormatter nef = new NumberEditorFormatter(); + nef.setMinimum(getModel().getMinimum()); + nef.setMaximum(getModel().getMaximum()); + ftf.setFormatterFactory(new DefaultFormatterFactory(nef)); } /** - * Creates a new NumberEditor object. + * Creates a new NumberEditor object. * - * @param spinner DOCUMENT ME! + * @param spinner the spinner. + * @param decimalFormatPattern the number format pattern. */ public NumberEditor(JSpinner spinner, String decimalFormatPattern) { super(spinner); + NumberEditorFormatter nef + = new NumberEditorFormatter(decimalFormatPattern); + nef.setMinimum(getModel().getMinimum()); + nef.setMaximum(getModel().getMaximum()); + ftf.setFormatterFactory(new DefaultFormatterFactory(nef)); } /** - * DOCUMENT ME! + * Returns the format used by the text field. * - * @return DOCUMENT ME! + * @return The format used by the text field. */ public DecimalFormat getFormat() { - return null; + NumberFormatter formatter = (NumberFormatter) ftf.getFormatter(); + return (DecimalFormat) formatter.getFormat(); } + /** + * Returns the model used by the editor's {@link JSpinner} component, + * cast to a {@link SpinnerNumberModel}. + * + * @return The model. + */ public SpinnerNumberModel getModel() { return (SpinnerNumberModel) getSpinner().getModel(); } } + + static class NumberEditorFormatter + extends NumberFormatter + { + public NumberEditorFormatter() + { + super(NumberFormat.getInstance()); + } + public NumberEditorFormatter(String decimalFormatPattern) + { + super(new DecimalFormat(decimalFormatPattern)); + } + } /** * A JSpinner editor used for the {@link SpinnerListModel}. @@ -279,6 +353,11 @@ public class JSpinner extends JComponent super(spinner); } + /** + * Returns the spinner's model cast as a {@link SpinnerListModel}. + * + * @return The spinner's model. + */ public SpinnerListModel getModel() { return (SpinnerListModel) getSpinner().getModel(); @@ -299,9 +378,6 @@ public class JSpinner extends JComponent /** The serialVersionUID. */ private static final long serialVersionUID = -4279356973770397815L; - /** The DateFormat instance used to format the date. */ - SimpleDateFormat dateFormat; - /** * Creates a new instance of DateEditor for the specified * JSpinner. @@ -312,7 +388,10 @@ public class JSpinner extends JComponent public DateEditor(JSpinner spinner) { super(spinner); - init(new SimpleDateFormat()); + DateEditorFormatter nef = new DateEditorFormatter(); + nef.setMinimum(getModel().getStart()); + nef.setMaximum(getModel().getEnd()); + ftf.setFormatterFactory(new DefaultFormatterFactory(nef)); } /** @@ -329,26 +408,10 @@ public class JSpinner extends JComponent public DateEditor(JSpinner spinner, String dateFormatPattern) { super(spinner); - init(new SimpleDateFormat(dateFormatPattern)); - } - - /** - * Initializes the JFormattedTextField for this editor. - * - * @param format the date format to use in the formatted text field - */ - private void init(SimpleDateFormat format) - { - dateFormat = format; - getTextField().setFormatterFactory( - new JFormattedTextField.AbstractFormatterFactory() - { - public JFormattedTextField.AbstractFormatter - getFormatter(JFormattedTextField ftf) - { - return new DateFormatter(dateFormat); - } - }); + DateEditorFormatter nef = new DateEditorFormatter(dateFormatPattern); + nef.setMinimum(getModel().getStart()); + nef.setMaximum(getModel().getEnd()); + ftf.setFormatterFactory(new DefaultFormatterFactory(nef)); } /** @@ -360,7 +423,8 @@ public class JSpinner extends JComponent */ public SimpleDateFormat getFormat() { - return dateFormat; + DateFormatter formatter = (DateFormatter) ftf.getFormatter(); + return (SimpleDateFormat) formatter.getFormat(); } /** @@ -374,25 +438,59 @@ public class JSpinner extends JComponent } } - private static final long serialVersionUID = 3412663575706551720L; + static class DateEditorFormatter + extends DateFormatter + { + public DateEditorFormatter() + { + super(DateFormat.getInstance()); + } + public DateEditorFormatter(String dateFormatPattern) + { + super(new SimpleDateFormat(dateFormatPattern)); + } + } + + /** + * A listener that forwards {@link ChangeEvent} notifications from the model + * to the {@link JSpinner}'s listeners. + */ + class ModelListener implements ChangeListener + { + /** + * Creates a new listener. + */ + public ModelListener() + { + // nothing to do here + } + + /** + * Receives notification from the model that its state has changed. + * + * @param event the event (ignored). + */ + public void stateChanged(ChangeEvent event) + { + fireStateChanged(); + } + } - /** DOCUMENT ME! */ + /** + * The model that defines the current value and permitted values for the + * spinner. + */ private SpinnerModel model; - /** DOCUMENT ME! */ + /** The current editor. */ private JComponent editor; - /** DOCUMENT ME! */ - private ChangeListener listener = new ChangeListener() - { - public void stateChanged(ChangeEvent evt) - { - fireStateChanged(); - } - }; + private static final long serialVersionUID = 3412663575706551720L; /** - * Creates a JSpinner with SpinnerNumberModel + * Creates a new JSpinner with default instance of + * {@link SpinnerNumberModel} (that is, a model with value 0, step size 1, + * and no upper or lower limit). * * @see javax.swing.SpinnerNumberModel */ @@ -402,15 +500,19 @@ public class JSpinner extends JComponent } /** - * Creates a JSpinner with the specific model and sets the default editor + * Creates a new JSpinner with the specified model. The + * {@link #createEditor(SpinnerModel)} method is used to create an editor + * that is suitable for the model. * - * @param model DOCUMENT ME! + * @param model the model (null not permitted). + * + * @throws NullPointerException if model is null. */ public JSpinner(SpinnerModel model) { this.model = model; - model.addChangeListener(listener); - setEditor(createEditor(model)); + this.editor = createEditor(model); + model.addChangeListener(new ModelListener()); updateUI(); } @@ -439,12 +541,13 @@ public class JSpinner extends JComponent } /** - * Changes the current editor to the new editor. This methods should remove - * the old listeners (if any) and adds the new listeners (if any). + * Changes the current editor to the new editor. The old editor is + * removed from the spinner's {@link ChangeEvent} list. * - * @param editor the new editor + * @param editor the new editor (null not permitted. * - * @throws IllegalArgumentException DOCUMENT ME! + * @throws IllegalArgumentException if editor is + * null. * * @see #getEditor */ @@ -453,21 +556,22 @@ public class JSpinner extends JComponent if (editor == null) throw new IllegalArgumentException("editor may not be null"); - if (this.editor instanceof DefaultEditor) - ((DefaultEditor) editor).dismiss(this); - else if (this.editor instanceof ChangeListener) - removeChangeListener((ChangeListener) this.editor); - - if (editor instanceof ChangeListener) - addChangeListener((ChangeListener) editor); - + JComponent oldEditor = this.editor; + if (oldEditor instanceof DefaultEditor) + ((DefaultEditor) oldEditor).dismiss(this); + else if (oldEditor instanceof ChangeListener) + removeChangeListener((ChangeListener) oldEditor); + this.editor = editor; + firePropertyChange("editor", oldEditor, editor); } /** - * Gets the underly model. + * Returns the model used by the {@link JSpinner} component. * - * @return the underly model + * @return The model. + * + * @see #setModel(SpinnerModel) */ public SpinnerModel getModel() { @@ -492,9 +596,7 @@ public class JSpinner extends JComponent SpinnerModel oldModel = model; model = newModel; firePropertyChange("model", oldModel, newModel); - - if (editor == null) - setEditor(createEditor(model)); + setEditor(createEditor(model)); } /** @@ -545,9 +647,9 @@ public class JSpinner extends JComponent } /** - * DOCUMENT ME! + * Sets the value in the model. * - * @param value DOCUMENT ME! + * @param value the new value. */ public void setValue(Object value) { @@ -555,10 +657,10 @@ public class JSpinner extends JComponent } /** - * This method returns a name to identify which look and feel class will be + * Returns the ID that identifies which look and feel class will be * the UI delegate for this spinner. * - * @return The UIClass identifier. "SpinnerUI" + * @return "SpinnerUI". */ public String getUIClassID() { @@ -575,7 +677,7 @@ public class JSpinner extends JComponent } /** - * This method sets the spinner's UI delegate. + * Sets the UI delegate for the component. * * @param ui The spinner's UI delegate. */ @@ -628,14 +730,11 @@ public class JSpinner extends JComponent } /** - * Creates an editor for this JSpinner. Really, it should be a - * JSpinner.DefaultEditor, but since that should be - * implemented by a JFormattedTextField, and one is not written, I am just - * using a dummy one backed by a JLabel. + * Creates an editor that is appropriate for the specified model. * - * @param model DOCUMENT ME! + * @param model the model. * - * @return the default editor + * @return The editor. */ protected JComponent createEditor(SpinnerModel model) { @@ -643,6 +742,8 @@ public class JSpinner extends JComponent return new DateEditor(this); else if (model instanceof SpinnerNumberModel) return new NumberEditor(this); + else if (model instanceof SpinnerListModel) + return new ListEditor(this); else return new DefaultEditor(this); } diff --git a/javax/swing/JSplitPane.java b/javax/swing/JSplitPane.java index 70feefab2..dc75dfe31 100644 --- a/javax/swing/JSplitPane.java +++ b/javax/swing/JSplitPane.java @@ -343,10 +343,13 @@ public class JSplitPane extends JComponent implements Accessible throw new IllegalArgumentException("Constraints is not a known identifier."); + // If no dividerLocation has been set, then we need to trigger an + // initial layout. + if (getDividerLocation() != -1) + resetToPreferredSizes(); + super.addImpl(comp, constraints, index); } - invalidate(); - layout(); } /** diff --git a/javax/swing/JTabbedPane.java b/javax/swing/JTabbedPane.java index 8a7d4c07f..1619874b0 100644 --- a/javax/swing/JTabbedPane.java +++ b/javax/swing/JTabbedPane.java @@ -44,12 +44,14 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.io.Serializable; +import java.util.Locale; import java.util.Vector; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleStateSet; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.TabbedPaneUI; @@ -136,7 +138,12 @@ public class JTabbedPane extends JComponent implements Serializable, */ public Accessible getAccessibleChild(int i) { - return null; + // Testing shows that the reference implementation returns instances + // of page here. + Accessible child = null; + if (i >= 0 && i < tabs.size()) + child = (Page) tabs.get(i); + return child; } /** @@ -273,6 +280,8 @@ public class JTabbedPane extends JComponent implements Serializable, * A private class that holds all the information for each tab. */ private class Page + extends AccessibleContext + implements Accessible { /** The tooltip string. */ private String tip; @@ -553,6 +562,74 @@ public class JTabbedPane extends JComponent implements Serializable, underlinedChar = index; } + + /** + * Returns the accessible context, which is this object itself. + * + * @return the accessible context, which is this object itself + */ + public AccessibleContext getAccessibleContext() + { + return this; + } + + /** + * Returns the accessible role of this tab, which is always + * {@link AccessibleRole#PAGE_TAB}. + * + * @return the accessible role of this tab + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.PAGE_TAB; + } + + public AccessibleStateSet getAccessibleStateSet() + { + // FIXME: Implement this properly. + return null; + } + + public int getAccessibleIndexInParent() + { + // FIXME: Implement this properly. + return 0; + } + + /** + * Returns the number of accessible children, which is always one (the + * component of this tab). + * + * @return the number of accessible children + */ + public int getAccessibleChildrenCount() + { + return 1; + } + + /** + * Returns the accessible child of this tab, which is the component + * displayed by the tab. + * + * @return the accessible child of this tab + */ + public Accessible getAccessibleChild(int i) + { + // A quick test shows that this method always returns the component + // displayed by the tab, regardless of the index. + return (Accessible) component; + } + + /** + * Returns the locale of this accessible object. + * + * @return the locale of this accessible object + */ + public Locale getLocale() + { + // TODO: Is this ok? + return Locale.getDefault(); + } } private static final long serialVersionUID = 1614381073220130939L; diff --git a/javax/swing/JTable.java b/javax/swing/JTable.java index fe456cee4..38b2d89f9 100644 --- a/javax/swing/JTable.java +++ b/javax/swing/JTable.java @@ -1,5 +1,5 @@ /* JTable.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -46,8 +46,6 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Point; import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.FocusListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -86,8 +84,16 @@ import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; -import javax.swing.text.Caret; +/** + * The table component, displaying information, organized in rows and columns. + * The table can be placed in the scroll bar and have the optional header + * that is always visible. Cell values may be editable after double clicking + * on the cell. Cell columns may have various data types, that are + * displayed and edited by the different renderers and editors. It is possible + * to set different column width. The columns are also resizeable by + * dragging the column boundary in the header. + */ public class JTable extends JComponent implements TableModelListener, Scrollable, TableColumnModelListener, @@ -588,7 +594,7 @@ public class JTable return lastColumn; } } - + /** * Creates a new AccessibleJTable. * @@ -979,9 +985,9 @@ public class JTable class TableColumnPropertyChangeHandler implements PropertyChangeListener { /** - * Receives notification that a property of the observed TableColumns - * has changed. - * + * Receives notification that a property of the observed TableColumns has + * changed. + * * @param ev the property change event */ public void propertyChange(PropertyChangeEvent ev) @@ -989,13 +995,15 @@ public class JTable if (ev.getPropertyName().equals("preferredWidth")) { JTableHeader header = getTableHeader(); - if (header != null) - { - TableColumn col = (TableColumn) ev.getSource(); - header.setResizingColumn(col); - doLayout(); - header.setResizingColumn(null); - } + if (header != null) + // Do nothing if the table is in the resizing mode. + if (header.getResizingColumn() == null) + { + TableColumn col = (TableColumn) ev.getSource(); + header.setResizingColumn(col); + doLayout(); + header.setResizingColumn(null); + } } } } @@ -1006,11 +1014,30 @@ public class JTable private class BooleanCellRenderer extends DefaultTableCellRenderer { - /** * The CheckBox that is used for rendering. */ - private JCheckBox checkBox = new JCheckBox(); + private final JCheckBox checkBox = new JCheckBox(); + + /** + * The check box must have the text field background and be centered. + */ + private BooleanCellRenderer() + { + // Render the checkbox identically as the text field. + JTextField f = new JTextField(); + checkBox.setForeground(f.getForeground()); + checkBox.setBackground(f.getBackground()); + checkBox.setHorizontalAlignment(SwingConstants.CENTER); + } + + /** + * Get the check box. + */ + JCheckBox getCheckBox() + { + return checkBox; + } /** * Returns the component that is used for rendering the value. @@ -1029,8 +1056,14 @@ public class JTable boolean hasFocus, int row, int column) { - Boolean boolValue = (Boolean) value; - checkBox.setSelected(boolValue.booleanValue()); + // Null is rendered as false. + if (value == null) + checkBox.setSelected(false); + else + { + Boolean boolValue = (Boolean) value; + checkBox.setSelected(boolValue.booleanValue()); + } return checkBox; } } @@ -1200,12 +1233,52 @@ public class JTable { Icon iconValue = (Icon) value; setIcon(iconValue); + setText(""); } return this; } } + + /** + * The JTable text component (used in editing) always has the table + * as its parent. The scrollRectToVisible must be adjusted taking the + * relative component position. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ + private class TableTextField extends JTextField + { + /** + * Create the text field without the border. + */ + TableTextField() + { + setBorder(null); + } + + /** + * Scroll the table, making the given rectangle of this component + * visible. Mind the component position with relate to the table. + * With not this method overridden, the scroll pane scrolls to the + * top left cornec (untranslated position of the caret) after the first + * keystroke. + */ + public void scrollRectToVisible(Rectangle r) + { + // In private class we known that the rectangle data will not be + // reused and we need not to clone it. + r.translate(getX(), getY()); + super.scrollRectToVisible(r); + } + } + private static final long serialVersionUID = 3876025080382781659L; + + /** + * This table, for referring identically name methods from inner classes. + */ + final JTable this_table = this; /** @@ -1476,27 +1549,6 @@ public class JTable */ protected JTableHeader tableHeader; - /** - * The row of the cell being edited. - */ - int rowBeingEdited = -1; - - /** - * The column of the cell being edited. - */ - int columnBeingEdited = -1; - - /** - * The action listener for the editor's Timer. - */ - Timer editorTimer = new EditorUpdateTimer(); - - /** - * Stores the old value of a cell before it was edited, in case - * editing is cancelled - */ - Object oldCellValue; - /** * The property handler for this table's columns. */ @@ -1509,6 +1561,11 @@ public class JTable */ private boolean surrendersFocusOnKeystroke = false; + /** + * A Rectangle object to be reused in {@link #getCellRect}. + */ + private Rectangle rectCache = new Rectangle(); + /** * Creates a new JTable instance. */ @@ -1518,7 +1575,8 @@ public class JTable } /** - * Creates a new JTable instance. + * Creates a new JTable instance with the given number + * of rows and columns. * * @param numRows an int value * @param numColumns an int value @@ -1529,10 +1587,12 @@ public class JTable } /** - * Creates a new JTable instance. + * Creates a new JTable instance, storing the given data + * array and heaving the given column names. To see the column names, + * you must place the JTable into the {@link JScrollPane}. * - * @param data an Object[][] value - * @param columnNames an Object[] value + * @param data an Object[][] the table data + * @param columnNames an Object[] the column headers */ public JTable(Object[][] data, Object[] columnNames) { @@ -1540,20 +1600,31 @@ public class JTable } /** - * Creates a new JTable instance. - * - * @param dm a TableModel value + * Creates a new JTable instance, using the given data model + * object that provides information about the table content. The table model + * object is asked for the table size, other features and also receives + * notifications in the case when the table has been edited by the user. + * + * @param model + * the table model. */ - public JTable (TableModel dm) + public JTable (TableModel model) { - this(dm, null, null); + this(model, null, null); } /** - * Creates a new JTable instance. - * - * @param dm a TableModel value - * @param cm a TableColumnModel value + * Creates a new JTable instance, using the given model object + * that provides information about the table content. The table data model + * object is asked for the table size, other features and also receives + * notifications in the case when the table has been edited by the user. The + * table column model provides more detailed control on the table column + * related features. + * + * @param dm + * the table data mode + * @param cm + * the table column model */ public JTable (TableModel dm, TableColumnModel cm) { @@ -1561,11 +1632,13 @@ public class JTable } /** - * Creates a new JTable instance. + * Creates a new JTable instance, providing data model, + * column model and list selection model. The list selection model + * manages the selections. * - * @param dm a TableModel value - * @param cm a TableColumnModel value - * @param sm a ListSelectionModel value + * @param dm data model (manages table data) + * @param cm column model (manages table columns) + * @param sm list selection model (manages table selections) */ public JTable (TableModel dm, TableColumnModel cm, ListSelectionModel sm) { @@ -1593,8 +1666,23 @@ public class JTable columnModel.getSelectionModel().setAnchorSelectionIndex(0); columnModel.getSelectionModel().setLeadSelectionIndex(0); updateUI(); - } - + } + + /** + * Creates a new JTable instance that uses data and column + * names, stored in {@link Vector}s. + * + * @param data the table data + * @param columnNames the table column names. + */ + public JTable(Vector data, Vector columnNames) + { + this(new DefaultTableModel(data, columnNames)); + } + + /** + * Initialize local variables to default values. + */ protected void initializeLocalVars() { setTableHeader(createDefaultTableHeader()); @@ -1623,63 +1711,18 @@ public class JTable this.editingRow = -1; setIntercellSpacing(new Dimension(1,1)); } - - /** - * Creates a new JTable instance. - * - * @param data a Vector value - * @param columnNames a Vector value - */ - public JTable(Vector data, Vector columnNames) - { - this(new DefaultTableModel(data, columnNames)); - } - + /** - * The timer that updates the editor component. + * Add the new table column. The table column class allows to specify column + * features more precisely, setting the preferred width, column data type + * (column class) and table headers. + * + * There is no need the add columns to the table if the default column + * handling is sufficient. + * + * @param column + * the new column to add. */ - private class EditorUpdateTimer - extends Timer - implements ActionListener - { - /** - * Creates a new EditorUpdateTimer object with a default delay of 0.5 seconds. - */ - public EditorUpdateTimer() - { - super(500, null); - addActionListener(this); - } - - /** - * Lets the caret blink and repaints the table. - */ - public void actionPerformed(ActionEvent ev) - { - Caret c = ((JTextField)JTable.this.editorComp).getCaret(); - if (c != null) - c.setVisible(!c.isVisible()); - JTable.this.repaint(); - } - - /** - * Updates the blink delay according to the current caret. - */ - public void update() - { - stop(); - Caret c = ((JTextField)JTable.this.editorComp).getCaret(); - if (c != null) - { - setDelay(c.getBlinkRate()); - if (((JTextField)JTable.this.editorComp).isEditable()) - start(); - else - c.setVisible(false); - } - } - } - public void addColumn(TableColumn column) { if (column.getHeaderValue() == null) @@ -1691,12 +1734,24 @@ public class JTable columnModel.addColumn(column); column.addPropertyChangeListener(tableColumnPropertyChangeHandler); } - + + /** + * Create the default editors for this table. The default method creates + * the editor for Booleans. + * + * Other fields are edited as strings at the moment. + */ protected void createDefaultEditors() { - //FIXME: Create the editor object. + JCheckBox box = new BooleanCellRenderer().getCheckBox(); + setDefaultEditor(Boolean.class, new DefaultCellEditor(box)); } - + + /** + * Create the default renderers for this table. The default method creates + * renderers for Boolean, Number, Double, Date, Icon and ImageIcon. + * + */ protected void createDefaultRenderers() { setDefaultRenderer(Boolean.class, new BooleanCellRenderer()); @@ -1705,6 +1760,7 @@ public class JTable setDefaultRenderer(Double.class, new FloatCellRenderer()); setDefaultRenderer(Date.class, new DateCellRenderer()); setDefaultRenderer(Icon.class, new IconCellRenderer()); + setDefaultRenderer(ImageIcon.class, new IconCellRenderer()); } /** @@ -1714,112 +1770,148 @@ public class JTable { return new JScrollPane(table); } - + + /** + * Create the default table column model that is used if the user-defined + * column model is not provided. The default method creates + * {@link DefaultTableColumnModel}. + * + * @return the created table column model. + */ protected TableColumnModel createDefaultColumnModel() { return new DefaultTableColumnModel(); } + /** + * Create the default table data model that is used if the user-defined + * data model is not provided. The default method creates + * {@link DefaultTableModel}. + * + * @return the created table data model. + */ protected TableModel createDefaultDataModel() { return new DefaultTableModel(); } + /** + * Create the default table selection model that is used if the user-defined + * selection model is not provided. The default method creates + * {@link DefaultListSelectionModel}. + * + * @return the created table data model. + */ protected ListSelectionModel createDefaultSelectionModel() { return new DefaultListSelectionModel(); } - + + /** + * Create the default table header, if the user - defined table header is not + * provided. + * + * @return the default table header. + */ protected JTableHeader createDefaultTableHeader() { return new JTableHeader(columnModel); } - - // listener support - + + /** + * Invoked when the column is added. Revalidates and repains the table. + */ public void columnAdded (TableColumnModelEvent event) { revalidate(); repaint(); } + /** + * Invoked when the column margin is changed. + * Revalidates and repains the table. + */ public void columnMarginChanged (ChangeEvent event) { revalidate(); repaint(); } + /** + * Invoked when the column is moved. Revalidates and repains the table. + */ public void columnMoved (TableColumnModelEvent event) { revalidate(); repaint(); } + /** + * Invoked when the column is removed. Revalidates and repains the table. + */ public void columnRemoved (TableColumnModelEvent event) { revalidate(); repaint(); } + /** + * Invoked when the the column selection changes. + */ public void columnSelectionChanged (ListSelectionEvent event) { repaint(); } - + + /** + * Invoked when the editing is cancelled. + */ public void editingCanceled (ChangeEvent event) { - if (rowBeingEdited > -1 && columnBeingEdited > -1) + if (editorComp!=null) { - if (getValueAt(rowBeingEdited, columnBeingEdited) instanceof JTextField) - { - remove ((Component)getValueAt(rowBeingEdited, columnBeingEdited)); - setValueAt(oldCellValue, rowBeingEdited, columnBeingEdited); - } - rowBeingEdited = -1; - columnBeingEdited = -1; + remove(editorComp); + repaint(editorComp.getBounds()); + editorComp = null; } - editorTimer.stop(); - editorComp = null; - cellEditor = null; - requestFocusInWindow(false); - repaint(); } - + + /** + * Finish the current editing session and update the table with the + * new value by calling {@link #setValueAt}. + * + * @param event the change event + */ public void editingStopped (ChangeEvent event) { - if (rowBeingEdited > -1 && columnBeingEdited > -1) + if (editorComp!=null) { - if (getValueAt(rowBeingEdited, columnBeingEdited) instanceof JTextField) - { - remove((Component)getValueAt(rowBeingEdited, columnBeingEdited)); - setValueAt(((JTextField)editorComp).getText(), - rowBeingEdited, columnBeingEdited); - } - rowBeingEdited = -1; - columnBeingEdited = -1; + remove(editorComp); + setValueAt(cellEditor.getCellEditorValue(), editingRow, editingColumn); + repaint(editorComp.getBounds()); + editorComp = null; } - editorTimer.stop(); - editorComp = null; - cellEditor = null; - requestFocusInWindow(false); - repaint(); + requestFocusInWindow(); } + /** + * Invoked when the table changes. + * null means everything changed. + */ public void tableChanged (TableModelEvent event) { // update the column model from the table model if the structure has // changed and the flag autoCreateColumnsFromModel is set - if ((event.getFirstRow() ==TableModelEvent.HEADER_ROW) - && autoCreateColumnsFromModel) - + if ((event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW)) + && autoCreateColumnsFromModel) createDefaultColumnsFromModel(); // If the structure changes, we need to revalidate, since that might // affect the size parameters of the JTable. Otherwise we only need // to perform a repaint to update the view. - if (event.getType() == TableModelEvent.INSERT) + if (event == null || event.getType() == TableModelEvent.INSERT) revalidate(); - else if (event.getType() == TableModelEvent.DELETE) + if (event == null || event.getType() == TableModelEvent.DELETE) { if (dataModel.getRowCount() == 0) clearSelection(); @@ -1828,6 +1920,9 @@ public class JTable repaint(); } + /** + * Invoked when another table row is selected. + */ public void valueChanged (ListSelectionEvent event) { repaint(); @@ -1863,29 +1958,30 @@ public class JTable } /** - * Returns index of the row that contains specified point or - * -1 if this table doesn't contain this point. - * - * @param point point to identify the row - * @return index of the row that contains specified point or - * -1 if this table doesn't contain this point. + * Returns index of the row that contains specified point or -1 if this table + * doesn't contain this point. + * + * @param point + * point to identify the row + * @return index of the row that contains specified point or -1 if this table + * doesn't contain this point. */ public int rowAtPoint(Point point) { if (point != null) { int nrows = getRowCount(); - int height = getRowHeight(); + int height = getRowHeight() + getRowMargin(); int y = point.y; - for (int i = 0; i < nrows; ++i) - { - if (0 <= y && y < height) - return i; - y -= height; - } + int r = y / height; + if (r < 0 || r >= nrows) + return -1; + else + return r; } - return -1; + else + return -1; } /** @@ -1908,6 +2004,9 @@ public class JTable int column, boolean includeSpacing) { + // moveToCellBeingEdited expects the cached value and clones it. + // If the caching would be removed later, uplate moveToCellBeingEdited + // as well. int height = getRowHeight(row); int width = columnModel.getColumn(column).getWidth(); int x_gap = columnModel.getColumnMargin(); @@ -1923,9 +2022,10 @@ public class JTable x += columnModel.getColumn(i).getWidth(); if (includeSpacing) - return new Rectangle(x, y, width, height); + rectCache.setBounds(x, y, width, height +y_gap); else - return new Rectangle(x, y, width - x_gap, height - y_gap); + rectCache.setBounds(x, y, width - x_gap, height); + return rectCache; } public void clearSelection() @@ -2008,44 +2108,88 @@ public class JTable } + /** + * Get the cell editor, suitable for editing the given cell. The default + * method requests the editor from the column model. If the column model does + * not provide the editor, the call is forwarded to the + * {@link #getDefaultEditor(Class)} with the parameter, obtained from + * {@link TableModel#getColumnClass(int)}. + * + * @param row the cell row + * @param column the cell column + * @return the editor to edit that cell + */ public TableCellEditor getCellEditor(int row, int column) { TableCellEditor editor = columnModel.getColumn(column).getCellEditor(); if (editor == null) - editor = getDefaultEditor(dataModel.getColumnClass(column)); - + { + int mcolumn = convertColumnIndexToModel(column); + editor = getDefaultEditor(dataModel.getColumnClass(mcolumn)); + } + return editor; } - + + /** + * Get the default editor for editing values of the given type + * (String, Boolean and so on). + * + * @param columnClass the class of the value that will be edited. + * + * @return the editor, suitable for editing this data type + */ public TableCellEditor getDefaultEditor(Class columnClass) { if (defaultEditorsByColumnClass.containsKey(columnClass)) return (TableCellEditor) defaultEditorsByColumnClass.get(columnClass); else { - // FIXME: We have at least an editor for Object.class in our defaults. - TableCellEditor r = new DefaultCellEditor(new JTextField()); + JTextField t = new TableTextField(); + TableCellEditor r = new DefaultCellEditor(t); defaultEditorsByColumnClass.put(columnClass, r); return r; } } + /** + * Get the cell renderer for rendering the given cell. + * + * @param row the cell row + * @param column the cell column + * @return the cell renderer to render that cell. + */ public TableCellRenderer getCellRenderer(int row, int column) { - TableCellRenderer renderer = - columnModel.getColumn(column).getCellRenderer(); + TableCellRenderer renderer = columnModel.getColumn(column).getCellRenderer(); if (renderer == null) - renderer = getDefaultRenderer(getColumnClass(column)); - + { + int mcolumn = convertColumnIndexToModel(column); + renderer = getDefaultRenderer(dataModel.getColumnClass(mcolumn)); + } return renderer; } + /** + * Set default renderer for rendering the given data type. + * + * @param columnClass the data type (String, Boolean and so on) that must be + * rendered. + * @param rend the renderer that will rend this data type + */ public void setDefaultRenderer(Class columnClass, TableCellRenderer rend) { defaultRenderersByColumnClass.put(columnClass, rend); } + /** + * Get the default renderer for rendering the given data type. + * + * @param columnClass the data that must be rendered + * + * @return the appropriate defauld renderer for rendering that data type. + */ public TableCellRenderer getDefaultRenderer(Class columnClass) { if (defaultRenderersByColumnClass.containsKey(columnClass)) @@ -2057,7 +2201,19 @@ public class JTable return r; } } - + + /** + * Convert the table model index into the table column number. + * The model number need not match the real column position. The columns + * may be rearranged by the user with mouse at any time by dragging the + * column headers. + * + * @param vc the column number (0=first). + * + * @return the table column model index of this column. + * + * @see TableColumn#getModelIndex() + */ public int convertColumnIndexToModel(int vc) { if (vc < 0) @@ -2065,7 +2221,19 @@ public class JTable else return columnModel.getColumn(vc).getModelIndex(); } - + + /** + * Convert the table column number to the table column model index. + * The model number need not match the real column position. The columns + * may be rearranged by the user with mouse at any time by dragging the + * column headers. + * + * @param mc the table column index (0=first). + * + * @return the table column number in the model + * + * @see TableColumn#getModelIndex() + */ public int convertColumnIndexToView(int mc) { if (mc < 0) @@ -2078,7 +2246,16 @@ public class JTable } return -1; } - + + /** + * Prepare the renderer for rendering the given cell. + * + * @param renderer the renderer being prepared + * @param row the row of the cell being rendered + * @param column the column of the cell being rendered + * + * @return the component which .paint() method will paint the cell. + */ public Component prepareRenderer(TableCellRenderer renderer, int row, int column) @@ -2640,8 +2817,13 @@ public class JTable if (dataModel != null && columnModel != null) { int ncols = getColumnCount(); + TableColumn column; for (int i = 0; i < ncols; ++i) - columnModel.getColumn(i).setHeaderValue(dataModel.getColumnName(i)); + { + column = columnModel.getColumn(i); + if (column.getHeaderValue()==null) + column.setHeaderValue(dataModel.getColumnName(i)); + } } // according to Sun's spec we also have to set the tableHeader's @@ -2899,10 +3081,34 @@ public class JTable for (int i = 0; i < cols.length; i++) { if (cols[i] != null) - cols[i].setWidth(cols[i].getWidth() + average); + cols[i].setWidth(cols[i].getPreferredWidth() + average); } } - + + /** + * This distributes the superfluous width in a table, setting the width of the + * column being resized strictly to its preferred width. + */ + private void distributeSpillResizing(TableColumn[] cols, int spill, + TableColumn resizeIt) + { + int average = spill / (cols.length-1); + for (int i = 0; i < cols.length; i++) + { + if (cols[i] != null && !cols[i].equals(resizeIt)) + cols[i].setWidth(cols[i].getPreferredWidth() + average); + } + resizeIt.setWidth(resizeIt.getPreferredWidth()); + } + + /** + * Set the widths of all columns, taking they preferred widths into + * consideration. The excess space, if any, will be distrubuted between + * all columns. This method also handles special cases when one of the + * collumns is currently being resized. + * + * @see TableColumn#setPreferredWidth(int) + */ public void doLayout() { TableColumn resizingColumn = null; @@ -2911,7 +3117,6 @@ public class JTable if (ncols < 1) return; - int[] pref = new int[ncols]; int prefSum = 0; int rCol = -1; @@ -2921,8 +3126,7 @@ public class JTable for (int i = 0; i < ncols; ++i) { TableColumn col = columnModel.getColumn(i); - int p = col.getWidth(); - pref[i] = p; + int p = col.getPreferredWidth(); prefSum += p; if (resizingColumn == col) rCol = i; @@ -2951,14 +3155,38 @@ public class JTable cols = new TableColumn[ncols]; for (int i = 0; i < ncols; ++i) cols[i] = columnModel.getColumn(i); - distributeSpill(cols, spill); + distributeSpillResizing(cols, spill, resizingColumn); break; case AUTO_RESIZE_SUBSEQUENT_COLUMNS: - cols = new TableColumn[ncols]; - for (int i = rCol; i < ncols; ++i) - cols[i] = columnModel.getColumn(i); - distributeSpill(cols, spill); + + // Subtract the width of the non-resized columns from the spill. + int w = 0; + int wp = 0; + TableColumn column; + for (int i = 0; i < rCol; i++) + { + column = columnModel.getColumn(i); + w += column.getWidth(); + wp+= column.getPreferredWidth(); + } + + // The number of columns right from the column being resized. + int n = ncols-rCol-1; + if (n>0) + { + // If there are any columns on the right sied to resize. + spill = (getWidth()-w) - (prefSum-wp); + int average = spill / n; + + // For all columns right from the column being resized: + for (int i = rCol+1; i < ncols; i++) + { + column = columnModel.getColumn(i); + column.setWidth(column.getPreferredWidth() + average); + } + } + resizingColumn.setWidth(resizingColumn.getPreferredWidth()); break; case AUTO_RESIZE_OFF: @@ -2974,6 +3202,16 @@ public class JTable cols[i] = columnModel.getColumn(i); distributeSpill(cols, spill); } + + if (editorComp!=null) + moveToCellBeingEdited(editorComp); + + // Repaint fixes the invalid view after the first keystroke if the cell + // editing is started immediately after the program start or cell + // resizing. + repaint(); + if (tableHeader!=null) + tableHeader.repaint(); } /** @@ -2983,7 +3221,7 @@ public class JTable { doLayout(); } - + /** * Obsolete since JDK 1.4. Please use doLayout(). */ @@ -3024,47 +3262,108 @@ public class JTable repaint(); } + /** + * Get the class (datatype) of the column. The cells are rendered and edited + * differently, depending from they data type. + * + * @param column the column (not the model index). + * + * @return the class, defining data type of that column (String.class for + * String, Boolean.class for boolean and so on). + */ public Class getColumnClass(int column) { - return getModel().getColumnClass(column); + return getModel().getColumnClass(convertColumnIndexToModel(column)); } + /** + * Get the name of the column. If the column has the column identifier set, + * the return value is the result of the .toString() method call on that + * identifier. If the identifier is not explicitly set, the returned value + * is calculated by + * {@link javax.swing.table.AbstractTableModel#getColumnName(int)}. + * + * @param column the column + * + * @return the name of that column. + */ public String getColumnName(int column) { int modelColumn = columnModel.getColumn(column).getModelIndex(); return dataModel.getColumnName(modelColumn); } + /** + * Get the column, currently being edited + * + * @return the column, currently being edited. + */ public int getEditingColumn() { return editingColumn; } + /** + * Set the column, currently being edited + * + * @param column the column, currently being edited. + */ public void setEditingColumn(int column) { editingColumn = column; } + /** + * Get the row currently being edited. + * + * @return the row, currently being edited. + */ public int getEditingRow() { return editingRow; } - public void setEditingRow(int column) + /** + * Set the row currently being edited. + * + * @param row the row, that will be edited + */ + public void setEditingRow(int row) { - editingRow = column; + editingRow = row; } + /** + * Get the editor component that is currently editing one of the cells + * + * @return the editor component or null, if none of the cells is being + * edited. + */ public Component getEditorComponent() { return editorComp; } + /** + * Check if one of the table cells is currently being edited. + * + * @return true if there is a cell being edited. + */ public boolean isEditing() { return editorComp != null; } + /** + * Set the default editor for the given column class (column data type). + * By default, String is handled by text field and Boolean is handled by + * the check box. + * + * @param columnClass the column data type + * @param editor the editor that will edit this data type + * + * @see TableModel#getColumnClass(int) + */ public void setDefaultEditor(Class columnClass, TableCellEditor editor) { if (editor != null) @@ -3072,7 +3371,7 @@ public class JTable else defaultEditorsByColumnClass.remove(columnClass); } - + public void addColumnSelectionInterval(int index0, int index1) { if ((index0 < 0 || index0 > (getColumnCount()-1) @@ -3127,21 +3426,49 @@ public class JTable getSelectionModel().removeSelectionInterval(index0, index1); } + /** + * Checks if the given column is selected. + * + * @param column the column + * + * @return true if the column is selected (as reported by the selection + * model, associated with the column model), false otherwise. + */ public boolean isColumnSelected(int column) { return getColumnModel().getSelectionModel().isSelectedIndex(column); } - + + /** + * Checks if the given row is selected. + * + * @param row the row + * + * @return true if the row is selected (as reported by the selection model), + * false otherwise. + */ public boolean isRowSelected(int row) { return getSelectionModel().isSelectedIndex(row); } - + + /** + * Checks if the given cell is selected. The cell is selected if both + * the cell row and the cell column are selected. + * + * @param row the cell row + * @param column the cell column + * + * @return true if the cell is selected, false otherwise + */ public boolean isCellSelected(int row, int column) { return isRowSelected(row) && isColumnSelected(column); } + /** + * Select all table. + */ public void selectAll() { // rowLead and colLead store the current lead selection indices @@ -3156,22 +3483,51 @@ public class JTable addColumnSelectionInterval(colLead,colLead); addRowSelectionInterval(rowLead, rowLead); } - + + /** + * Get the cell value at the given position. + * + * @param row the row to get the value + * @param column the actual column number (not the model index) + * to get the value. + * + * @return the cell value, as returned by model. + */ public Object getValueAt(int row, int column) { return dataModel.getValueAt(row, convertColumnIndexToModel(column)); } - + + /** + * Set value for the cell at the given position. If the cell is not + * editable, this method returns without action. The modified cell is + * repainted. + * + * @param value the value to set + * @param row the row of the cell being modified + * @param column the column of the cell being modified + */ public void setValueAt(Object value, int row, int column) { if (!isCellEditable(row, column)) return; - - if (value instanceof Component) - add((Component)value); dataModel.setValueAt(value, row, convertColumnIndexToModel(column)); + + repaint(getCellRect(row, column, true)); } - + + /** + * Get table column with the given identified. + * + * @param identifier the column identifier + * + * @return the table column with this identifier + * + * @throws IllegalArgumentException if identifier is + * null or there is no column with that identifier. + * + * @see TableColumn#setIdentifier(Object) + */ public TableColumn getColumn(Object identifier) { return columnModel.getColumn(columnModel.getColumnIndex(identifier)); @@ -3184,7 +3540,7 @@ public class JTable * @param row the row index. * @param column the column index. * - * @return A boolean. + * @return true if the cell is editable, false otherwise. */ public boolean isCellEditable(int row, int column) { @@ -3273,18 +3629,49 @@ public class JTable */ public boolean editCellAt (int row, int column) { - oldCellValue = getValueAt(row, column); + // Complete the previous editing session, if still active. + if (isEditing()) + editingStopped(new ChangeEvent("editingStopped")); + + editingRow = row; + editingColumn = column; + setCellEditor(getCellEditor(row, column)); editorComp = prepareEditor(cellEditor, row, column); - cellEditor.addCellEditorListener(this); - rowBeingEdited = row; - columnBeingEdited = column; - setValueAt(editorComp, row, column); - ((JTextField)editorComp).requestFocusInWindow(false); - editorTimer.start(); + + // Remove the previous editor components, if present. Only one + // editor component at time is allowed in the table. + removeAll(); + add(editorComp); + moveToCellBeingEdited(editorComp); + scrollRectToVisible(editorComp.getBounds()); + editorComp.requestFocusInWindow(); return true; } + /** + * Move the given component under the cell being edited. + * The table must be in the editing mode. + * + * @param component the component to move. + */ + private void moveToCellBeingEdited(Component component) + { + Rectangle r = getCellRect(editingRow, editingColumn, true); + // Place the text field so that it would not touch the table + // border. + + // TODO Figure out while 5 and which constant should here be. + int xOffset = 5; + r.x+=xOffset; + r.y++; + r.width -=xOffset; + r.height --; + + // Clone rectangle as getCellRect returns the cached value. + component.setBounds(new Rectangle(r)); + } + /** * Programmatically starts editing the specified cell. * @@ -3343,7 +3730,7 @@ public class JTable // TODO: Implement functionality of this property (in UI impl). surrendersFocusOnKeystroke = value; } - + /** * Returns whether cell editors of this table should receive keyboard focus * when the editor is activated by a keystroke. The default setting is diff --git a/javax/swing/JTextField.java b/javax/swing/JTextField.java index c49031061..01c5c06a3 100644 --- a/javax/swing/JTextField.java +++ b/javax/swing/JTextField.java @@ -41,6 +41,7 @@ package javax.swing; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; +import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; @@ -352,7 +353,10 @@ public class JTextField extends JTextComponent Dimension size = super.getPreferredSize(); if (columns != 0) - size.width = columns * getColumnWidth(); + { + Insets i = getInsets(); + size.width = columns * getColumnWidth() + i.left + i.right; + } return size; } @@ -526,4 +530,18 @@ public class JTextField extends JTextComponent // javax.swing.text.FieldView. return horizontalVisibility; } + + /** + * Returns true, unless this is embedded in a + * JViewport in which case the viewport takes responsibility of + * validating. + * + * @return true, unless this is embedded in a + * JViewport in which case the viewport takes + * responsibility of validating + */ + public boolean isValidateRoot() + { + return ! (getParent() instanceof JViewport); + } } diff --git a/javax/swing/JTextPane.java b/javax/swing/JTextPane.java index 7c95d7682..c0a5f80cf 100644 --- a/javax/swing/JTextPane.java +++ b/javax/swing/JTextPane.java @@ -327,9 +327,11 @@ public class JTextPane if (start == dot && end == dot) // There is no selection, update insertAttributes instead { - MutableAttributeSet inputAttributes = - getStyledEditorKit().getInputAttributes(); - inputAttributes.addAttributes(attribute); + MutableAttributeSet inputAttributes = + getStyledEditorKit().getInputAttributes(); + if (replace) + inputAttributes.removeAttributes(inputAttributes); + inputAttributes.addAttributes(attribute); } else getStyledDocument().setCharacterAttributes(start, end - start, attribute, diff --git a/javax/swing/JTree.java b/javax/swing/JTree.java index d566f5351..f616474eb 100644 --- a/javax/swing/JTree.java +++ b/javax/swing/JTree.java @@ -1482,6 +1482,9 @@ public class JTree extends JComponent implements Scrollable, Accessible setModel(model); setSelectionModel(new EmptySelectionModel()); selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + + // The root node appears expanded by default. + nodeStates.put(new TreePath(model.getRoot()), EXPANDED); } /** @@ -2497,8 +2500,9 @@ public class JTree extends JComponent implements Scrollable, Accessible { TreeUI ui = getUI(); - if (ui != null) - return ui.stopEditing(this); + if (isEditing()) + if (ui != null) + return ui.stopEditing(this); return false; } @@ -2506,9 +2510,10 @@ public class JTree extends JComponent implements Scrollable, Accessible public void cancelEditing() { TreeUI ui = getUI(); - - if (ui != null) - ui.cancelEditing(this); + + if (isEditing()) + if (ui != null) + ui.cancelEditing(this); } public void startEditingAtPath(TreePath path) @@ -2738,7 +2743,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * * @return a String representation of this JTree */ - public String paramString() + protected String paramString() { // TODO: this is completely legal, but it would possibly be nice // to return some more content, like the tree structure, some properties diff --git a/javax/swing/JViewport.java b/javax/swing/JViewport.java index debb5742e..fad940f13 100644 --- a/javax/swing/JViewport.java +++ b/javax/swing/JViewport.java @@ -113,7 +113,7 @@ public class JViewport extends JComponent implements Accessible /** * Creates a new instance of AccessibleJViewport. */ - public AccessibleJViewport() + protected AccessibleJViewport() { // Nothing to do here. } @@ -251,6 +251,13 @@ public class JViewport extends JComponent implements Accessible */ boolean sizeChanged = true; + /** + * Indicates if this JViewport is the paint root or not. If it is not, then + * we may not assume that the offscreen buffer still has the right content + * because parent components may have cleared the background already. + */ + private boolean isPaintRoot = false; + /** * Initializes the default setting for the scrollMode property. */ @@ -258,7 +265,7 @@ public class JViewport extends JComponent implements Accessible { String scrollModeProp = SystemProperties.getProperty("gnu.javax.swing.JViewport.scrollMode", - "BLIT"); + "BACKINGSTORE"); if (scrollModeProp.equalsIgnoreCase("simple")) defaultScrollMode = SIMPLE_SCROLL_MODE; else if (scrollModeProp.equalsIgnoreCase("backingstore")) @@ -635,11 +642,19 @@ public class JViewport extends JComponent implements Accessible */ public void repaint(long tm, int x, int y, int w, int h) { - Component parent = getParent(); - if (parent != null) - { - parent.repaint(tm, x + getX(), y + getY(), w, h); - } +// Component parent = getParent(); +// if (parent != null) +// parent.repaint(tm, x + getX(), y + getY(), w, h); +// else +// super.repaint(tm, x, y, w, h); + + // The specs suggest to implement something like the above. This however + // breaks blit painting, because the parent (most likely a JScrollPane) + // clears the background of the offscreen area of the JViewport, thus + // destroying the pieces that we want to clip. So we simply call super here + // instead. + super.repaint(tm, x, y, w, h); + } protected void addImpl(Component comp, Object constraints, int index) @@ -710,9 +725,11 @@ public class JViewport extends JComponent implements Accessible protected boolean computeBlit(int dx, int dy, Point blitFrom, Point blitTo, Dimension blitSize, Rectangle blitPaint) { - if ((dx != 0 && dy != 0) || damaged) + if ((dx != 0 && dy != 0) || (dy == 0 && dy == 0) || damaged) // We cannot blit if the viewport is scrolled in both directions at - // once. + // once. Also, we do not want to blit if the viewport is not scrolled at + // all, because that probably means the view component repaints itself + // and the buffer needs updating. return false; Rectangle portBounds = SwingUtilities.calculateInnerArea(this, getBounds()); @@ -854,6 +871,11 @@ public class JViewport extends JComponent implements Accessible // everything. else { + // If the image has not been scrolled at all, only the changed + // clip must be updated in the buffer. + if (dx==0 && dy==0) + g2.setClip(g.getClip()); + paintSimple(g2); } g2.dispose(); @@ -877,23 +899,43 @@ public class JViewport extends JComponent implements Accessible */ void paintBlit(Graphics g) { - // We cannot perform blitted painting as it is described in Sun's API docs. - // There it is suggested that this painting method should blit directly - // on the parent window's surface. This is not possible because when using - // Swing's double buffering (at least our implementation), it would - // immediatly be painted when the buffer is painted on the screen. For this - // to work we would need a kind of hole in the buffer image. And honestly - // I find this method not very elegant. - // The alternative, blitting directly on the buffer image, is also not - // possible because the buffer image gets cleared everytime when an opaque - // parent component is drawn on it. - - // What we do instead is falling back to the backing store approach which - // is in fact a mixed blitting/backing store approach where the blitting - // is performed on the backing store image and this is then drawn to the - // graphics context. This is very robust and works independent of the - // painting mechanism that is used by Swing. And it should have comparable - // performance characteristics as the blitting method. - paintBackingStore(g); + // First we move the part that remains visible after scrolling, then + // we only need to paint the bit that becomes newly visible. + Point viewPosition = getViewPosition(); + int dx = viewPosition.x - lastPaintPosition.x; + int dy = viewPosition.y - lastPaintPosition.y; + boolean canBlit = computeBlit(dx, dy, cachedBlitFrom, cachedBlitTo, + cachedBlitSize, cachedBlitPaint); + if (canBlit && isPaintRoot) + { + // Copy the part that remains visible during scrolling. + g.copyArea(cachedBlitFrom.x, cachedBlitFrom.y, + cachedBlitSize.width, cachedBlitSize.height, + cachedBlitTo.x - cachedBlitFrom.x, + cachedBlitTo.y - cachedBlitFrom.y); + // Now paint the part that becomes newly visible. + g.setClip(cachedBlitPaint.x, cachedBlitPaint.y, + cachedBlitPaint.width, cachedBlitPaint.height); + paintSimple(g); + } + // If blitting is not possible for some reason, fall back to repainting + // everything. + else + { + paintSimple(g); + } + lastPaintPosition.setLocation(getViewPosition()); + } + + /** + * Overridden from JComponent to set the {@link #isPaintRoot} flag. + * + * @param r the rectangle to paint + */ + void paintImmediately2(Rectangle r) + { + isPaintRoot = true; + super.paintImmediately2(r); + isPaintRoot = false; } } diff --git a/javax/swing/JWindow.java b/javax/swing/JWindow.java index cc0ac7fd9..19d830ed1 100644 --- a/javax/swing/JWindow.java +++ b/javax/swing/JWindow.java @@ -68,7 +68,7 @@ public class JWindow extends Window implements Accessible, RootPaneContainer /** * Creates a new instance of AccessibleJWindow. */ - public AccessibleJWindow() + protected AccessibleJWindow() { super(); // Nothing to do here. @@ -86,33 +86,73 @@ public class JWindow extends Window implements Accessible, RootPaneContainer protected AccessibleContext accessibleContext; + /** + * Creates a new JWindow that has a shared invisible owner frame + * as its parent. + */ public JWindow() { - super(SwingUtilities.getOwnerFrame()); + super(SwingUtilities.getOwnerFrame(null)); windowInit(); } + /** + * Creates a new JWindow that uses the specified graphics + * environment. This can be used to open a window on a different screen for + * example. + * + * @param gc the graphics environment to use + */ public JWindow(GraphicsConfiguration gc) { - super(SwingUtilities.getOwnerFrame(), gc); + super(SwingUtilities.getOwnerFrame(null), gc); windowInit(); } - + + /** + * Creates a new JWindow that has the specified + * owner frame. If owner is null, then + * an invisible shared owner frame is installed as owner frame. + * + * @param owner the owner frame of this window; if null a shared + * invisible owner frame is used + */ public JWindow(Frame owner) { - super(owner); + super(SwingUtilities.getOwnerFrame(owner)); windowInit(); } + /** + * Creates a new JWindow that has the specified + * owner window. If owner is null, + * then an invisible shared owner frame is installed as owner frame. + * + * @param owner the owner window of this window; if null a + * shared invisible owner frame is used + */ public JWindow(Window owner) { - super(owner); + super(SwingUtilities.getOwnerFrame(owner)); windowInit(); } + /** + * Creates a new JWindow for the given graphics configuration + * and that has the specified owner window. If + * owner is null, then an invisible shared owner + * frame is installed as owner frame. + * + * The gc parameter can be used to open the window on a + * different screen for example. + * + * @param owner the owner window of this window; if null a + * shared invisible owner frame is used + * @param gc the graphics configuration to use + */ public JWindow(Window owner, GraphicsConfiguration gc) { - super(owner, gc); + super(SwingUtilities.getOwnerFrame(owner), gc); windowInit(); } diff --git a/javax/swing/Popup.java b/javax/swing/Popup.java index 203ee3c9b..c3de69e05 100644 --- a/javax/swing/Popup.java +++ b/javax/swing/Popup.java @@ -161,7 +161,7 @@ public class Popup super(owner, contents, x, y); this.contents = contents; - window = new JWindow(); + window = new JWindow(SwingUtilities.getWindowAncestor(owner)); window.getContentPane().add(contents); window.setLocation(x, y); window.setFocusableWindowState(false); diff --git a/javax/swing/PopupFactory.java b/javax/swing/PopupFactory.java index 7bb2529cd..b32620599 100644 --- a/javax/swing/PopupFactory.java +++ b/javax/swing/PopupFactory.java @@ -152,13 +152,18 @@ public class PopupFactory // If we have a root pane and the contents fits within the root pane and // lightweight popups are enabled, than we can use a lightweight popup. JRootPane root = SwingUtilities.getRootPane(owner); - Point rootLoc = root.getLocationOnScreen(); - Dimension contentsSize = contents.getSize(); - Dimension rootSize = root.getSize(); - if (x >= rootLoc.x && y > rootLoc.y - && (x - rootLoc.x) + contentsSize.width < rootSize.width - && (y - rootLoc.y) + contentsSize.height < rootSize.height) - popup = new Popup.LightweightPopup(owner, contents, x, y); + if (root != null) + { + Point rootLoc = root.getLocationOnScreen(); + Dimension contentsSize = contents.getSize(); + Dimension rootSize = root.getSize(); + if (x >= rootLoc.x && y > rootLoc.y + && (x - rootLoc.x) + contentsSize.width < rootSize.width + && (y - rootLoc.y) + contentsSize.height < rootSize.height) + popup = new Popup.LightweightPopup(owner, contents, x, y); + else + popup = new Popup.JWindowPopup(owner, contents, x, y); + } else popup = new Popup.JWindowPopup(owner, contents, x, y); return popup; diff --git a/javax/swing/RepaintManager.java b/javax/swing/RepaintManager.java index 0be81053d..33a42cd1b 100644 --- a/javax/swing/RepaintManager.java +++ b/javax/swing/RepaintManager.java @@ -40,6 +40,7 @@ package javax.swing; import java.awt.Component; import java.awt.Dimension; +import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.image.VolatileImage; @@ -48,6 +49,8 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; +import java.util.Map; +import java.util.Set; import java.util.WeakHashMap; /** @@ -62,6 +65,7 @@ import java.util.WeakHashMap; * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html">this * document for more details.

      * + * @author Roman Kennke (kennke@aicas.com) * @author Graydon Hoare (graydon@redhat.com) */ public class RepaintManager @@ -84,7 +88,7 @@ public class RepaintManager * swing paint thread, which revalidates all invalid components and * repaints any damage in the swing scene.

      */ - protected class RepaintWorker + private class RepaintWorker implements Runnable { @@ -107,12 +111,18 @@ public class RepaintManager public void run() { - ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); - RepaintManager rm = - (RepaintManager) currentRepaintManagers.get(threadGroup); - setLive(false); - rm.validateInvalidComponents(); - rm.paintDirtyRegions(); + try + { + ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); + RepaintManager rm = + (RepaintManager) currentRepaintManagers.get(threadGroup); + rm.validateInvalidComponents(); + rm.paintDirtyRegions(); + } + finally + { + setLive(false); + } } } @@ -135,41 +145,23 @@ public class RepaintManager * @param o1 the first component * @param o2 the second component * - * @return a negative integer, if o1 is higher in the - * hierarchy than o2, zero, if both are at the same - * level and a positive integer, if o1 is deeper in - * the hierarchy than o2 + * @return a negative integer, if o1 is bigger in than + * o2, zero, if both are at the same size and a + * positive integer, if o1 is smaller than + * o2 */ public int compare(Object o1, Object o2) { if (o1 instanceof JComponent && o2 instanceof JComponent) { JComponent c1 = (JComponent) o1; + Rectangle d1 = (Rectangle) dirtyComponents.get(c1); JComponent c2 = (JComponent) o2; - return getDepth(c1) - getDepth(c2); + Rectangle d2 = (Rectangle) dirtyComponents.get(c2); + return d2.width * d2.height - d1.width * d1.height; } - else - throw new ClassCastException("This comparator can only be used with " - + "JComponents"); - } - - /** - * Computes the depth for a given JComponent. - * - * @param c the component to compute the depth for - * - * @return the depth of the component - */ - private int getDepth(JComponent c) - { - Component comp = c; - int depth = 0; - while (comp != null) - { - comp = comp.getParent(); - depth++; - } - return depth; + throw new ClassCastException("This comparator can only be used with " + + "JComponents"); } } @@ -179,6 +171,9 @@ public class RepaintManager * to exactly one rectangle. When more regions are marked as dirty on a * component, they are union'ed with the existing rectangle. * + * This is package private to avoid a synthetic accessor method in inner + * class. + * * @see #addDirtyRegion * @see #getDirtyRegion * @see #isCompletelyDirty @@ -187,18 +182,10 @@ public class RepaintManager */ HashMap dirtyComponents; - HashMap workDirtyComponents; - - /** - * Stores the order in which the components get repainted. - */ - ArrayList repaintOrder; - ArrayList workRepaintOrder; - /** * The comparator used for ordered inserting into the repaintOrder list. */ - Comparator comparator; + private transient Comparator comparator; /** * A single, shared instance of the helper class. Any methods which mark @@ -209,7 +196,7 @@ public class RepaintManager * @see #addDirtyRegion * @see #addInvalidComponent */ - RepaintWorker repaintWorker; + private RepaintWorker repaintWorker; /** * The set of components which need revalidation, in the "layout" sense. @@ -221,8 +208,7 @@ public class RepaintManager * @see #removeInvalidComponent * @see #validateInvalidComponents */ - ArrayList invalidComponents; - ArrayList workInvalidComponents; + private ArrayList invalidComponents; /** * Whether or not double buffering is enabled on this repaint @@ -232,17 +218,27 @@ public class RepaintManager * @see #isDoubleBufferingEnabled * @see #setDoubleBufferingEnabled */ - boolean doubleBufferingEnabled; + private boolean doubleBufferingEnabled; - /** - * The current offscreen buffer. This is reused for all requests for - * offscreen drawing buffers. It grows as necessary, up to {@link - * #doubleBufferMaximumSize}, but there is only one shared instance. - * - * @see #getOffscreenBuffer - * @see #doubleBufferMaximumSize + /** + * The offscreen buffers. This map holds one offscreen buffer per + * Window/Applet and releases them as soon as the Window/Applet gets garbage + * collected. + */ + private WeakHashMap offscreenBuffers; + + /** + * Indicates if the RepaintManager is currently repainting an area. + */ + private boolean repaintUnderway; + + /** + * This holds buffer commit requests when the RepaintManager is working. + * This maps Component objects (the top level components) to Rectangle + * objects (the area of the corresponding buffer that must be blitted on + * the component). */ - Image doubleBuffer; + private HashMap commitRequests; /** * The maximum width and height to allocate as a double buffer. Requests @@ -252,7 +248,7 @@ public class RepaintManager * @see #getDoubleBufferMaximumSize * @see #setDoubleBufferMaximumSize */ - Dimension doubleBufferMaximumSize; + private Dimension doubleBufferMaximumSize; /** @@ -261,14 +257,13 @@ public class RepaintManager public RepaintManager() { dirtyComponents = new HashMap(); - workDirtyComponents = new HashMap(); - repaintOrder = new ArrayList(); - workRepaintOrder = new ArrayList(); invalidComponents = new ArrayList(); - workInvalidComponents = new ArrayList(); repaintWorker = new RepaintWorker(); doubleBufferMaximumSize = new Dimension(2000,2000); doubleBufferingEnabled = true; + offscreenBuffers = new WeakHashMap(); + repaintUnderway = false; + commitRequests = new HashMap(); } /** @@ -346,9 +341,9 @@ public class RepaintManager * * @see #removeInvalidComponent */ - public synchronized void addInvalidComponent(JComponent component) + public void addInvalidComponent(JComponent component) { - Component ancestor = component.getParent(); + Component ancestor = component; while (ancestor != null && (! (ancestor instanceof JComponent) @@ -363,8 +358,11 @@ public class RepaintManager if (invalidComponents.contains(component)) return; - invalidComponents.add(component); - + synchronized (invalidComponents) + { + invalidComponents.add(component); + } + if (! repaintWorker.isLive()) { repaintWorker.setLive(true); @@ -379,9 +377,12 @@ public class RepaintManager * * @see #addInvalidComponent */ - public synchronized void removeInvalidComponent(JComponent component) + public void removeInvalidComponent(JComponent component) { - invalidComponents.remove(component); + synchronized (invalidComponents) + { + invalidComponents.remove(component); + } } /** @@ -402,17 +403,21 @@ public class RepaintManager * @see #markCompletelyClean * @see #markCompletelyDirty */ - public synchronized void addDirtyRegion(JComponent component, int x, int y, - int w, int h) + public void addDirtyRegion(JComponent component, int x, int y, + int w, int h) { - if (w == 0 || h == 0 || !component.isShowing()) + if (w <= 0 || h <= 0 || !component.isShowing()) return; + Rectangle r = new Rectangle(x, y, w, h); if (dirtyComponents.containsKey(component)) - r = r.union((Rectangle)dirtyComponents.get(component)); - else - insertInRepaintOrder(component); - dirtyComponents.put(component, r); + r = r.union((Rectangle) dirtyComponents.get(component)); + + synchronized (dirtyComponents) + { + dirtyComponents.put(component, r); + } + if (! repaintWorker.isLive()) { repaintWorker.setLive(true); @@ -420,22 +425,6 @@ public class RepaintManager } } - /** - * Inserts a component into the repaintOrder list in an ordered fashion, - * using a binary search. - * - * @param c the component to be inserted - */ - private void insertInRepaintOrder(JComponent c) - { - if (comparator == null) - comparator = new ComponentComparator(); - int insertIndex = Collections.binarySearch(repaintOrder, c, comparator); - if (insertIndex < 0) - insertIndex = -(insertIndex + 1); - repaintOrder.add(insertIndex, c); - } - /** * Get the dirty region associated with a component, or null * if the component has no dirty region. @@ -489,7 +478,7 @@ public class RepaintManager */ public void markCompletelyClean(JComponent component) { - synchronized (this) + synchronized (dirtyComponents) { dirtyComponents.remove(component); } @@ -523,63 +512,58 @@ public class RepaintManager */ public void validateInvalidComponents() { - // In order to keep the blocking of application threads minimal, we switch - // the invalidComponents field with the workInvalidComponents field and - // work with the workInvalidComponents field. - synchronized(this) - { - ArrayList swap = invalidComponents; - invalidComponents = workInvalidComponents; - workInvalidComponents = swap; - } - for (Iterator i = workInvalidComponents.iterator(); i.hasNext(); ) + // We don't use an iterator here because that would fail when there are + // components invalidated during the validation of others, which happens + // quite frequently. Instead we synchronize the access a little more. + while (invalidComponents.size() > 0) { - Component comp = (Component) i.next(); - // Find validate root. - while ((!(comp instanceof JComponent) - || !((JComponent) comp).isValidateRoot()) - && comp.getParent() != null) - comp = comp.getParent(); - - // Validate the validate root. + Component comp; + synchronized (invalidComponents) + { + comp = (Component) invalidComponents.remove(0); + } + // Validate the validate component. if (! (comp.isVisible() && comp.isShowing())) continue; comp.validate(); } - workInvalidComponents.clear(); } /** * Repaint all regions of all components which have been marked dirty in * the {@link #dirtyComponents} table. */ - public synchronized void paintDirtyRegions() + public void paintDirtyRegions() { - // In order to keep the blocking of application threads minimal, we switch - // the dirtyComponents field with the workdirtyComponents field and the - // repaintOrder field with the workRepaintOrder field and work with the - // work* fields. - synchronized(this) - { - ArrayList swap = workRepaintOrder; - workRepaintOrder = repaintOrder; - repaintOrder = swap; - HashMap swap2 = workDirtyComponents; - workDirtyComponents = dirtyComponents; - dirtyComponents = swap2; - } - for (Iterator i = workRepaintOrder.iterator(); i.hasNext();) + // Short circuit if there is nothing to paint. + if (dirtyComponents.size() == 0) + return; + + synchronized (dirtyComponents) { - JComponent comp = (JComponent) i.next(); - // If a component is marked completely clean in the meantime, then skip - // it. - Rectangle damaged = (Rectangle) workDirtyComponents.get(comp); - if (damaged == null || damaged.isEmpty()) - continue; - comp.paintImmediately(damaged); + // We sort the components by their size here. This way we have a good + // chance that painting the bigger components also paints the smaller + // components and we don't need to paint them twice. + ArrayList repaintOrder = new ArrayList(dirtyComponents.size()); + repaintOrder.addAll(dirtyComponents.keySet()); + if (comparator == null) + comparator = new ComponentComparator(); + Collections.sort(repaintOrder, comparator); + repaintUnderway = true; + for (Iterator i = repaintOrder.iterator(); i.hasNext();) + { + JComponent comp = (JComponent) i.next(); + // If a component is marked completely clean in the meantime, then skip + // it. + Rectangle damaged = (Rectangle) dirtyComponents.get(comp); + if (damaged == null || damaged.isEmpty()) + continue; + comp.paintImmediately(damaged); + dirtyComponents.remove(comp); + } + repaintUnderway = false; + commitRemainingBuffers(); } - workRepaintOrder.clear(); - workDirtyComponents.clear(); } /** @@ -592,21 +576,92 @@ public class RepaintManager * @param proposedHeight The proposed height of the offscreen buffer * * @return A shared offscreen buffer for painting - * - * @see #doubleBuffer */ public Image getOffscreenBuffer(Component component, int proposedWidth, int proposedHeight) { - if (doubleBuffer == null - || (((doubleBuffer.getWidth(null) < proposedWidth) - || (doubleBuffer.getHeight(null) < proposedHeight)) - && (proposedWidth < doubleBufferMaximumSize.width) - && (proposedHeight < doubleBufferMaximumSize.height))) + Component root = SwingUtilities.getRoot(component); + Image buffer = (Image) offscreenBuffers.get(root); + if (buffer == null + || ((buffer.getWidth(null) < proposedWidth + || buffer.getHeight(null) < proposedHeight) + && proposedWidth < doubleBufferMaximumSize.width + && proposedHeight < doubleBufferMaximumSize.height)) + { + buffer = component.createImage(proposedWidth, proposedHeight); + offscreenBuffers.put(root, buffer); + } + return buffer; + } + + /** + * Blits the back buffer of the specified root component to the screen. If + * the RepaintManager is currently working on a paint request, the commit + * requests are queued up and committed at once when the paint request is + * done (by {@link #commitRemainingBuffers}). This is package private because + * it must get called by JComponent. + * + * @param root the component, either a Window or an Applet instance + * @param area the area to paint on screen + */ + void commitBuffer(Component root, Rectangle area) + { + // We synchronize on dirtyComponents here because that is what + // paintDirtyRegions also synchronizes on while painting. + synchronized (dirtyComponents) + { + // If the RepaintManager is not currently painting, then directly + // blit the requested buffer on the screen. + if (! repaintUnderway) + { + Graphics g = root.getGraphics(); + Image buffer = (Image) offscreenBuffers.get(root); + Rectangle clip = g.getClipBounds(); + area = SwingUtilities.computeIntersection(clip.x, clip.y, + clip.width, clip.height, + area); + int dx1 = area.x; + int dy1 = area.y; + int dx2 = area.x + area.width; + int dy2 = area.y + area.height; + g.drawImage(buffer, dx1, dy1, dx2, dy2, + dx1, dy1, dx2, dy2, root); + g.dispose(); + } + // Otherwise queue this request up, until all the RepaintManager work + // is done. + else + { + Rectangle commitArea; + if (commitRequests.containsKey(root)) + commitArea = area.union((Rectangle) commitRequests.get(root)); + else + commitArea = area; + commitRequests.put(root, commitArea); + } + } + } + + /** + * Commits the queued up back buffers to screen all at once. + */ + private void commitRemainingBuffers() + { + // We synchronize on dirtyComponents here because that is what + // paintDirtyRegions also synchronizes on while painting. + synchronized (dirtyComponents) { - doubleBuffer = component.createImage(proposedWidth, proposedHeight); + Set entrySet = commitRequests.entrySet(); + Iterator i = entrySet.iterator(); + while (i.hasNext()) + { + Map.Entry entry = (Map.Entry) i.next(); + Component root = (Component) entry.getKey(); + Rectangle area = (Rectangle) entry.getValue(); + commitBuffer(root, area); + i.remove(); + } } - return doubleBuffer; } /** diff --git a/javax/swing/ScrollPaneLayout.java b/javax/swing/ScrollPaneLayout.java index edf1f1f42..b00b5c4e7 100644 --- a/javax/swing/ScrollPaneLayout.java +++ b/javax/swing/ScrollPaneLayout.java @@ -285,20 +285,20 @@ public class ScrollPaneLayout // Sun's implementation simply throws a ClassCastException if // parent is no JScrollPane, so do we. JScrollPane sc = (JScrollPane) parent; - Dimension viewportSize = viewport.getMinimumSize(); - int width = viewportSize.width; - int height = viewportSize.height; - if (hsb != null && hsb.isVisible()) - height += hsb.getMinimumSize().height; - if (vsb != null && vsb.isVisible()) - width += vsb.getMinimumSize().width; - if (rowHead != null && rowHead.isVisible()) - width += rowHead.getMinimumSize().width; - if (colHead != null && colHead.isVisible()) - height += colHead.getMinimumSize().height; Insets i = sc.getInsets(); - return new Dimension(width + i.left + i.right, - height + i.top + i.bottom); + Dimension viewportMinSize = sc.getViewport().getMinimumSize(); + + int width = i.left + i.right + viewportMinSize.width; + if (sc.getVerticalScrollBarPolicy() + != JScrollPane.VERTICAL_SCROLLBAR_NEVER) + width += sc.getVerticalScrollBar().getMinimumSize().width; + + int height = i.top + i.bottom + viewportMinSize.height; + if (sc.getHorizontalScrollBarPolicy() + != JScrollPane.HORIZONTAL_SCROLLBAR_NEVER) + height += sc.getHorizontalScrollBar().getMinimumSize().height; + + return new Dimension(width, height); } /** diff --git a/javax/swing/SpinnerDateModel.java b/javax/swing/SpinnerDateModel.java index c0de7d55c..a92f5a49e 100644 --- a/javax/swing/SpinnerDateModel.java +++ b/javax/swing/SpinnerDateModel.java @@ -1,5 +1,5 @@ /* SpinnerDateModel.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,21 +42,37 @@ import java.io.Serializable; import java.util.Calendar; import java.util.Date; +import javax.swing.event.ChangeEvent; + /** - * SpinnerDateModel - * - * Implements a SpinnerModel for dates, rotating a calendar field such as - * month, year, day, week, hour, minute. + * A date model used by the {@link JSpinner} component. This implements a + * spinner model for dates, rotating a calendar field such as month, year, + * day, week, hour, minute. * * @author Sven de Marothy - * @version 0.1 (first implementation) + * @since 1.4 */ public class SpinnerDateModel extends AbstractSpinnerModel implements Serializable { + /** The current date. */ private Calendar date; + + /** + * The start or earliest permitted date (null for no + * minimum). + */ private Comparable start; + + /** + * The end or latest permitted date (null for no + * maximum). + */ private Comparable end; + + /** + * The calendar field used to calculate the previous or next date. + */ private int calendarField; /** @@ -66,8 +82,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel private static final long serialVersionUID = -4802518107105940612L; /** - * Constructs a SpinnerDateModel using the current date, - * no start or end limit, and Calendar.DAY_OF_MONTH as the calendar field. + * Constructs a SpinnerDateModel using the current date, + * no start or end limit, and {@link Calendar#DAY_OF_MONTH} as the calendar + * field. */ public SpinnerDateModel() { @@ -87,6 +104,12 @@ public class SpinnerDateModel extends AbstractSpinnerModel public SpinnerDateModel(Date value, Comparable start, Comparable end, int calendarField) { + if (value == null) + throw new IllegalArgumentException("Null 'value' argument."); + if (start != null && start.compareTo(value) > 0) + throw new IllegalArgumentException("Require value on or after start."); + if (end != null && end.compareTo(value) < 0) + throw new IllegalArgumentException("Require value on or before end."); date = Calendar.getInstance(); date.setTime(value); this.start = start; @@ -95,7 +118,10 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the value of the Calendar field to spin. + * Returns the {@link Calendar} field used to calculate the previous and + * next dates in the sequence. + * + * @return The date field code. */ public int getCalendarField() { @@ -103,8 +129,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the current date in the sequence. - * @return a Date object. + * Returns the current date. + * + * @return The current date. */ public Date getDate() { @@ -112,8 +139,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the starting limit of the SpinnerModel. - * @return a Date object, or null if there is no limit. + * Returns the start date, or null if there is no minimum date. + * + * @return The start date. */ public Comparable getStart() { @@ -121,8 +149,9 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the end limit of the SpinnerModel. - * @return a Date object, or null if there is no limit. + * Returns the end date, or null if there is no maximum date. + * + * @return The end date. */ public Comparable getEnd() { @@ -130,9 +159,10 @@ public class SpinnerDateModel extends AbstractSpinnerModel } /** - * Returns the current date in the sequence, - * this method returns the same as getDate(). - * @return a Date object. + * Returns the current date in the sequence (this method returns the same as + * {@link #getDate()}. + * + * @return The current date. */ public Object getValue() { @@ -141,8 +171,10 @@ public class SpinnerDateModel extends AbstractSpinnerModel /** * Returns the next date in the sequence, or null if the - * next date is equal to or past the end limit. - * @return a Date object, or null. + * next date is after the end date. The current date is not changed. + * + * @return The next date, or null if the current value is + * the latest date represented by the model. */ public Object getNextValue() { @@ -152,14 +184,17 @@ public class SpinnerDateModel extends AbstractSpinnerModel Date nextDate = nextCal.getTime(); if (end != null) if (end.compareTo(nextDate) < 0) - return null; + return null; return nextDate; } /** * Returns the previous date in the sequence, or null if the - * next date is equal to or past the end limit. - * @return a Date object, or null. + * previous date is prior to the start date. The current date is not + * changed. + * + * @return The previous date, or null if the current value is + * the earliest date represented by the model. */ public Object getPreviousValue() { @@ -167,16 +202,21 @@ public class SpinnerDateModel extends AbstractSpinnerModel prevCal.setTime(date.getTime()); prevCal.roll(calendarField, false); Date prevDate = prevCal.getTime(); - if (end != null) - if (end.compareTo(prevDate) > 0) - return null; + if (start != null) + if (start.compareTo(prevDate) > 0) + return null; return prevDate; } /** - * Sets the date field to change. It must be a valid Calendar field, - * excluding Calendar.ZONE_OFFSET and Calendar.DST_OFFSET. - * @param calendarField - the calendar field to set. + * Sets the date field to change when calculating the next and previous + * values. It must be a valid {@link Calendar} field, excluding + * {@link Calendar#ZONE_OFFSET} and {@link Calendar#DST_OFFSET}. + * + * @param calendarField the calendar field to set. + * + * @throws IllegalArgumentException if calendarField is not + * a valid code. */ public void setCalendarField(int calendarField) { @@ -187,51 +227,67 @@ public class SpinnerDateModel extends AbstractSpinnerModel if (this.calendarField != calendarField) { - this.calendarField = calendarField; - fireStateChanged(); + this.calendarField = calendarField; + fireStateChanged(); } } /** - * Sets the starting date limit for the sequence. - * - * @param start - a Date object of the limit date, - * or null for no limit. + * Sets the start date and, if the new date is different to the old date, + * sends a {@link ChangeEvent} to all registered listeners. A + * null date is interpreted as "no start date". No check + * is made to ensure that the new start date is on or before the current + * date - the caller is responsible for ensuring that this relationship + * holds. + * + * @param start the new start date (null permitted). */ public void setStart(Comparable start) { if (this.start != start) { - this.start = start; - fireStateChanged(); + this.start = start; + fireStateChanged(); } } /** - * Sets the end date limit for the sequence. - * - * @param end - a Date object of the limit date, - * or null for no limit. + * Sets the end date and, if the new date is different to the old date, + * sends a {@link ChangeEvent} to all registered listeners. A + * null date is interpreted as "no end date". No check + * is made to ensure that the new end date is on or after the current date - + * the caller is responsible for ensuring that this relationship holds. + * + * @param end the new end date (null permitted). */ public void setEnd(Comparable end) { if (this.end != end) { - this.end = end; - fireStateChanged(); + this.end = end; + fireStateChanged(); } } /** - * Sets the current date in the sequence. + * Sets the current date and, if the new value is different to the old + * value, sends a {@link ChangeEvent} to all registered listeners. * - * @param value - a Date object. + * @param value the new date (null not permitted, must be an + * instance of Date). + * + * @throws IllegalArgumentException if value is not an instance + * of Date. */ public void setValue(Object value) { if (! (value instanceof Date) || value == null) throw new IllegalArgumentException("Value not a date."); - date.setTime((Date) value); - fireStateChanged(); + + if (!date.getTime().equals(value)) + { + date.setTime((Date) value); + fireStateChanged(); + } } } diff --git a/javax/swing/SpinnerNumberModel.java b/javax/swing/SpinnerNumberModel.java index 2274c9ec0..389c536e4 100644 --- a/javax/swing/SpinnerNumberModel.java +++ b/javax/swing/SpinnerNumberModel.java @@ -1,5 +1,5 @@ /* SpinnerNumberModel.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,11 +39,13 @@ package javax.swing; import java.io.Serializable; +import javax.swing.event.ChangeEvent; + /** - * SpinnerNumberModel + * A model used by the {@link JSpinner} component. * * @author Ka-Hing Cheung - * @version 1.0 + * @since 1.4 */ public class SpinnerNumberModel extends AbstractSpinnerModel implements Serializable @@ -53,16 +55,16 @@ public class SpinnerNumberModel extends AbstractSpinnerModel */ private static final long serialVersionUID = 7279176385485777821L; - /** DOCUMENT ME! */ + /** The current value. */ private Number value; - /** DOCUMENT ME! */ + /** The minimum value (or null). */ private Comparable minimum; - /** DOCUMENT ME! */ + /** The maximum value (or null). */ private Comparable maximum; - /** DOCUMENT ME! */ + /** The step size. */ private Number stepSize; /** @@ -75,14 +77,14 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Creates a SpinnerNumberModel with double precision + * Creates a SpinnerNumberModel with double precision. * * @param value the initial value * @param minimum the minimum value * @param maximum the maximum value * @param stepSize the step size - * @throws IllegalArgumentException if minimum <= value <= maximum does not - * hold + * @throws IllegalArgumentException if minimum <= value <= maximum does + * not hold. */ public SpinnerNumberModel(double value, double minimum, double maximum, double stepSize) @@ -92,14 +94,14 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Creates a SpinnerNumberModel with integer precision + * Creates a SpinnerNumberModel with integer precision. * * @param value the initial value * @param minimum the minimum value * @param maximum the maximum value * @param stepSize the step size - * @throws IllegalArgumentException if minimum <= value <= maximum does not - * hold + * @throws IllegalArgumentException if minimum <= value <= maximum does + * not hold. */ public SpinnerNumberModel(int value, int minimum, int maximum, int stepSize) { @@ -108,16 +110,19 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Creates a SpinnerNumberModel with Numbers and - * Comparables. + * Creates a SpinnerNumberModel with the given attributes. * - * @param value the initial value - * @param minimum the minimum value, if null there's no minimum - * @param maximum the maximum value, if null there's no maximum - * @param stepSize the step size + * @param value the initial value. + * @param minimum the minimum value (null permitted). + * @param maximum the maximum value (null permitted). + * @param stepSize the step size. * * @throws IllegalArgumentException if minimum <= value <= maximum * does not hold + * @throws IllegalArgumentException if value is + * null. + * @throws IllegalArgumentException if stepSize is + * null. */ public SpinnerNumberModel(Number value, Comparable minimum, Comparable maximum, Number stepSize) @@ -128,33 +133,14 @@ public class SpinnerNumberModel extends AbstractSpinnerModel throw new IllegalArgumentException("value may not be null"); if (minimum != null) { - if (minimum.compareTo(value) > 0) - throw new IllegalArgumentException("minimum is not <= value"); + if (minimum.compareTo(value) > 0) + throw new IllegalArgumentException("minimum is not <= value"); } - else - minimum = new Comparable() - { - public int compareTo(Object obj) - { - return -1; - } - }; - - if (maximum != null) { - if (maximum.compareTo(value) < 0) - throw new IllegalArgumentException("maximum is not >= value"); + if (maximum.compareTo(value) < 0) + throw new IllegalArgumentException("maximum is not >= value"); } - else - maximum = new Comparable() - { - public int compareTo(Object obj) - { - return 1; - } - }; - this.value = value; this.stepSize = stepSize; @@ -163,26 +149,31 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Sets the new value and fire a change event + * Sets the current value and, if the new value is different to the old + * value, sends a {@link ChangeEvent} to all registered listeners. * - * @param value the new value + * @param value the new value (null not permitted, must be an + * instance of Number). * - * @throws IllegalArgumentException if minimum <= value <= maximum - * does not hold + * @throws IllegalArgumentException if value is not an instance + * of Number. */ public void setValue(Object value) { if (! (value instanceof Number)) throw new IllegalArgumentException("value must be a Number"); - this.value = (Number) value; - fireStateChanged(); + if (!this.value.equals(value)) + { + this.value = (Number) value; + fireStateChanged(); + } } /** - * Gets the current value + * Returns the current value. * - * @return the current value + * @return The current value. */ public Object getValue() { @@ -190,10 +181,12 @@ public class SpinnerNumberModel extends AbstractSpinnerModel } /** - * Gets the next value without changing the current value, or null if the - * current value is maximum. + * Returns the next value, or null if adding the step size to + * the current value results in a value greater than the maximum value. + * The current value is not changed. * - * @return the next value + * @return The next value, or null if the current value is the + * maximum value represented by this model. */ public Object getNextValue() { @@ -211,15 +204,21 @@ public class SpinnerNumberModel extends AbstractSpinnerModel num = new Short((short) (value.shortValue() + stepSize.shortValue())); else num = new Byte((byte) (value.byteValue() + stepSize.byteValue())); - - return maximum.compareTo(num) >= 0 ? num : null; + + // check upper bound if set + if ((maximum != null) && maximum.compareTo(num) < 0) + num = null; + + return num; } /** - * Gets the previous value without changing the current value, or null if - * the current value is minimum. + * Returns the previous value, or null if subtracting the + * step size from the current value results in a value less than the minimum + * value. The current value is not changed. * - * @return the previous value + * @return The previous value, or null if the current value + * is the minimum value represented by this model. */ public Object getPreviousValue() { @@ -237,62 +236,110 @@ public class SpinnerNumberModel extends AbstractSpinnerModel num = new Short((short) (value.shortValue() - stepSize.shortValue())); else num = new Byte((byte) (value.byteValue() - stepSize.byteValue())); + + // check lower bound if set + if ((minimum != null) && minimum.compareTo(num) > 0) + num = null; - return minimum.compareTo(num) <= 0 ? num : null; + return num; } /** - * DOCUMENT ME! + * Returns the current value. * - * @return DOCUMENT ME! + * @return The current value. */ public Number getNumber() { return value; } + /** + * Returns the minimum value, or null if there is no minimum. + * + * @return The minimum value. + */ public Comparable getMinimum() { return minimum; } + /** + * Sets the minimum value and, if the new value is different to the old + * value, sends a {@link ChangeEvent} to all registered listeners. A + * null value is interpreted as "no minimum value". No check + * is made to ensure that the new minimum is less than or equal to the + * current value, the caller is responsible for ensuring that this + * relationship holds. + * + * @param newMinimum the new minimum value (null permitted). + */ public void setMinimum(Comparable newMinimum) { - if (minimum != newMinimum) + if (minimum != null ? !minimum.equals(newMinimum) : newMinimum != null) { - minimum = newMinimum; - fireStateChanged(); + minimum = newMinimum; + fireStateChanged(); } } + /** + * Returns the maximum value, or null if there is no maximum. + * + * @return The maximum value. + */ public Comparable getMaximum() { return maximum; } + /** + * Sets the maximum value and, if the new value is different to the old + * value, sends a {@link ChangeEvent} to all registered listeners. A + * null value is interpreted as "no maximum value". No check + * is made to ensure that the new maximum is greater than or equal to the + * current value, the caller is responsible for ensuring that this + * relationship holds. + * + * @param newMaximum the new maximum (null permitted). + */ public void setMaximum(Comparable newMaximum) { - if (maximum != newMaximum) + if (maximum != null ? !maximum.equals(newMaximum) : newMaximum != null) { - maximum = newMaximum; - fireStateChanged(); + maximum = newMaximum; + fireStateChanged(); } } + /** + * Returns the step size. + * + * @return The step size. + */ public Number getStepSize() { return stepSize; } + /** + * Sets the step size and, if the new step size is different to the old + * step size, sends a {@link ChangeEvent} to all registered listeners. + * + * @param newStepSize the new step size (null not permitted). + * + * @throws IllegalArgumentException if newStepSize is + * null. + */ public void setStepSize(Number newStepSize) { if (newStepSize == null) throw new IllegalArgumentException(); - if (stepSize != newStepSize) + if (!stepSize.equals(newStepSize)) { - stepSize = newStepSize; - fireStateChanged(); + stepSize = newStepSize; + fireStateChanged(); } } } diff --git a/javax/swing/SwingUtilities.java b/javax/swing/SwingUtilities.java index f50f26b63..b58e5e0d8 100644 --- a/javax/swing/SwingUtilities.java +++ b/javax/swing/SwingUtilities.java @@ -83,31 +83,6 @@ public class SwingUtilities { // Do nothing. } - - /** - * Calculates the portion of the base rectangle which is inside the - * insets. - * - * @param base The rectangle to apply the insets to - * @param insets The insets to apply to the base rectangle - * @param ret A rectangle to use for storing the return value, or - * null - * - * @return The calculated area inside the base rectangle and its insets, - * either stored in ret or a new Rectangle if ret is null - * - * @see #calculateInnerArea - */ - public static Rectangle calculateInsetArea(Rectangle base, Insets insets, - Rectangle ret) - { - if (ret == null) - ret = new Rectangle(); - ret.setBounds(base.x + insets.left, base.y + insets.top, - base.width - (insets.left + insets.right), - base.height - (insets.top + insets.bottom)); - return ret; - } /** * Calculates the portion of the component's bounds which is inside the @@ -122,13 +97,18 @@ public class SwingUtilities * * @return The calculated area inside the component and its border * insets - * - * @see #calculateInsetArea */ public static Rectangle calculateInnerArea(JComponent c, Rectangle r) { Rectangle b = getLocalBounds(c); - return calculateInsetArea(b, c.getInsets(), r); + if (r == null) + r = new Rectangle(); + Insets i = c.getInsets(); + r.x = b.x + i.left; + r.width = b.width - i.left - i.right; + r.y = b.y + i.top; + r.height = b.height - i.top - i.bottom; + return r; } /** @@ -831,7 +811,6 @@ public class SwingUtilities if (icon == null) { - textIconGap = 0; iconR.width = 0; iconR.height = 0; } @@ -1021,11 +1000,16 @@ public class SwingUtilities * * @return The common Frame */ - static Frame getOwnerFrame() + static Window getOwnerFrame(Window owner) { - if (ownerFrame == null) - ownerFrame = new OwnerFrame(); - return ownerFrame; + Window result = owner; + if (result == null) + { + if (ownerFrame == null) + ownerFrame = new OwnerFrame(); + result = ownerFrame; + } + return result; } /** diff --git a/javax/swing/Timer.java b/javax/swing/Timer.java index 5ed310d4e..c6ed8842f 100644 --- a/javax/swing/Timer.java +++ b/javax/swing/Timer.java @@ -68,11 +68,11 @@ public class Timer public void run() { if (logTimers) - System.out.println("javax.swing.Timer -> queueEvent()"); + System.out.println("javax.swing.Timer -> queueEvent()"); queueEvent(); if (!repeats) - task = null; + task = null; } } @@ -141,8 +141,9 @@ public class Timer /** * The task that calls queueEvent(). When null this Timer is stopped. + * This is package private to avoid synthetic accessor method. */ - private Task task; + Task task; /** * This object manages a "queue" of virtual actionEvents, maintained as a diff --git a/javax/swing/ToolTipManager.java b/javax/swing/ToolTipManager.java index 289149fb6..c7de4db83 100644 --- a/javax/swing/ToolTipManager.java +++ b/javax/swing/ToolTipManager.java @@ -40,9 +40,6 @@ package javax.swing; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.LayoutManager; -import java.awt.Panel; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; diff --git a/javax/swing/UIManager.java b/javax/swing/UIManager.java index fbf1c7c79..bf8739dac 100644 --- a/javax/swing/UIManager.java +++ b/javax/swing/UIManager.java @@ -43,11 +43,11 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.Insets; import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.io.Serializable; import java.util.Locale; import javax.swing.border.Border; -import javax.swing.event.SwingPropertyChangeSupport; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.metal.MetalLookAndFeel; @@ -138,8 +138,8 @@ public class UIManager implements Serializable static UIDefaults userUIDefaults; /** Property change listener mechanism. */ - static SwingPropertyChangeSupport listeners - = new SwingPropertyChangeSupport(UIManager.class); + static PropertyChangeSupport listeners + = new PropertyChangeSupport(UIManager.class); static { diff --git a/javax/swing/ViewportLayout.java b/javax/swing/ViewportLayout.java index 79fd26c56..f935f71bb 100644 --- a/javax/swing/ViewportLayout.java +++ b/javax/swing/ViewportLayout.java @@ -83,14 +83,16 @@ public class ViewportLayout implements LayoutManager, Serializable return new Dimension(); } + /** + * Return the minimumSize for the JViewport that is laid out + * by this layout manager. + * + * @param parent the viewport + */ public Dimension minimumLayoutSize(Container parent) { - JViewport vp = (JViewport)parent; - Component view = vp.getView(); - if (view != null) - return view.getMinimumSize(); - else - return new Dimension(); + // These values have been determined by the Mauve test for this method. + return new Dimension(4, 4); } /** diff --git a/javax/swing/event/DocumentEvent.java b/javax/swing/event/DocumentEvent.java index 6cd8e61fe..c17b24254 100644 --- a/javax/swing/event/DocumentEvent.java +++ b/javax/swing/event/DocumentEvent.java @@ -81,7 +81,7 @@ public interface DocumentEvent /** * EventType */ - class EventType + final class EventType { /** * INSERT diff --git a/javax/swing/event/SwingPropertyChangeSupport.java b/javax/swing/event/SwingPropertyChangeSupport.java index 7e8ff0dc2..7fb8aa67d 100644 --- a/javax/swing/event/SwingPropertyChangeSupport.java +++ b/javax/swing/event/SwingPropertyChangeSupport.java @@ -1,5 +1,5 @@ /* SwingPropertyChangeSupport.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,47 +39,23 @@ package javax.swing.event; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeListenerProxy; import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.EventListener; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; /** * Provides a mechanism for registering {@link PropertyChangeListener}s and * forwarding {@link PropertyChangeEvent}s to those listeners. - * + * + * As of JDK1.5 this class is no longer in use. Use + * {@link PropertyChangeSupport} instead. + * * @author Andrew Selkirk */ public final class SwingPropertyChangeSupport - extends PropertyChangeSupport + extends PropertyChangeSupport { private static final long serialVersionUID = 7162625831330845068L; - /** - * Storage for the listeners that are not linked to a specific property. - */ - private transient EventListenerList listeners; - - /** - * Storage for the listeners that are linked (by name) to a specific property. - * The hash table maps String objects (the property names) to - * {@link EventListenerList} instances (which record the listener(s) for the - * given property). - */ - private Hashtable propertyListeners; - - /** - * The object that is used as the default source for the - * {@link PropertyChangeEvent}s generated by this class. - */ - private Object source; - /** * Creates a new instance. * @@ -90,247 +66,5 @@ public final class SwingPropertyChangeSupport public SwingPropertyChangeSupport(Object source) { super(source); - this.source = source; - this.listeners = new EventListenerList(); - this.propertyListeners = new Hashtable(); } - - /** - * Registers listener to receive notification of any future - * {@link PropertyChangeEvent}s generated by this instance. - * - * @param listener the listener (null is ignored). - * - * @see #removePropertyChangeListener(PropertyChangeListener) - */ - public synchronized void addPropertyChangeListener(PropertyChangeListener - listener) - { - listeners.add(PropertyChangeListener.class, listener); - } - - /** - * Registers listener to receive notification of any future - * {@link PropertyChangeEvent}s generated by this instance for the named - * property. - * - * @param propertyName the property name. - * @param listener the listener. - * - * @see #removePropertyChangeListener(String, PropertyChangeListener) - */ - public synchronized void addPropertyChangeListener(String propertyName, - PropertyChangeListener listener) - { - EventListenerList list; - list = (EventListenerList) propertyListeners.get(propertyName); - if (list == null) - { - list = new EventListenerList(); - propertyListeners.put(propertyName, list); - } - list.add(PropertyChangeListener.class, listener); - } - - /** - * Removes listener from the list of registered listeners, so - * that it will no longer receive notification of property change events. - * - * @param listener the listener to remove. - */ - public synchronized void removePropertyChangeListener(PropertyChangeListener - listener) - { - listeners.remove(PropertyChangeListener.class, listener); - } - - /** - * Removes listener from the list of registered listeners for - * the named property, so that it will no longer receive notification of - * property change events. - * - * @param propertyName the property name. - * @param listener the listener to remove. - */ - public synchronized void removePropertyChangeListener(String propertyName, - PropertyChangeListener listener) - { - EventListenerList list; - list = (EventListenerList) propertyListeners.get(propertyName); - if (list == null) - return; - list.remove(PropertyChangeListener.class, listener); - if (list.getListenerCount() == 0) - { - propertyListeners.remove(propertyName); - } - } - - /** - * Returns an array of the {@link PropertyChangeListener}s registered with - * this SwingPropertyChangeSupport instance. - * - * @return The array of listeners. - * - * @since 1.4 - */ - public synchronized PropertyChangeListener[] getPropertyChangeListeners() - { - // fetch the named listeners first so we know how many there are - List namedListeners = new ArrayList(); - Set namedListenerEntries = propertyListeners.entrySet(); - Iterator iterator = namedListenerEntries.iterator(); - while (iterator.hasNext()) - { - Map.Entry e = (Map.Entry) iterator.next(); - String propertyName = (String) e.getKey(); - EventListenerList ell = (EventListenerList) e.getValue(); - if (ell != null) - { - Object[] list = ell.getListenerList(); - for (int i = 0; i < list.length; i += 2) - { - namedListeners.add(new PropertyChangeListenerProxy(propertyName, - (PropertyChangeListener) list[i + 1])); - } - } - } - - // create an array that can hold everything - int size = listeners.getListenerCount() + namedListeners.size(); - PropertyChangeListener[] result = new PropertyChangeListener[size]; - - // copy in the general listeners - Object[] list = listeners.getListenerList(); - int index = 0; - for (int i = 0; i < list.length; i += 2) - result[index++] = (PropertyChangeListener) list[i + 1]; - - // ...and the named listeners - Iterator iterator2 = namedListeners.iterator(); - while (iterator2.hasNext()) - result[index++] = (PropertyChangeListenerProxy) iterator2.next(); - - return result; - } - - /** - * Returns an array of all listeners that are registered to receive - * notification of changes to the named property. This includes the general - * listeners as well as those registered specifically for the named - * property. - * - * @param propertyName the property name. - * - * @return An array of all listeners for the named property. - */ - public synchronized PropertyChangeListener[] getPropertyChangeListeners( - String propertyName) - { - EventListenerList list - = (EventListenerList) propertyListeners.get(propertyName); - if (list == null) - return getPropertyChangeListeners(); - int size = listeners.getListenerCount() + list.getListenerCount(); - PropertyChangeListener[] result = new PropertyChangeListener[size]; - - // copy in the general listeners - int index = 0; - for (int i = 0; i < listeners.listenerList.length; i += 2) - { - result[index++] - = (PropertyChangeListener) listeners.listenerList[i + 1]; - } - - // copy in the specific listeners - Object[] specificListeners = list.getListenerList(); - for (int i = 0; i < specificListeners.length; i += 2) - { - result[index++] = (PropertyChangeListener) specificListeners[i + 1]; - } - return result; - } - - /** - * Creates a new {@link PropertyChangeEvent} using the given arguments (and - * the default source for this - * SwingPropertyChangeSupport instance) and forwards it to all - * registered listeners via the - * {@link PropertyChangeListener#propertyChange(PropertyChangeEvent)} method. - *

      - * Note that if oldValue and newValue are non-null - * and equal, no listeners will be notified. - * - * @param propertyName the property name. - * @param oldValue the old value - * @param newValue the new value. - */ - public void firePropertyChange(String propertyName, Object oldValue, - Object newValue) - { - PropertyChangeEvent event; - event = new PropertyChangeEvent(source, propertyName, oldValue, newValue); - firePropertyChange(event); - } - - /** - * Forwards event to registered listeners. - *

      - * Note that if the event's getOldValue() and - * getNewValue() methods return non-null and equal values, no - * listeners will be notified. - * - * @param event the event. - */ - public void firePropertyChange(PropertyChangeEvent event) - { - EventListenerList list; - EventListener[] listenerList; - int index; - PropertyChangeListener listener; - - // if the old and new values are non-null and equal, don't notify listeners - if (event.getOldValue() != null && event.getNewValue() != null && - event.getOldValue().equals(event.getNewValue())) - return; - - // Process Main Listener List - listenerList = listeners.getListeners(PropertyChangeListener.class); - for (index = 0; index < listenerList.length; index++) - { - listener = (PropertyChangeListener) listenerList[index]; - listener.propertyChange(event); - } - - // Process Property Listener List - list = (EventListenerList) propertyListeners.get(event.getPropertyName()); - if (list != null) - { - listenerList = list.getListeners(PropertyChangeListener.class); - for (index = 0; index < listenerList.length; index++) - { - listener = (PropertyChangeListener) listenerList[index]; - listener.propertyChange(event); - } - } - - } - - /** - * Tell whether the specified property is being listened on or not. This - * will only return true if there are listeners on all - * properties or if there is a listener specifically on this property. - * - * @param propertyName the property that may be listened on - * @return whether the property is being listened on - * @throws NullPointerException if propertyName is null - */ - public synchronized boolean hasListeners(String propertyName) - { - if (listeners.getListenerCount() > 0) - return true; - else - return (propertyListeners.get(propertyName) != null); - } - } diff --git a/javax/swing/plaf/basic/BasicBorders.java b/javax/swing/plaf/basic/BasicBorders.java index 5d4ce1893..5e2cf2e48 100644 --- a/javax/swing/plaf/basic/BasicBorders.java +++ b/javax/swing/plaf/basic/BasicBorders.java @@ -299,9 +299,7 @@ public class BasicBorders public static Border getSplitPaneDividerBorder() { /* See comment in methods above for why this border is not shared. */ - return new SplitPaneDividerBorder( - UIManager.getColor("SplitPane.highlight"), - UIManager.getColor("SplitPane.darkShadow")); + return new SplitPaneDividerBorder(); } @@ -1517,35 +1515,16 @@ public class BasicBorders private static class SplitPaneDividerBorder implements Border, UIResource, Serializable { - /** - * The highlight color, which is drawn on the left or top edge - * depending on the orientation of the JSplitPanel. - */ - protected Color highlight; - - - /** - * The highlight color, which is drawn on the right or bottom edge - * depending on the orientation of the JSplitPanel. - */ - protected Color shadow; - - /** * Constructs a new border for drawing the divider of a JSplitPane * in the Basic look and feel. The outer parts of the JSplitPane have * their own border class, SplitPaneBorder. - * - * @param shadow the shadow color. - * @param highlight the highlight color. */ - public SplitPaneDividerBorder(Color highlight, Color shadow) + public SplitPaneDividerBorder() { - this.highlight = (highlight != null) ? highlight : Color.white; - this.shadow = (shadow != null) ? shadow : Color.black; + // Nothing to do here. } - /** * Paints the border around the divider of a JSplitPane. * @@ -1564,6 +1543,8 @@ public class BasicBorders public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + Color highlight = UIManager.getColor("SplitPane.highlight"); + Color shadow = UIManager.getColor("SplitPane.shadow"); Color oldColor, dcol; int x2, y2; JSplitPane sp; @@ -1624,17 +1605,15 @@ public class BasicBorders return new Insets(1, 1, 1, 1); } - /** * Determines whether this border fills every pixel in its area * when painting. * - * @return true if both highlight and shadow - * color are fully opaque. + * @return true */ public boolean isBorderOpaque() { - return (highlight.getAlpha() == 255) && (shadow.getAlpha() == 255); + return true; } @@ -1785,4 +1764,5 @@ public class BasicBorders return insets; } } + } diff --git a/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java b/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java index 95e0dc982..e45970ed0 100644 --- a/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java +++ b/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java @@ -45,7 +45,6 @@ import javax.swing.JMenuItem; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.UIDefaults; -import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; /** diff --git a/javax/swing/plaf/basic/BasicColorChooserUI.java b/javax/swing/plaf/basic/BasicColorChooserUI.java index 5a872ae63..f37cbd7b8 100644 --- a/javax/swing/plaf/basic/BasicColorChooserUI.java +++ b/javax/swing/plaf/basic/BasicColorChooserUI.java @@ -141,10 +141,9 @@ public class BasicColorChooserUI extends ColorChooserUI protected PropertyChangeListener propertyChangeListener; /** - * The JColorChooser. - * This is package-private to avoid an accessor method. + * The JColorChooser this is installed on. */ - JColorChooser chooser; + protected JColorChooser chooser; /** The JTabbedPane that is used. */ JTabbedPane pane; diff --git a/javax/swing/plaf/basic/BasicComboPopup.java b/javax/swing/plaf/basic/BasicComboPopup.java index 08dab7f9f..798101d0d 100644 --- a/javax/swing/plaf/basic/BasicComboPopup.java +++ b/javax/swing/plaf/basic/BasicComboPopup.java @@ -69,6 +69,7 @@ import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.Timer; +import javax.swing.UIManager; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionEvent; @@ -193,8 +194,23 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup if (selectedIndex > comboBox.getMaximumRowCount()) scrollbar.setValue(getPopupHeightForRowCount(selectedIndex)); + // We put the autoclose-registration inside an InvocationEvent, so that + // the same event that triggered this show() call won't hide the popup + // immediately. + SwingUtilities.invokeLater + (new Runnable() + { + public void run() + { + // Register this popup to be autoclosed when user clicks outside the + // popup. + BasicLookAndFeel laf = (BasicLookAndFeel) UIManager.getLookAndFeel(); + laf.registerForAutoClose(BasicComboPopup.this); + }}); + // location specified is relative to comboBox super.show(comboBox, 0, cbBounds.height); + } /** diff --git a/javax/swing/plaf/basic/BasicHTML.java b/javax/swing/plaf/basic/BasicHTML.java index b9891e144..ff7a7cdaf 100644 --- a/javax/swing/plaf/basic/BasicHTML.java +++ b/javax/swing/plaf/basic/BasicHTML.java @@ -138,7 +138,7 @@ public class BasicHTML /** * Stores a HTML renderer in c's client property if * text is HTML, otherwise it clears the corresponding client - * property. This is useful for {@link java.swing.plaf.ComponentUI} + * property. This is useful for {@link javax.swing.plaf.ComponentUI} * implementations that are shared between it's components. * * @param c the component to update the renderer for diff --git a/javax/swing/plaf/basic/BasicInternalFrameUI.java b/javax/swing/plaf/basic/BasicInternalFrameUI.java index f9653bd2e..9fc442c3a 100644 --- a/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -54,8 +54,6 @@ import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.beans.PropertyVetoException; -import java.beans.VetoableChangeListener; import javax.swing.DefaultDesktopManager; import javax.swing.DesktopManager; @@ -891,38 +889,10 @@ public class BasicInternalFrameUI extends InternalFrameUI * This helper class listens for PropertyChangeEvents from the * JInternalFrame. */ - public class InternalFramePropertyChangeListener implements - PropertyChangeListener, VetoableChangeListener + public class InternalFramePropertyChangeListener + implements PropertyChangeListener { - /** - * This method is called when one of the JInternalFrame's properties change. - * This method is to allow JInternalFrame to veto an attempt to close the - * internal frame. This allows JInternalFrame to honour its - * defaultCloseOperation if that is DO_NOTHING_ON_CLOSE. - */ - public void vetoableChange(PropertyChangeEvent e) - throws PropertyVetoException - { - if (e.getPropertyName().equals(JInternalFrame.IS_CLOSED_PROPERTY)) - { - if (frame.getDefaultCloseOperation() == JInternalFrame.HIDE_ON_CLOSE) - { - frame.setVisible(false); - frame.getDesktopPane().repaint(); - throw new PropertyVetoException( - "close operation is HIDE_ON_CLOSE\n", - e); - } - else if (frame.getDefaultCloseOperation() == JInternalFrame.DISPOSE_ON_CLOSE) - closeFrame(frame); - else - throw new PropertyVetoException( - "close operation is DO_NOTHING_ON_CLOSE\n", - e); - } - } - /** * This method is called when one of the JInternalFrame's properties change. * @@ -1091,13 +1061,6 @@ public class BasicInternalFrameUI extends InternalFrameUI */ protected PropertyChangeListener propertyChangeListener; - /** - * The VetoableChangeListener. Listens to PropertyChangeEvents - * from the JInternalFrame and allows the JInternalFrame to - * veto attempts to close it. - */ - private VetoableChangeListener internalFrameVetoableChangeListener; - /** The InternalFrameListener that listens to the JInternalFrame. */ private transient BasicInternalFrameListener internalFrameListener; @@ -1238,13 +1201,11 @@ public class BasicInternalFrameUI extends InternalFrameUI borderListener = createBorderListener(frame); componentListener = createComponentListener(); propertyChangeListener = createPropertyChangeListener(); - internalFrameVetoableChangeListener = new InternalFramePropertyChangeListener(); frame.addMouseListener(borderListener); frame.addMouseMotionListener(borderListener); frame.addInternalFrameListener(internalFrameListener); frame.addPropertyChangeListener(propertyChangeListener); - frame.addVetoableChangeListener(internalFrameVetoableChangeListener); frame.getRootPane().getGlassPane().addMouseListener(glassPaneDispatcher); frame.getRootPane().getGlassPane().addMouseMotionListener(glassPaneDispatcher); } diff --git a/javax/swing/plaf/basic/BasicListUI.java b/javax/swing/plaf/basic/BasicListUI.java index 00d157a62..9771db270 100644 --- a/javax/swing/plaf/basic/BasicListUI.java +++ b/javax/swing/plaf/basic/BasicListUI.java @@ -135,6 +135,7 @@ public class BasicListUI extends ListUI */ public void contentsChanged(ListDataEvent e) { + updateLayoutStateNeeded |= modelChanged; list.revalidate(); } @@ -145,6 +146,7 @@ public class BasicListUI extends ListUI */ public void intervalAdded(ListDataEvent e) { + updateLayoutStateNeeded |= modelChanged; list.revalidate(); } @@ -155,6 +157,7 @@ public class BasicListUI extends ListUI */ public void intervalRemoved(ListDataEvent e) { + updateLayoutStateNeeded |= modelChanged; list.revalidate(); } } @@ -541,17 +544,21 @@ public class BasicListUI extends ListUI */ public void propertyChange(PropertyChangeEvent e) { - if (e.getSource() == BasicListUI.this.list) + if (e.getPropertyName().equals("model")) { if (e.getOldValue() != null && e.getOldValue() instanceof ListModel) - ((ListModel) e.getOldValue()).removeListDataListener(BasicListUI.this.listDataListener); - + { + ListModel oldModel = (ListModel) e.getOldValue(); + oldModel.removeListDataListener(listDataListener); + } if (e.getNewValue() != null && e.getNewValue() instanceof ListModel) - ((ListModel) e.getNewValue()).addListDataListener(BasicListUI.this.listDataListener); + { + ListModel newModel = (ListModel) e.getNewValue(); + newModel.addListDataListener(BasicListUI.this.listDataListener); + } + + updateLayoutStateNeeded |= modelChanged; } - // Update the updateLayoutStateNeeded flag. - if (e.getPropertyName().equals("model")) - updateLayoutStateNeeded |= modelChanged; else if (e.getPropertyName().equals("selectionModel")) updateLayoutStateNeeded |= selectionModelChanged; else if (e.getPropertyName().equals("font")) @@ -720,12 +727,19 @@ public class BasicListUI extends ListUI int minIndex = Math.min(index1, index2); int maxIndex = Math.max(index1, index2); Point loc = indexToLocation(list, minIndex); - Rectangle bounds = new Rectangle(loc.x, loc.y, cellWidth, + + // When the layoutOrientation is VERTICAL, then the width == the list + // width. Otherwise the cellWidth field is used. + int width = cellWidth; + if (l.getLayoutOrientation() == JList.VERTICAL) + width = l.getWidth(); + + Rectangle bounds = new Rectangle(loc.x, loc.y, width, getCellHeight(minIndex)); for (int i = minIndex + 1; i <= maxIndex; i++) { Point hiLoc = indexToLocation(list, i); - Rectangle hibounds = new Rectangle(hiLoc.x, hiLoc.y, cellWidth, + Rectangle hibounds = new Rectangle(hiLoc.x, hiLoc.y, width, getCellHeight(i)); bounds = bounds.union(hibounds); } @@ -883,8 +897,6 @@ public class BasicListUI extends ListUI Dimension dim = flyweight.getPreferredSize(); cellWidth = Math.max(cellWidth, dim.width); } - if (list.getLayoutOrientation() == JList.VERTICAL) - cellWidth = Math.max(cellWidth, list.getSize().width); } } diff --git a/javax/swing/plaf/basic/BasicLookAndFeel.java b/javax/swing/plaf/basic/BasicLookAndFeel.java index f5217be1f..3451224be 100644 --- a/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -38,15 +38,24 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import java.awt.AWTEvent; import java.awt.Color; +import java.awt.Component; +import java.awt.Container; import java.awt.Dimension; import java.awt.Font; +import java.awt.Toolkit; +import java.awt.event.AWTEventListener; import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.Enumeration; +import java.util.Iterator; import java.util.ResourceBundle; +import java.util.Set; +import java.util.WeakHashMap; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; @@ -57,8 +66,11 @@ import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.BorderFactory; +import javax.swing.JPopupMenu; import javax.swing.KeyStroke; import javax.swing.LookAndFeel; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.border.BevelBorder; @@ -77,6 +89,96 @@ import javax.swing.plaf.InsetsUIResource; public abstract class BasicLookAndFeel extends LookAndFeel implements Serializable { + + /** + * Helps closing menu popups when the user clicks outside of any menu area. + * This is implemented as an AWTEventListener that listens on the event + * queue directly, grabs all mouse events from there and finds out of they + * are targetted at a menu/submenu/menubar or not. If not, + * the MenuSelectionManager is messaged to close the currently opened menus, + * if any. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class PopupHelper implements AWTEventListener + { + + /** + * Registered popups for autoclose. + */ + private WeakHashMap autoClosePopups = new WeakHashMap(); + + /** + * Receives an event from the event queue. + * + * @param event + */ + public void eventDispatched(AWTEvent event) + { + if (event instanceof MouseEvent) + { + MouseEvent mouseEvent = (MouseEvent) event; + if (mouseEvent.getID() == MouseEvent.MOUSE_PRESSED) + mousePressed(mouseEvent); + } + } + + /** + * Handles mouse pressed events from the event queue. + * + * @param ev the mouse pressed event + */ + private void mousePressed(MouseEvent ev) + { + // Autoclose all menus managed by the MenuSelectionManager. + MenuSelectionManager m = MenuSelectionManager.defaultManager(); + Component target = ev.getComponent(); + if (target instanceof Container) + target = ((Container) target).findComponentAt(ev.getPoint()); + if (! m.isComponentPartOfCurrentMenu(target)) + m.clearSelectedPath(); + + // Handle other registered popup instances, like ComboBox popups. + autoClosePopups(ev, target); + } + + /** + * Registers Popup and its content to be autoclosed when a mouseclick + * occurs outside of the popup. + * + * @param popup the popup to be autoclosed when clicked outside + */ + void registerForAutoClose(JPopupMenu popup) + { + autoClosePopups.put(popup, null); + } + + /** + * Automatically closes all popups that are not 'hit' by the mouse event. + * + * @param ev the mouse event + * @param target the target of the mouse event + */ + private void autoClosePopups(MouseEvent ev, Component target) + { + if (autoClosePopups.size() != 0) + { + Set popups = autoClosePopups.keySet(); + Iterator i = popups.iterator(); + while (i.hasNext()) + { + JPopupMenu popup = (JPopupMenu) i.next(); + if (!(target == popup + || SwingUtilities.isDescendingFrom(target, popup))) + { + popup.setVisible(false); + i.remove(); + } + } + } + } + } + /** * An action that can play an audio file. * @@ -137,6 +239,11 @@ public abstract class BasicLookAndFeel extends LookAndFeel static final long serialVersionUID = -6096995660290287879L; + /** + * Helps closing menu popups when user clicks outside of the menu area. + */ + private transient PopupHelper popupHelper; + private ActionMap audioActionMap; /** @@ -1023,6 +1130,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "SplitPane.dividerSize", new Integer(7), "SplitPane.highlight", new ColorUIResource(highLight), "SplitPane.shadow", new ColorUIResource(shadow), + "SplitPaneDivider.border", BasicBorders.getSplitPaneDividerBorder(), + "SplitPaneDivider.draggingColor", new ColorUIResource(Color.DARK_GRAY), "TabbedPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { "ctrl PAGE_DOWN","navigatePageDown", "ctrl PAGE_UP", "navigatePageUp", @@ -1520,4 +1629,36 @@ public abstract class BasicLookAndFeel extends LookAndFeel } } + /** + * Initializes the Look and Feel. + */ + public void initialize() + { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + popupHelper = new PopupHelper(); + toolkit.addAWTEventListener(popupHelper, AWTEvent.MOUSE_EVENT_MASK); + } + + /** + * Uninitializes the Look and Feel. + */ + public void uninitialize() + { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + toolkit.removeAWTEventListener(popupHelper); + popupHelper = null; + } + + /** + * Registers a JPopupMenu for autoclosing when a mouseclick occurs outside + * of the JPopupMenu. This must be called when the popup gets opened. The + * popup is unregistered from autoclosing as soon as it either got closed + * by this helper, or when it has been garbage collected. + * + * @param popup the popup menu to autoclose + */ + void registerForAutoClose(JPopupMenu popup) + { + popupHelper.registerForAutoClose(popup); + } } diff --git a/javax/swing/plaf/basic/BasicMenuItemUI.java b/javax/swing/plaf/basic/BasicMenuItemUI.java index 63f0ce206..9166c49ee 100644 --- a/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -610,8 +610,7 @@ public class BasicMenuItemUI extends MenuItemUI Font f = m.getFont(); g.setFont(f); FontMetrics fm = g.getFontMetrics(f); - SwingUtilities.calculateInnerArea(m, br); - SwingUtilities.calculateInsetArea(br, m.getInsets(), vr); + SwingUtilities.calculateInnerArea(m, vr); paintBackground(g, m, background); /* diff --git a/javax/swing/plaf/basic/BasicPopupMenuUI.java b/javax/swing/plaf/basic/BasicPopupMenuUI.java index e15a17bab..6ecd06b39 100644 --- a/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -37,28 +37,20 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import java.awt.AWTEvent; import java.awt.Component; -import java.awt.Container; -import java.awt.Cursor; import java.awt.Dimension; -import java.awt.Point; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import javax.swing.BoxLayout; import javax.swing.JComponent; -import javax.swing.JLayeredPane; -import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.LookAndFeel; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; -import javax.swing.RootPaneContainer; import javax.swing.SwingUtilities; -import javax.swing.event.MouseInputListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.plaf.ComponentUI; @@ -73,9 +65,6 @@ public class BasicPopupMenuUI extends PopupMenuUI /* popupMenu for which this UI delegate is for*/ protected JPopupMenu popupMenu; - /* MouseInputListener listens to mouse events. Package private for inner classes. */ - static transient MouseInputListener mouseInputListener; - /* PopupMenuListener listens to popup menu events fired by JPopupMenu*/ private transient PopupMenuListener popupMenuListener; @@ -270,30 +259,9 @@ public class BasicPopupMenuUI extends PopupMenuUI // remove listener that listens to component events fired // by the top - level window that this popup belongs to. Component invoker = popupMenu.getInvoker(); - - RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities - .getRoot(invoker); + Component rootContainer = SwingUtilities.getRoot(invoker); if (rootContainer != null) - { - ((Container) rootContainer).removeComponentListener(topWindowListener); - - // If this popup menu is the last popup menu visible on the screen, - // then - // stop interrupting mouse events in the glass pane before hiding this - // last popup menu. - boolean topLevelMenu = (popupMenu.getInvoker() instanceof JMenu) - && ((JMenu) popupMenu.getInvoker()).isTopLevelMenu(); - - if (topLevelMenu || !(popupMenu.getInvoker() instanceof MenuElement)) - { - // set glass pane not to interrupt mouse events and remove - // mouseInputListener - Container glassPane = (Container) rootContainer.getGlassPane(); - glassPane.setVisible(false); - glassPane.removeMouseListener(mouseInputListener); - mouseInputListener = null; - } - } + rootContainer.removeComponentListener(topWindowListener); } /** @@ -307,20 +275,8 @@ public class BasicPopupMenuUI extends PopupMenuUI // ComponentEvents fired by it. We need to cancel this popup menu // if topWindow to which this popup belongs was resized or moved. Component invoker = popupMenu.getInvoker(); - RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities - .getRoot(invoker); - ((Container) rootContainer).addComponentListener(topWindowListener); - - // Set the glass pane to interrupt all mouse events originating in root - // container - if (mouseInputListener == null) - { - Container glassPane = (Container) rootContainer.getGlassPane(); - glassPane.setVisible(true); - mouseInputListener = new MouseInputHandler(rootContainer); - glassPane.addMouseListener(mouseInputListener); - glassPane.addMouseMotionListener(mouseInputListener); - } + Component rootContainer = SwingUtilities.getRoot(invoker); + rootContainer.addComponentListener(topWindowListener); // if this popup menu is a free floating popup menu, // then by default its first element should be always selected when @@ -399,275 +355,4 @@ public class BasicPopupMenuUI extends PopupMenuUI } } - /** - * MouseInputHandler listens to all mouse events originated in the root - * container. This class is responsible for closing menu hierarchy when the - * user presses mouse over any component that do not belong to the current - * menu hierarchy. This is acomplished by interrupting all mouse event in - * the glass pane and checking if other component was pressed while menu - * was open, before redestributing events further to intended components - */ - private class MouseInputHandler implements MouseInputListener - { - private JLayeredPane layeredPane; - private Container glassPane; - private Cursor nativeCursor; - private transient Component mouseEventTarget; - private transient Component pressedComponent; - private transient Component lastComponentEntered; - private transient Component tempComponent; - private transient int pressCount; - - /** - * Creates a new MouseInputHandler object. - * - * @param c the top most root container - */ - public MouseInputHandler(RootPaneContainer c) - { - layeredPane = c.getLayeredPane(); - glassPane = (Container) c.getGlassPane(); - } - - /** - * Handles mouse clicked event - * - * @param e Mouse event - */ - public void mouseClicked(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouseDragged event - * - * @param e MouseEvent - */ - public void mouseDragged(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouseEntered event - * - * @param e MouseEvent - */ - public void mouseEntered(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouseExited event - * - * @param e MouseEvent - */ - public void mouseExited(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouse moved event - * - * @param e MouseEvent - */ - public void mouseMoved(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouse pressed event - * - * @param e MouseEvent - */ - public void mousePressed(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouse released event - * - * @param e MouseEvent - */ - public void mouseReleased(MouseEvent e) - { - handleEvent(e); - } - - /* - * This method determines component that was intended to received mouse - * event, before it was interrupted within the glass pane. This method - * also redispatches mouse entered and mouse exited events to the - * appropriate components. This code is slightly modified code from - * Container.LightweightDispatcher class, which is private inside - * Container class and cannot be used here. - */ - public void acquireComponentForMouseEvent(MouseEvent me) - { - int x = me.getX(); - int y = me.getY(); - - // Find the candidate which should receive this event. - Component parent = layeredPane; - Component candidate = null; - Point p = me.getPoint(); - while ((candidate == null) && (parent != null)) - { - p = SwingUtilities.convertPoint(glassPane, p.x, p.y, parent); - candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y); - - if (candidate == null) - { - p = SwingUtilities.convertPoint(parent, p.x, p.y, - parent.getParent()); - parent = parent.getParent(); - } - } - - // If the only candidate we found was the native container itself, - // don't dispatch any event at all. We only care about the lightweight - // children here. - if (candidate == layeredPane) - candidate = null; - - // If our candidate is new, inform the old target we're leaving. - if ((lastComponentEntered != null) && lastComponentEntered.isShowing() - && (lastComponentEntered != candidate)) - { - // Old candidate could have been removed from - // the layeredPane so we check first. - if (SwingUtilities.isDescendingFrom(lastComponentEntered, layeredPane)) - { - Point tp = SwingUtilities.convertPoint(layeredPane, x, y, - lastComponentEntered); - MouseEvent exited = new MouseEvent(lastComponentEntered, - MouseEvent.MOUSE_EXITED, - me.getWhen(), - me.getModifiersEx(), tp.x, - tp.y, me.getClickCount(), - me.isPopupTrigger(), - me.getButton()); - - tempComponent = lastComponentEntered; - lastComponentEntered = null; - tempComponent.dispatchEvent(exited); - } - - lastComponentEntered = null; - } - - // If we have a candidate, maybe enter it. - if (candidate != null) - { - mouseEventTarget = candidate; - - if (candidate.isLightweight() && candidate.isShowing() - && (candidate != layeredPane) - && (candidate != lastComponentEntered)) - { - lastComponentEntered = mouseEventTarget; - - Point cp = SwingUtilities.convertPoint(layeredPane, x, y, - lastComponentEntered); - MouseEvent entered = new MouseEvent(lastComponentEntered, - MouseEvent.MOUSE_ENTERED, - me.getWhen(), - me.getModifiersEx(), cp.x, - cp.y, me.getClickCount(), - me.isPopupTrigger(), - me.getButton()); - lastComponentEntered.dispatchEvent(entered); - } - } - - if ((me.getID() == MouseEvent.MOUSE_RELEASED) - || ((me.getID() == MouseEvent.MOUSE_PRESSED) && (pressCount > 0)) - || (me.getID() == MouseEvent.MOUSE_DRAGGED)) - { - // If any of the following events occur while a button is held down, - // they should be dispatched to the same component to which the - // original MOUSE_PRESSED event was dispatched: - // - MOUSE_RELEASED - // - MOUSE_PRESSED: another button pressed while the first is held down - // - MOUSE_DRAGGED - if (SwingUtilities.isDescendingFrom(pressedComponent, layeredPane)) - mouseEventTarget = pressedComponent; - else if (me.getID() == MouseEvent.MOUSE_CLICKED) - { - // Don't dispatch CLICKED events whose target is not the same as the - // target for the original PRESSED event. - if (candidate != pressedComponent) - mouseEventTarget = null; - else if (pressCount == 0) - pressedComponent = null; - } - } - } - - /* - * This method handles mouse events interrupted by glassPane. It - * redispatches the mouse events appropriately to the intended components. - * The code in this method is also taken from - * Container.LightweightDispatcher class. The code is slightly modified - * to handle the case when mouse is released over non-menu component. In - * this case this method closes current menu hierarchy before - * redispatching the event further. - */ - public void handleEvent(AWTEvent e) - { - if (e instanceof MouseEvent) - { - MouseEvent me = (MouseEvent) e; - - acquireComponentForMouseEvent(me); - - // Avoid dispatching ENTERED and EXITED events twice. - if (mouseEventTarget != null && mouseEventTarget.isShowing() - && (e.getID() != MouseEvent.MOUSE_ENTERED) - && (e.getID() != MouseEvent.MOUSE_EXITED)) - { - MouseEvent newEvt = SwingUtilities.convertMouseEvent(glassPane, - me, - mouseEventTarget); - - mouseEventTarget.dispatchEvent(newEvt); - - // If mouse was clicked over the component that is not part - // of menu hierarchy,then must close the menu hierarchy */ - if (e.getID() == MouseEvent.MOUSE_RELEASED) - { - boolean partOfMenuHierarchy = false; - MenuSelectionManager manager = MenuSelectionManager - .defaultManager(); - - partOfMenuHierarchy = manager.isComponentPartOfCurrentMenu(mouseEventTarget); - - if (! partOfMenuHierarchy) - manager.clearSelectedPath(); - } - - switch (e.getID()) - { - case MouseEvent.MOUSE_PRESSED: - if (pressCount++ == 0) - pressedComponent = mouseEventTarget; - break; - case MouseEvent.MOUSE_RELEASED: - // Clear our memory of the original PRESSED event, only if - // we're not expecting a CLICKED event after this. If - // there is a CLICKED event after this, it will do clean up. - if ((--pressCount == 0) - && (mouseEventTarget != pressedComponent)) - pressedComponent = null; - break; - } - } - } - } - } } diff --git a/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java b/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java index 8af5ff7f9..f8f62e156 100644 --- a/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java +++ b/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java @@ -45,7 +45,6 @@ import javax.swing.JMenuItem; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.UIDefaults; -import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; /** diff --git a/javax/swing/plaf/basic/BasicRootPaneUI.java b/javax/swing/plaf/basic/BasicRootPaneUI.java index 2a698e8a1..28e3b67c1 100644 --- a/javax/swing/plaf/basic/BasicRootPaneUI.java +++ b/javax/swing/plaf/basic/BasicRootPaneUI.java @@ -1,4 +1,4 @@ -/* BasicPanelUI.java -- +/* BasicRootPaneUI.java -- Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,7 +43,6 @@ import java.beans.PropertyChangeListener; import javax.swing.JComponent; import javax.swing.JRootPane; -import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.RootPaneUI; @@ -75,8 +74,7 @@ public class BasicRootPaneUI extends RootPaneUI */ protected void installDefaults(JRootPane rp) { - // Is this ok? - rp.setBackground(UIManager.getColor("control")); + // TODO: What to do here, if anything? (might be a hook method) } /** diff --git a/javax/swing/plaf/basic/BasicSpinnerUI.java b/javax/swing/plaf/basic/BasicSpinnerUI.java index 3b7399eaf..6f7a41a1d 100644 --- a/javax/swing/plaf/basic/BasicSpinnerUI.java +++ b/javax/swing/plaf/basic/BasicSpinnerUI.java @@ -1,5 +1,5 @@ -/* SpinnerUI.java -- - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +/* BasicSpinnerUI.java -- + Copyright (C) 2003, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,7 @@ package javax.swing.plaf.basic; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; +import java.awt.Font; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.event.ActionEvent; @@ -59,22 +60,21 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.SpinnerUI; /** - * DOCUMENT ME! + * A UI delegate for the {@link JSpinner} component. * * @author Ka-Hing Cheung * - * @see javax.swing.JSpinner * @since 1.4 */ public class BasicSpinnerUI extends SpinnerUI { /** - * Creates a new ComponentUI for the specified + * Creates a new BasicSpinnerUI for the specified * JComponent * - * @param c DOCUMENT ME! + * @param c the component (ignored). * - * @return a ComponentUI + * @return A new instance of {@link BasicSpinnerUI}. */ public static ComponentUI createUI(JComponent c) { @@ -144,14 +144,15 @@ public class BasicSpinnerUI extends SpinnerUI { return new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) - { - // FIXME: Add check for enabled property change. Need to - // disable the buttons. - if ("editor".equals(evt.getPropertyName())) - BasicSpinnerUI.this.replaceEditor((JComponent) evt.getOldValue(), - (JComponent) evt.getNewValue()); - } + public void propertyChange(PropertyChangeEvent event) + { + // FIXME: Add check for enabled property change. Need to + // disable the buttons. + if ("editor".equals(event.getPropertyName())) + BasicSpinnerUI.this.replaceEditor((JComponent) event.getOldValue(), + (JComponent) event.getNewValue()); + // FIXME: Handle 'font' property change + } }; } @@ -169,6 +170,12 @@ public class BasicSpinnerUI extends SpinnerUI LookAndFeel.installColorsAndFont(spinner, "Spinner.background", "Spinner.foreground", "Spinner.font"); LookAndFeel.installBorder(spinner, "Spinner.border"); + JComponent e = spinner.getEditor(); + if (e instanceof JSpinner.DefaultEditor) + { + JSpinner.DefaultEditor de = (JSpinner.DefaultEditor) e; + de.getTextField().setBorder(null); + } spinner.setLayout(createLayout()); spinner.setOpaque(true); } @@ -352,7 +359,8 @@ public class BasicSpinnerUI extends SpinnerUI private PropertyChangeListener listener = createPropertyChangeListener(); /** - * DOCUMENT ME! + * A layout manager for the {@link JSpinner} component. The spinner has + * three subcomponents: an editor, a 'next' button and a 'previous' button. */ private class DefaultLayoutManager implements LayoutManager { @@ -365,58 +373,52 @@ public class BasicSpinnerUI extends SpinnerUI { synchronized (parent.getTreeLock()) { - Insets i = parent.getInsets(); - boolean l2r = parent.getComponentOrientation().isLeftToRight(); - /* - -------------- -------------- - | | n | | n | | - | e | - | or | - | e | - | | p | | p | | - -------------- -------------- - */ - Dimension e = minSize(editor); - Dimension n = minSize(next); - Dimension p = minSize(previous); - Dimension s = spinner.getPreferredSize(); - - int x = l2r ? i.left : i.right; - int y = i.top; - int w = Math.max(p.width, n.width); - int h = Math.max(p.height, n.height); - h = Math.max(h, e.height / 2); - int e_width = s.width - w; - - if (l2r) - { - setBounds(editor, x, y + (s.height - e.height) / 2, e_width, - e.height); - x += e_width; - - setBounds(next, x, y, w, h); - y += h; - - setBounds(previous, x, y, w, h); - } - else - { - setBounds(next, x, y + (s.height - e.height) / 2, w, h); - y += h; - - setBounds(previous, x, y, w, h); - x += w; - y -= h; - - setBounds(editor, x, y, e_width, e.height); - } + Insets i = parent.getInsets(); + boolean l2r = parent.getComponentOrientation().isLeftToRight(); + /* + -------------- -------------- + | | n | | n | | + | e | - | or | - | e | + | | p | | p | | + -------------- -------------- + */ + Dimension e = prefSize(editor); + Dimension n = prefSize(next); + Dimension p = prefSize(previous); + Dimension s = spinner.getPreferredSize(); + + int x = l2r ? i.left : i.right; + int y = i.top; + int w = Math.max(p.width, n.width); + int h = e.height / 2; + int e_width = s.width - w - i.left - i.right; + + if (l2r) + { + setBounds(editor, x, y, e_width, 2 * h); + x += e_width; + setBounds(next, x, y, w, h); + y += h; + setBounds(previous, x, y, w, h); + } + else + { + setBounds(next, x, y + (s.height - e.height) / 2, w, h); + y += h; + setBounds(previous, x, y + (s.height - e.height) / 2, w, h); + x += w; + y -= h; + setBounds(editor, x, y, e_width, e.height); + } } } /** - * DOCUMENT ME! + * Calculates the minimum layout size. * - * @param parent DOCUMENT ME! + * @param parent the parent. * - * @return DOCUMENT ME! + * @return The minimum layout size. */ public Dimension minimumLayoutSize(Container parent) { @@ -424,36 +426,32 @@ public class BasicSpinnerUI extends SpinnerUI if (editor != null) { - Dimension tmp = editor.getMinimumSize(); - d.width += tmp.width; - d.height = tmp.height; + Dimension tmp = editor.getMinimumSize(); + d.width += tmp.width; + d.height = tmp.height; } int nextWidth = 0; int previousWidth = 0; - int otherHeight = 0; if (next != null) { - Dimension tmp = next.getMinimumSize(); - nextWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = next.getMinimumSize(); + nextWidth = tmp.width; } if (previous != null) { - Dimension tmp = previous.getMinimumSize(); - previousWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = previous.getMinimumSize(); + previousWidth = tmp.width; } - d.height = Math.max(d.height, otherHeight); d.width += Math.max(nextWidth, previousWidth); return d; } /** - * DOCUMENT ME! + * Returns the preferred layout size of the container. * * @param parent DOCUMENT ME! * @@ -465,31 +463,29 @@ public class BasicSpinnerUI extends SpinnerUI if (editor != null) { - Dimension tmp = editor.getPreferredSize(); - d.width += Math.max(tmp.width, 40); - d.height = tmp.height; + Dimension tmp = editor.getPreferredSize(); + d.width += Math.max(tmp.width, 40); + d.height = tmp.height; } int nextWidth = 0; int previousWidth = 0; - int otherHeight = 0; if (next != null) { - Dimension tmp = next.getPreferredSize(); - nextWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = next.getPreferredSize(); + nextWidth = tmp.width; } if (previous != null) { - Dimension tmp = previous.getPreferredSize(); - previousWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = previous.getPreferredSize(); + previousWidth = tmp.width; } - d.height = Math.max(d.height, otherHeight); d.width += Math.max(nextWidth, previousWidth); - + Insets insets = parent.getInsets(); + d.width = d.width + insets.left + insets.right; + d.height = d.height + insets.top + insets.bottom; return d; } @@ -501,11 +497,11 @@ public class BasicSpinnerUI extends SpinnerUI public void removeLayoutComponent(Component child) { if (child == editor) - editor = null; + editor = null; else if (child == next) - next = null; + next = null; else if (previous == child) - previous = null; + previous = null; } /** @@ -517,11 +513,11 @@ public class BasicSpinnerUI extends SpinnerUI public void addLayoutComponent(String name, Component child) { if ("Editor".equals(name)) - editor = child; + editor = child; else if ("Next".equals(name)) - next = child; + next = child; else if ("Previous".equals(name)) - previous = child; + previous = child; } /** @@ -531,36 +527,36 @@ public class BasicSpinnerUI extends SpinnerUI * * @return DOCUMENT ME! */ - private Dimension minSize(Component c) + private Dimension prefSize(Component c) { if (c == null) - return new Dimension(); + return new Dimension(); else - return c.getMinimumSize(); + return c.getPreferredSize(); } /** - * DOCUMENT ME! + * Sets the bounds for the specified component. * - * @param c DOCUMENT ME! - * @param x DOCUMENT ME! - * @param y DOCUMENT ME! - * @param w DOCUMENT ME! - * @param h DOCUMENT ME! + * @param c the component. + * @param x the x-coordinate for the top-left of the component bounds. + * @param y the y-coordinate for the top-left of the component bounds. + * @param w the width of the bounds. + * @param h the height of the bounds. */ private void setBounds(Component c, int x, int y, int w, int h) { if (c != null) - c.setBounds(x, y, w, h); + c.setBounds(x, y, w, h); } - /** DOCUMENT ME! */ + /** The editor component. */ private Component editor; - /** DOCUMENT ME! */ + /** The next button. */ private Component next; - /** DOCUMENT ME! */ + /** The previous button. */ private Component previous; } } diff --git a/javax/swing/plaf/basic/BasicSplitPaneDivider.java b/javax/swing/plaf/basic/BasicSplitPaneDivider.java index ff17ff084..06d32984e 100644 --- a/javax/swing/plaf/basic/BasicSplitPaneDivider.java +++ b/javax/swing/plaf/basic/BasicSplitPaneDivider.java @@ -38,7 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; @@ -161,31 +160,6 @@ public class BasicSplitPaneDivider extends Container */ transient int currentDividerLocation = 1; - /** DOCUMENT ME! */ - private transient Border tmpBorder = new Border() - { - public Insets getBorderInsets(Component c) - { - return new Insets(2, 2, 2, 2); - } - - public boolean isBorderOpaque() - { - return false; - } - - public void paintBorder(Component c, Graphics g, int x, int y, - int width, int height) - { - Color saved = g.getColor(); - g.setColor(Color.BLACK); - - g.drawRect(x + 2, y + 2, width - 4, height - 4); - - g.setColor(saved); - } - }; - /** * Constructs a new divider. * @@ -196,7 +170,6 @@ public class BasicSplitPaneDivider extends Container setLayout(new DividerLayout()); setBasicSplitPaneUI(ui); setDividerSize(splitPane.getDividerSize()); - setBorder(tmpBorder); } /** @@ -212,8 +185,6 @@ public class BasicSplitPaneDivider extends Container if (splitPane != null) { splitPane.removePropertyChangeListener(this); - splitPane.removeMouseListener(mouseHandler); - splitPane.removeMouseMotionListener(mouseHandler); removeMouseListener(mouseHandler); removeMouseMotionListener(mouseHandler); splitPane = null; @@ -227,8 +198,6 @@ public class BasicSplitPaneDivider extends Container if (splitPane != null) { splitPane.addPropertyChangeListener(this); - splitPane.addMouseListener(mouseHandler); - splitPane.addMouseMotionListener(mouseHandler); addMouseListener(mouseHandler); addMouseMotionListener(mouseHandler); hiddenDivider = splitPaneUI.getNonContinuousLayoutDivider(); diff --git a/javax/swing/plaf/basic/BasicSplitPaneUI.java b/javax/swing/plaf/basic/BasicSplitPaneUI.java index cf31e8b5d..8a7c9d2a2 100644 --- a/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -62,6 +62,7 @@ import javax.swing.LookAndFeel; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.SplitPaneUI; +import javax.swing.plaf.UIResource; /** * This is the Basic Look and Feel implementation of the SplitPaneUI class. @@ -253,20 +254,21 @@ public class BasicSplitPaneUI extends SplitPaneUI JSplitPane split = (JSplitPane) container; distributeExtraSpace(); Insets insets = split.getInsets(); - int width = getInitialLocation(insets); Dimension dims = split.getSize(); - for (int i = 0; i < components.length; i += 2) - { - if (components[i] == null) - continue; - setComponentToSize(components[i], sizes[i], width, insets, dims); - width += sizes[i]; - } - if (components[1] != null) - { - setComponentToSize(components[1], sizes[1], width, insets, dims); - width += sizes[1]; - } + int loc = getInitialLocation(insets); + int available = getAvailableSize(dims, insets); + sizes[0] = getDividerLocation(split) - loc; + sizes[1] = available - sizes[0] - sizes[2]; + // The size of the divider won't change. + + // Layout component#1. + setComponentToSize(components[0], sizes[0], loc, insets, dims); + // Layout divider. + loc += sizes[0]; + setComponentToSize(components[2], sizes[2], loc, insets, dims); + // Layout component#2. + loc += sizes[2]; + setComponentToSize(components[1], sizes[1], loc, insets, dims); } } @@ -388,6 +390,8 @@ public class BasicSplitPaneUI extends SplitPaneUI { for (int i = 0; i < components.length; i++) resetSizeAt(i); + setDividerLocation(splitPane, + getInitialLocation(splitPane.getInsets()) + sizes[0]); } /** @@ -451,21 +455,7 @@ public class BasicSplitPaneUI extends SplitPaneUI */ void distributeExtraSpace() { - int availSize = getAvailableSize(splitPane.getSize(), - splitPane.getInsets()); - int[] newSizes = new int[3]; - double weight = splitPane.getResizeWeight(); - - int oldLen = sizes[0] + sizes[1]; - - // dividers don't change size. - availSize -= sizes[2] + oldLen; - - int rightAlloc = (int) (availSize * (1 - weight)); - int leftAlloc = availSize - rightAlloc; - - sizes[0] += leftAlloc; - sizes[1] += rightAlloc; + // FIXME: This needs to be reimplemented correctly. } /** @@ -835,8 +825,6 @@ public class BasicSplitPaneUI extends SplitPaneUI if (prop <= 1 && prop >= 0) splitPane.setDividerLocation(prop); } - layoutManager.layoutContainer(splitPane); - splitPane.repaint(); // Don't have to deal with continuous_layout - only // necessary in dragging modes (and it's checked // every time you drag there) @@ -933,6 +921,8 @@ public class BasicSplitPaneUI extends SplitPaneUI /** The JSplitPane that this UI draws. */ protected JSplitPane splitPane; + private int dividerLocation; + /** * Creates a new BasicSplitPaneUI object. */ @@ -992,6 +982,7 @@ public class BasicSplitPaneUI extends SplitPaneUI "SplitPane.foreground"); LookAndFeel.installBorder(splitPane, "SplitPane.border"); divider = createDefaultDivider(); + divider.setBorder(UIManager.getBorder("SplitPaneDivider.border")); resetLayoutManager(); nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider(); splitPane.add(divider, JSplitPane.DIVIDER); @@ -1012,8 +1003,10 @@ public class BasicSplitPaneUI extends SplitPaneUI divider = null; nonContinuousLayoutDivider = null; - splitPane.setBackground(null); - splitPane.setBorder(null); + if (splitPane.getBackground() instanceof UIResource) + splitPane.setBackground(null); + if (splitPane.getBorder() instanceof UIResource) + splitPane.setBorder(null); } /** @@ -1219,7 +1212,8 @@ public class BasicSplitPaneUI extends SplitPaneUI if (nonContinuousLayoutDivider == null) { nonContinuousLayoutDivider = new Canvas(); - nonContinuousLayoutDivider.setBackground(Color.DARK_GRAY); + Color c = UIManager.getColor("SplitPaneDivider.draggingColor"); + nonContinuousLayoutDivider.setBackground(c); } return nonContinuousLayoutDivider; } @@ -1298,44 +1292,7 @@ public class BasicSplitPaneUI extends SplitPaneUI */ public void setDividerLocation(JSplitPane jc, int location) { - location = validLocation(location); - Container p = jc.getParent(); - Component right = jc.getRightComponent(); - Dimension rightPrefSize = right == null ? new Dimension(0, 0) - : right.getPreferredSize(); - Dimension size = jc.getSize(); - // check if the size has been set for the splitpane - if (size.width == 0 && size.height == 0) - size = jc.getPreferredSize(); - - if (getOrientation() == 0 && location > size.height) - { - location = size.height; - while (p != null) - { - p.setSize(p.getWidth(), p.getHeight() + rightPrefSize.height); - p = p.getParent(); - } - } - else if (location > size.width) - { - location = size.width; - while (p != null) - { - p.setSize(p.getWidth() + rightPrefSize.width, p.getHeight()); - p = p.getParent(); - } - } - - setLastDragLocation(getDividerLocation(splitPane)); - splitPane.setLastDividerLocation(getDividerLocation(splitPane)); - int[] tmpSizes = layoutManager.getSizes(); - tmpSizes[0] = location - - layoutManager.getInitialLocation(splitPane.getInsets()); - tmpSizes[1] = layoutManager.getAvailableSize(splitPane.getSize(), - splitPane.getInsets()) - - tmpSizes[0]; - layoutManager.setSizes(tmpSizes); + dividerLocation = location; splitPane.revalidate(); splitPane.repaint(); } @@ -1349,8 +1306,7 @@ public class BasicSplitPaneUI extends SplitPaneUI */ public int getDividerLocation(JSplitPane jc) { - return layoutManager.sizes[0] - + layoutManager.getInitialLocation(splitPane.getInsets()); + return dividerLocation; } /** @@ -1365,7 +1321,7 @@ public class BasicSplitPaneUI extends SplitPaneUI { int value = layoutManager.getInitialLocation(jc.getInsets()); if (layoutManager.components[0] != null) - value -= layoutManager.minimumSizeOfComponent(0); + value += layoutManager.minimumSizeOfComponent(0); return value; } @@ -1501,8 +1457,6 @@ public class BasicSplitPaneUI extends SplitPaneUI nonContinuousLayoutDivider.setVisible(true); nonContinuousLayoutDivider.setBounds(divider.getBounds()); } - splitPane.revalidate(); - splitPane.repaint(); } /** @@ -1544,11 +1498,9 @@ public class BasicSplitPaneUI extends SplitPaneUI nonContinuousLayoutDivider.setVisible(false); draggingHW = false; location = validLocation(location); - dragDividerTo(location); splitPane.setDividerLocation(location); splitPane.setLastDividerLocation(beginDragDividerLocation); beginDragDividerLocation = -1; - splitPane.repaint(); } /** diff --git a/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/javax/swing/plaf/basic/BasicTabbedPaneUI.java index a8f52cef6..5b1e1ff0f 100644 --- a/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -451,6 +451,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants } } runCount = runs; + if (runCount > tabRuns.length) + expandTabRunsArray(); tabRuns[0] = 0; normalizeTabRuns(tabPlacement, tabCount, start, max); @@ -1025,6 +1027,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants } } runCount = runs; + if (runCount > tabRuns.length) + expandTabRunsArray(); padSelectedTab(tabPlacement, tabPane.getSelectedIndex()); } @@ -1733,9 +1737,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants int tabCount = tabPane.getTabCount(); int currRun = 1; - if (tabCount > runCount) - runCount = tabCount; - if (tabCount < 1) return; diff --git a/javax/swing/plaf/basic/BasicTableHeaderUI.java b/javax/swing/plaf/basic/BasicTableHeaderUI.java index 9c8a5ef95..1e8e39f38 100644 --- a/javax/swing/plaf/basic/BasicTableHeaderUI.java +++ b/javax/swing/plaf/basic/BasicTableHeaderUI.java @@ -39,14 +39,18 @@ exception statement from your version. */ package javax.swing.plaf.basic; import java.awt.Component; +import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import javax.swing.CellRendererPane; import javax.swing.JComponent; import javax.swing.LookAndFeel; +import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.event.MouseInputListener; @@ -57,62 +61,346 @@ import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; +/** + * Basic pluggable look and feel interface for JTableHeader. + */ public class BasicTableHeaderUI extends TableHeaderUI { - + /** + * The width of the space (in both direction) around the column boundary, + * where mouse cursor changes shape into "resize" + */ + static int COLUMN_BOUNDARY_TOLERANCE = 3; + public static ComponentUI createUI(JComponent h) { return new BasicTableHeaderUI(); } - + + /** + * The table header that is using this interface. + */ protected JTableHeader header; + + /** + * The mouse input listener, responsible for mouse manipulations with + * the table header. + */ protected MouseInputListener mouseInputListener; + + /** + * Paint the header cell. + */ protected CellRendererPane rendererPane; + + /** + * The header cell border. + */ protected Border cellBorder; - - public class MouseInputHandler implements MouseInputListener + + /** + * If not null, one of the columns is currently being dragged. + */ + Rectangle draggingHeaderRect; + + /** + * Handles column movement and rearrangement by mouse. The same instance works + * both as mouse listener and the mouse motion listner. + */ + public class MouseInputHandler + implements MouseInputListener { + /** + * If true, the cursor is being already shown in the alternative "resize" + * shape. + */ + boolean showingResizeCursor; + + /** + * The position, from where the cursor is dragged during resizing. Double + * purpose field (absolute value during resizing and relative offset during + * column dragging). + */ + int draggingFrom = - 1; + + /** + * The number of the column being dragged. + */ + int draggingColumnNumber; + + /** + * The previous preferred width of the column. + */ + int prevPrefWidth = - 1; + + /** + * The timer to coalesce column resizing events. + */ + Timer timer; + + /** + * Returns without action, part of the MouseInputListener interface. + */ public void mouseClicked(MouseEvent e) { - // TODO: Implement this properly. + // Nothing to do. } + /** + * If being in the resizing mode, handle resizing. + */ public void mouseDragged(MouseEvent e) { - // TODO: Implement this properly. + TableColumn resizeIt = header.getResizingColumn(); + if (resizeIt != null && header.getResizingAllowed()) + { + // The timer is intialised on demand. + if (timer == null) + { + // The purpose of timer is to coalesce events. If the queue + // is free, the repaint event is fired immediately. + timer = new Timer(1, new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + header.getTable().doLayout(); + } + }); + timer.setRepeats(false); + timer.setCoalesce(true); + } + resizeIt.setPreferredWidth(prevPrefWidth + e.getX() - draggingFrom); + timer.restart(); + } + else if (draggingHeaderRect != null && header.getReorderingAllowed()) + { + draggingHeaderRect.x = e.getX() + draggingFrom; + header.repaint(); + } } + /** + * Returns without action, part of the MouseInputListener interface. + */ public void mouseEntered(MouseEvent e) { - // TODO: Implement this properly. + // Nothing to do. } + /** + * Reset drag information of the column resizing. + */ public void mouseExited(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingColumn() != null && header.getResizingAllowed()) + endResizing(); + if (header.getDraggedColumn() != null && header.getReorderingAllowed()) + endDragging(null); } + /** + * Change the mouse cursor if the mouse if above the column boundary. + */ public void mouseMoved(MouseEvent e) { - // TODO: Implement this properly. + // When dragging, the functionality is handled by the mouseDragged. + if (e.getButton() == 0 && header.getResizingAllowed()) + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n < 2) + // It must be at least two columns to have at least one boundary. + // Otherwise, nothing to do. + return; + + boolean onBoundary = false; + + int x = e.getX(); + int a = x - COLUMN_BOUNDARY_TOLERANCE; + int b = x + COLUMN_BOUNDARY_TOLERANCE; + + int p = 0; + + Scan: for (int i = 0; i < n - 1; i++) + { + p += model.getColumn(i).getWidth(); + + if (p >= a && p <= b) + { + TableColumn column = model.getColumn(i); + onBoundary = true; + + draggingFrom = x; + prevPrefWidth = column.getWidth(); + header.setResizingColumn(column); + break Scan; + } + } + + if (onBoundary != showingResizeCursor) + { + // Change the cursor shape, if needed. + if (onBoundary) + { + + if (p < x) + header.setCursor(Cursor.getPredefinedCursor + (Cursor.W_RESIZE_CURSOR)); + else + header.setCursor(Cursor.getPredefinedCursor + (Cursor.E_RESIZE_CURSOR)); + } + else + { + header.setCursor(Cursor.getDefaultCursor()); + header.setResizingColumn(null); + } + + showingResizeCursor = onBoundary; + } + } } + /** + * Starts the dragging/resizing procedure. + */ public void mousePressed(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingAllowed()) + { + TableColumn resizingColumn = header.getResizingColumn(); + if (resizingColumn != null) + { + resizingColumn.setPreferredWidth(resizingColumn.getWidth()); + return; + } + } + + if (header.getReorderingAllowed()) + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n < 2) + // It must be at least two columns to change the column location. + return; + + boolean onBoundary = false; + + int x = e.getX(); + int p = 0; + int col = - 1; + + Scan: for (int i = 0; i < n; i++) + { + p += model.getColumn(i).getWidth(); + if (p > x) + { + col = i; + break Scan; + } + } + if (col < 0) + return; + + TableColumn dragIt = model.getColumn(col); + header.setDraggedColumn(dragIt); + + draggingFrom = (p - dragIt.getWidth()) - x; + draggingHeaderRect = new Rectangle(header.getHeaderRect(col)); + draggingColumnNumber = col; + } } + /** + * Set all column preferred width to the current width to prevend abrupt + * width changes during the next resize. + */ public void mouseReleased(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingColumn() != null && header.getResizingAllowed()) + endResizing(); + if (header.getDraggedColumn() != null && header.getReorderingAllowed()) + endDragging(e); + } + + /** + * Stop resizing session. + */ + void endResizing() + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n > 2) + { + TableColumn c; + for (int i = 0; i < n; i++) + { + c = model.getColumn(i); + c.setPreferredWidth(c.getWidth()); + } + } + header.setResizingColumn(null); + showingResizeCursor = false; + if (timer != null) + timer.stop(); + header.setCursor(Cursor.getDefaultCursor()); } - } + /** + * Stop the dragging session. + * + * @param e the "mouse release" mouse event, needed to determing the final + * location for the dragged column. + */ + void endDragging(MouseEvent e) + { + header.setDraggedColumn(null); + + // Return if the mouse have left the header area while pressed. + if (e == null) + { + header.repaint(draggingHeaderRect); + draggingHeaderRect = null; + return; + } + else + draggingHeaderRect = null; + + TableColumnModel model = header.getColumnModel(); + + // Find where have we dragged the column. + int x = e.getX(); + int p = 0; + int col = - 1; + int n = model.getColumnCount(); + + Scan: for (int i = 0; i < n; i++) + { + p += model.getColumn(i).getWidth(); + if (p > x) + { + col = i; + break Scan; + } + } + if (col >= 0) + header.getTable().moveColumn(draggingColumnNumber, col); + } + } + + /** + * Create and return the mouse input listener. + * + * @return the mouse listener ({@link MouseInputHandler}, if not overridden. + */ protected MouseInputListener createMouseInputListener() { return new MouseInputHandler(); } - + + /** + * Construct a new BasicTableHeaderUI, create mouse listeners. + */ public BasicTableHeaderUI() { mouseInputListener = createMouseInputListener(); @@ -131,9 +419,15 @@ public class BasicTableHeaderUI extends TableHeaderUI // TODO: Implement this properly. } + /** + * Add the mouse listener and the mouse motion listener to the table + * header. The listeners support table column resizing and rearrangement + * by mouse. + */ protected void installListeners() { header.addMouseListener(mouseInputListener); + header.addMouseMotionListener(mouseInputListener); } public void installUI(JComponent c) @@ -156,10 +450,14 @@ public class BasicTableHeaderUI extends TableHeaderUI { // TODO: Implement this properly. } - + + /** + * Remove the previously installed listeners. + */ protected void uninstallListeners() { header.removeMouseListener(mouseInputListener); + header.removeMouseMotionListener(mouseInputListener); } public void uninstallUI(JComponent c) @@ -168,7 +466,10 @@ public class BasicTableHeaderUI extends TableHeaderUI uninstallKeyboardActions(); uninstallDefaults(); } - + + /** + * Repaint the table header. + */ public void paint(Graphics gfx, JComponent c) { TableColumnModel cmod = header.getColumnModel(); @@ -206,10 +507,26 @@ public class BasicTableHeaderUI extends TableHeaderUI bounds.width, bounds.height); } } - + + // This displays a running rectangle that is much simplier than the total + // animation, as it is seen in Sun's application. + // TODO animate the collumn dragging like in Sun's jre. + if (draggingHeaderRect!=null) + { + gfx.setColor(header.getForeground()); + gfx.drawRect(draggingHeaderRect.x, draggingHeaderRect.y+2, + draggingHeaderRect.width-1, draggingHeaderRect.height-6); + } } - public Dimension getPreferredSize(JComponent c) + /** + * Get the preferred header size. + * + * @param ignored unused + * + * @return the preferred size of the associated header. + */ + public Dimension getPreferredSize(JComponent ignored) { TableColumnModel cmod = header.getColumnModel(); TableCellRenderer defaultRend = header.getDefaultRenderer(); diff --git a/javax/swing/plaf/basic/BasicTableUI.java b/javax/swing/plaf/basic/BasicTableUI.java index 18b69120d..8360a9ec7 100644 --- a/javax/swing/plaf/basic/BasicTableUI.java +++ b/javax/swing/plaf/basic/BasicTableUI.java @@ -58,11 +58,11 @@ import java.beans.PropertyChangeListener; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.CellRendererPane; +import javax.swing.DefaultCellEditor; import javax.swing.DefaultListSelectionModel; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JTable; -import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.LookAndFeel; @@ -74,8 +74,8 @@ import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.TableUI; +import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; @@ -193,10 +193,31 @@ public class BasicTableUI extends TableUI colModel.setSelectionInterval(lo_col, hi_col); } } - - public void mouseClicked(MouseEvent e) + + /** + * For the double click, start the cell editor. + */ + public void mouseClicked(MouseEvent e) { - // TODO: What should be done here, if anything? + Point p = e.getPoint(); + int row = table.rowAtPoint(p); + int col = table.columnAtPoint(p); + if (table.isCellEditable(row, col)) + { + // If the cell editor is the default editor, we request the + // number of the required clicks from it. Otherwise, + // require two clicks (double click). + TableCellEditor editor = table.getCellEditor(row, col); + if (editor instanceof DefaultCellEditor) + { + DefaultCellEditor ce = (DefaultCellEditor) editor; + if (e.getClickCount() < ce.getClickCountToStart()) + return; + } + else if (e.getClickCount() < 2) + return; + table.editCellAt(row, col); + } } public void mouseDragged(MouseEvent e) @@ -354,7 +375,8 @@ public class BasicTableUI extends TableUI maxTotalColumnWidth += table.getColumnModel().getColumn(i).getMaxWidth(); if (maxTotalColumnWidth == 0 || table.getRowCount() == 0) return null; - return new Dimension(maxTotalColumnWidth, table.getRowCount()*table.getRowHeight()); + return new Dimension(maxTotalColumnWidth, table.getRowCount()* + (table.getRowHeight()+table.getRowMargin())); } /** @@ -380,7 +402,7 @@ public class BasicTableUI extends TableUI public Dimension getPreferredSize(JComponent comp) { int width = table.getColumnModel().getTotalColumnWidth(); - int height = table.getRowCount() * table.getRowHeight(); + int height = table.getRowCount() * (table.getRowHeight()+table.getRowMargin()); return new Dimension(width, height); } @@ -854,6 +876,10 @@ public class BasicTableUI extends TableUI rowModel.setAnchorSelectionIndex(rowLead); colModel.setAnchorSelectionIndex(colLead); } + else if (command.equals("stopEditing")) + { + table.editingStopped(new ChangeEvent(command)); + } else { // If we're here that means we bound this TableAction class @@ -1185,30 +1211,17 @@ public class BasicTableUI extends TableUI * system beginning at (0,0) in the upper left corner of the * table * @param rend A cell renderer to paint with - * @param data The data to provide to the cell renderer - * @param rowLead The lead selection for the rows of the table. - * @param colLead The lead selection for the columns of the table. */ void paintCell(Graphics g, int row, int col, Rectangle bounds, - TableCellRenderer rend, TableModel data, - int rowLead, int colLead) + TableCellRenderer rend) { Component comp = table.prepareRenderer(rend, row, col); rendererPane.paintComponent(g, comp, table, bounds); - - // FIXME: this is manual painting of the Caret, why doesn't the - // JTextField take care of this itself? - if (comp instanceof JTextField) - { - Rectangle oldClip = g.getClipBounds(); - g.translate(bounds.x, bounds.y); - g.clipRect(0, 0, bounds.width, bounds.height); - ((JTextField)comp).getCaret().paint(g); - g.translate(-bounds.x, -bounds.y); - g.setClip(oldClip); - } } + /** + * Paint the associated table. + */ public void paint(Graphics gfx, JComponent ignored) { int ncols = table.getColumnCount(); @@ -1217,59 +1230,72 @@ public class BasicTableUI extends TableUI return; Rectangle clip = gfx.getClipBounds(); - TableColumnModel cols = table.getColumnModel(); - - int height = table.getRowHeight(); - int x0 = 0, y0 = 0; - int x = x0; - int y = y0; - - Dimension gap = table.getIntercellSpacing(); - int ymax = clip.y + clip.height; - int xmax = clip.x + clip.width; + // Determine the range of cells that are within the clip bounds. + Point p1 = new Point(clip.x, clip.y); + int c0 = table.columnAtPoint(p1); + if (c0 == -1) + c0 = 0; + int r0 = table.rowAtPoint(p1); + if (r0 == -1) + r0 = 0; + Point p2 = new Point(clip.x + clip.width, clip.y + clip.height); + int cn = table.columnAtPoint(p2); + if (cn == -1) + cn = table.getColumnCount() - 1; + int rn = table.rowAtPoint(p2); + if (rn == -1) + rn = table.getRowCount() - 1; + + TableColumnModel cmodel = table.getColumnModel(); + int [] widths = new int[cn+1]; + for (int i = c0; i <=cn ; i++) + { + widths[i] = cmodel.getColumn(i).getWidth(); + } + + Rectangle bounds = table.getCellRect(r0, c0, false); + bounds.height = table.getRowHeight()+table.getRowMargin(); + + // The left boundary of the area being repainted. + int left = bounds.x; + + // The top boundary of the area being repainted. + int top = bounds.y; + + // The bottom boundary of the area being repainted. + int bottom; + + // The cell height. + int height = bounds.height; + // paint the cell contents - for (int c = 0; c < ncols && x < xmax; ++c) + Color grid = table.getGridColor(); + for (int r = r0; r <= rn; ++r) { - y = y0; - TableColumn col = cols.getColumn(c); - int width = col.getWidth(); - int halfGapWidth = gap.width / 2; - int halfGapHeight = gap.height / 2; - for (int r = 0; r < nrows && y < ymax; ++r) + for (int c = c0; c <= cn; ++c) { - Rectangle bounds = new Rectangle(x + halfGapWidth, - y + halfGapHeight + 1, - width - gap.width + 1, - height - gap.height); - if (bounds.intersects(clip)) - { - paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c), - table.getModel(), - table.getSelectionModel().getLeadSelectionIndex(), - table.getColumnModel().getSelectionModel().getLeadSelectionIndex()); - } - y += height; + bounds.width = widths[c]; + paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c)); + bounds.x += widths[c]; } - x += width; + bounds.y += height; + bounds.x = left; } - - // tighten up the x and y max bounds - ymax = y; - xmax = x; - - Color grid = table.getGridColor(); + + bottom = bounds.y; // paint vertical grid lines if (grid != null && table.getShowVerticalLines()) { - x = x0; Color save = gfx.getColor(); gfx.setColor(grid); - for (int c = 0; c < ncols && x < xmax; ++c) + int x = left; + + for (int c = c0; c <= cn; ++c) { - x += cols.getColumn(c).getWidth(); - gfx.drawLine(x, y0, x, ymax); + gfx.drawLine(x, top, x, bottom); + x += widths[c]; } gfx.setColor(save); } @@ -1277,13 +1303,13 @@ public class BasicTableUI extends TableUI // paint horizontal grid lines if (grid != null && table.getShowHorizontalLines()) { - y = y0; Color save = gfx.getColor(); gfx.setColor(grid); - for (int r = 0; r < nrows && y < ymax; ++r) + int y = top; + for (int r = r0; r <= rn; ++r) { + gfx.drawLine(left, y, p2.x, y); y += height; - gfx.drawLine(x0, y, xmax, y); } gfx.setColor(save); } diff --git a/javax/swing/plaf/basic/BasicTextUI.java b/javax/swing/plaf/basic/BasicTextUI.java index fc3889484..516049838 100644 --- a/javax/swing/plaf/basic/BasicTextUI.java +++ b/javax/swing/plaf/basic/BasicTextUI.java @@ -1,5 +1,5 @@ /* BasicTextUI.java -- - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -46,15 +46,11 @@ import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; -import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.InputMap; @@ -70,6 +66,7 @@ import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.TextUI; import javax.swing.plaf.UIResource; +import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; import javax.swing.text.Caret; import javax.swing.text.DefaultCaret; @@ -82,6 +79,7 @@ import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; import javax.swing.text.Keymap; import javax.swing.text.Position; +import javax.swing.text.Utilities; import javax.swing.text.View; import javax.swing.text.ViewFactory; @@ -161,11 +159,11 @@ public abstract class BasicTextUI extends TextUI * Indicates that the preferences of one of the child view has changed. * This calls revalidate on the text component. * - * @param view the child view which's preference has changed + * @param v the child view which's preference has changed * @param width true if the width preference has changed * @param height true if the height preference has changed */ - public void preferenceChanged(View view, boolean width, boolean height) + public void preferenceChanged(View v, boolean width, boolean height) { textComponent.revalidate(); } @@ -181,7 +179,7 @@ public abstract class BasicTextUI extends TextUI view.setParent(null); if (v != null) - v.setParent(null); + v.setParent(this); view = v; } @@ -207,10 +205,10 @@ public abstract class BasicTextUI extends TextUI */ public int getViewCount() { + int count = 0; if (view != null) - return 1; - else - return 0; + count = 1; + return count; } /** @@ -249,7 +247,11 @@ public abstract class BasicTextUI extends TextUI public void paint(Graphics g, Shape s) { if (view != null) - view.paint(g, s); + { + Rectangle b = s.getBounds(); + view.setSize(b.width, b.height); + view.paint(g, s); + } } @@ -277,7 +279,7 @@ public abstract class BasicTextUI extends TextUI public Shape modelToView(int position, Shape a, Position.Bias bias) throws BadLocationException { - return ((View) view).modelToView(position, a, bias); + return view.modelToView(position, a, bias); } /** @@ -368,7 +370,7 @@ public abstract class BasicTextUI extends TextUI /** * Receives notifications when properties of the text component change. */ - class PropertyChangeHandler implements PropertyChangeListener + private class PropertyChangeHandler implements PropertyChangeListener { /** * Notifies when a property of the text component changes. @@ -448,7 +450,7 @@ public abstract class BasicTextUI extends TextUI /** * Receives notification when the model changes. */ - PropertyChangeHandler updateHandler = new PropertyChangeHandler(); + private PropertyChangeHandler updateHandler = new PropertyChangeHandler(); /** The DocumentEvent handler. */ DocumentHandler documentHandler = new DocumentHandler(); @@ -515,20 +517,19 @@ public abstract class BasicTextUI extends TextUI c.setOpaque(true); textComponent = (JTextComponent) c; - Document doc = textComponent.getDocument(); if (doc == null) { - doc = getEditorKit(textComponent).createDefaultDocument(); - textComponent.setDocument(doc); + doc = getEditorKit(textComponent).createDefaultDocument(); + textComponent.setDocument(doc); } - - textComponent.addPropertyChangeListener(updateHandler); - modelChanged(); - installDefaults(); installListeners(); installKeyboardActions(); + + // We need to trigger this so that the view hierarchy gets initialized. + modelChanged(); + } /** @@ -584,6 +585,7 @@ public abstract class BasicTextUI extends TextUI protected void installListeners() { textComponent.addFocusListener(focuslistener); + textComponent.addPropertyChangeListener(updateHandler); installDocumentListeners(); } @@ -621,6 +623,11 @@ public abstract class BasicTextUI extends TextUI */ protected Keymap createKeymap() { + // FIXME: It seems to me that this method implementation is wrong. It seems + // to fetch the focusInputMap and transform it to the KeyBinding/Keymap + // implemenation. I would think that it should be done the other way, + // fetching the keybindings (from prefix + ".bindings") and transform + // it to the newer InputMap/ActionMap implementation. JTextComponent.KeyBinding[] bindings = null; String prefix = getPropertyPrefix(); InputMapUIResource m = (InputMapUIResource) UIManager.get(prefix + ".focusInputMap"); @@ -637,10 +644,7 @@ public abstract class BasicTextUI extends TextUI } } if (bindings == null) - { - bindings = new JTextComponent.KeyBinding[0]; - UIManager.put(prefix + ".focusInputMap", bindings); - } + bindings = new JTextComponent.KeyBinding[0]; Keymap km = JTextComponent.addKeymap(getKeymapName(), JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP)); @@ -726,8 +730,6 @@ public abstract class BasicTextUI extends TextUI super.uninstallUI(component); rootView.setView(null); - textComponent.removePropertyChangeListener(updateHandler); - uninstallDefaults(); uninstallListeners(); uninstallKeyboardActions(); @@ -750,6 +752,7 @@ public abstract class BasicTextUI extends TextUI */ protected void uninstallListeners() { + textComponent.removePropertyChangeListener(updateHandler); textComponent.removeFocusListener(focuslistener); textComponent.getDocument().removeDocumentListener(documentHandler); } @@ -786,7 +789,9 @@ public abstract class BasicTextUI extends TextUI float w = v.getPreferredSpan(View.X_AXIS); float h = v.getPreferredSpan(View.Y_AXIS); - return new Dimension((int) w, (int) h); + Insets i = c.getInsets(); + return new Dimension((int) w + i.left + i.right, + (int) h + i.top + i.bottom); } /** @@ -817,18 +822,49 @@ public abstract class BasicTextUI extends TextUI } /** - * Paints the text component. + * Paints the text component. This acquires a read lock on the model and then + * calls {@link #paintSafely(Graphics)} in order to actually perform the + * painting. * * @param g the Graphics context to paint to * @param c not used here */ public final void paint(Graphics g, JComponent c) { - paintSafely(g); + try + { + Document doc = textComponent.getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument aDoc = (AbstractDocument) doc; + aDoc.readLock(); + } + + paintSafely(g); + } + finally + { + Document doc = textComponent.getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument aDoc = (AbstractDocument) doc; + aDoc.readUnlock(); + } + } } /** - * Actually performs the painting. + * This paints the text component while beeing sure that the model is not + * modified while painting. + * + * The following is performed in this order: + *

        + *
      1. If the text component is opaque, the background is painted by + * calling {@link #paintBackground(Graphics)}.
      2. + *
      3. If there is a highlighter, the highlighter is painted.
      4. + *
      5. The view hierarchy is painted.
      6. + *
      7. The Caret is painter.
      8. + *
      * * @param g the Graphics context to paint to */ @@ -840,9 +876,19 @@ public abstract class BasicTextUI extends TextUI if (textComponent.isOpaque()) paintBackground(g); - if (highlighter != null - && textComponent.getSelectionStart() != textComponent.getSelectionEnd()) - highlighter.paint(g); + // Try painting with the highlighter without checking whether there + // is a selection because a highlighter can be used to do more than + // marking selected text. + if (highlighter != null) + { + // Handle restoring of the color here to prevent + // drawing problems when the Highlighter implementor + // forgets to restore it. + Color oldColor = g.getColor(); + highlighter.paint(g); + g.setColor(oldColor); + } + rootView.paint(g, getVisibleEditorRect()); @@ -857,10 +903,23 @@ public abstract class BasicTextUI extends TextUI */ protected void paintBackground(Graphics g) { - // This method does nothing. All the background filling is done by the - // ComponentUI update method. However, the method is called by paint - // to provide a way for subclasses to draw something different (e.g. - // background images etc) on the background. + Color old = g.getColor(); + g.setColor(textComponent.getBackground()); + g.fillRect(0, 0, textComponent.getWidth(), textComponent.getHeight()); + g.setColor(old); + } + + /** + * Overridden for better control over background painting. This now simply + * calls {@link #paint} and this delegates the background painting to + * {@link #paintBackground}. + * + * @param g the graphics to use + * @param c the component to be painted + */ + public void update(Graphics g, JComponent c) + { + paint(g, c); } /** @@ -895,7 +954,84 @@ public abstract class BasicTextUI extends TextUI public void damageRange(JTextComponent t, int p0, int p1, Position.Bias firstBias, Position.Bias secondBias) { - // TODO: Implement me. + try + { + // Limit p0 and p1 to sane values to prevent unfriendly + // BadLocationExceptions. This makes it possible for the highlighter + // to send us illegal values which can happen when a large number + // of selected characters are removed (eg. by pressing delete + // or backspace). + // The reference implementation does not throw an exception, too. + p0 = Math.min(p0, t.getDocument().getLength()); + p1 = Math.min(p1, t.getDocument().getLength()); + + Rectangle l1 = modelToView(t, p0, firstBias); + Rectangle l2 = modelToView(t, p1, secondBias); + if (l1.y == l2.y) + t.repaint(l1.union(l2)); + else + { + // The two rectangles lie on different lines and we need a + // different algorithm to calculate the damaged area: + // 1. The line of p0 is damaged from the position of p0 + // to the right border. + // 2. All lines between the ones where p0 and p1 lie on + // are completely damaged. Use the allocation area to find + // out the bounds. + // 3. The final line is damaged from the left bound to the + // position of p1. + Insets insets = t.getInsets(); + + // Damage first line until the end. + l1.width = insets.right + t.getWidth() - l1.x; + t.repaint(l1); + + // Note: Utilities.getPositionBelow() may return the offset + // that was put in. In that case there is no next line and + // we should stop searching for one. + + int posBelow = Utilities.getPositionBelow(t, p0, l1.x); + if (posBelow < p1 && posBelow != -1 && posBelow != p0) + { + // Take the rectangle of the offset we just found and grow it + // to the maximum width. Retain y because this is our start + // height. + Rectangle grow = modelToView(t, posBelow); + grow.x = insets.left; + grow.width = t.getWidth() + insets.right; + + // Find further lines which have to be damaged completely. + int nextPosBelow = posBelow; + while (nextPosBelow < p1 && nextPosBelow != -1 && posBelow != nextPosBelow) + { + posBelow = nextPosBelow; + nextPosBelow = Utilities.getPositionBelow(t, posBelow, l1.x); + } + // Now posBelow is an offset on the last line which has to be damaged + // completely. (newPosBelow is on the same line as p1) + + // Retrieve the rectangle of posBelow and use its y and height + // value to calculate the final height of the multiple line + // spanning rectangle. + Rectangle end = modelToView(t, posBelow); + grow.height = end.y + end.height - grow.y; + + // Mark that area as damage. + t.repaint(grow); + } + + // Damage last line from its beginning to the position of p1. + l2.width += l2.x; + l2.x = insets.left; + t.repaint(l2); + } + } + catch (BadLocationException ex) + { + AssertionError err = new AssertionError("Unexpected bad location"); + err.initCause(ex); + throw err; + } } /** @@ -1061,7 +1197,6 @@ public abstract class BasicTextUI extends TextUI */ protected Rectangle getVisibleEditorRect() { - JTextComponent textComponent = getComponent(); int width = textComponent.getWidth(); int height = textComponent.getHeight(); @@ -1082,7 +1217,6 @@ public abstract class BasicTextUI extends TextUI protected final void setView(View view) { rootView.setView(view); - view.setParent(rootView); textComponent.revalidate(); textComponent.repaint(); } diff --git a/javax/swing/plaf/basic/BasicTreeUI.java b/javax/swing/plaf/basic/BasicTreeUI.java index 3bb803a56..b7913e0a1 100644 --- a/javax/swing/plaf/basic/BasicTreeUI.java +++ b/javax/swing/plaf/basic/BasicTreeUI.java @@ -45,6 +45,7 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; +import java.awt.Label; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -114,9 +115,18 @@ import javax.swing.tree.TreeSelectionModel; * @see javax.swing.JTree * @author Lillian Angel (langel@redhat.com) * @author Sascha Brawer (brawer@dandelis.ch) + * @author Audrius Meskauskas (audriusa@bioinformatics.org) */ public class BasicTreeUI extends TreeUI { + /** + * The tree cell editing may be started by the single mouse click on the + * selected cell. To separate it from the double mouse click, the editing + * session starts after this time (in ms) after that single click, and only + * no other clicks were performed during that time. + */ + static int WAIT_TILL_EDITING = 900; + /** Collapse Icon for the tree. */ protected transient Icon collapsedIcon; @@ -225,12 +235,6 @@ public class BasicTreeUI extends TreeUI /** Set to true if the editor has a different size than the renderer. */ protected boolean editorHasDifferentSize; - /** The action listener for the editor's Timer. */ - Timer editorTimer = new EditorUpdateTimer(); - - /** The new value of the node after editing. */ - Object newVal; - /** The action bound to KeyStrokes. */ TreeAction action; @@ -266,6 +270,20 @@ public class BasicTreeUI extends TreeUI private TreeExpansionListener treeExpansionListener; private TreeModelListener treeModelListener; + + /** + * This timer fires the editing action after about 1200 ms if not reset during + * that time. It handles the editing start with the single mouse click + * (and not the double mouse click) on the selected tree node. + */ + Timer startEditTimer; + + /** + * The special value of the mouse event is sent indicating that this is not + * just the mouse click, but the mouse click on the selected node. Sending + * such event forces to start the cell editing session. + */ + static final MouseEvent EDIT = new MouseEvent(new Label(), 7,7,7,7,7,7, false); /** * Creates a new BasicTreeUI object. @@ -303,7 +321,7 @@ public class BasicTreeUI extends TreeUI { return new BasicTreeUI(); } - + /** * Returns the Hash color. * @@ -796,7 +814,10 @@ public class BasicTreeUI extends TreeUI public boolean stopEditing(JTree tree) { if (isEditing(tree)) - completeEditing(true, false, false); + { + completeEditing(false, false, true); + finish(); + } return !isEditing(tree); } @@ -807,9 +828,12 @@ public class BasicTreeUI extends TreeUI * is the tree to cancel the editing session on. */ public void cancelEditing(JTree tree) - { - if (isEditing(tree)) - completeEditing(false, true, false); + { + // There is no need to send the cancel message to the editor, + // as the cancellation event itself arrives from it. This would + // only be necessary when cancelling the editing programatically. + completeEditing(false, false, false); + finish(); } /** @@ -1213,6 +1237,7 @@ public class BasicTreeUI extends TreeUI protected void updateCachedPreferredSize() { int maxWidth = 0; + updateCurrentVisiblePath(); boolean isLeaf = false; if (currentVisiblePath != null) { @@ -1246,7 +1271,7 @@ public class BasicTreeUI extends TreeUI protected void pathWasExpanded(TreePath path) { validCachedPreferredSize = false; - tree.repaint(); + tree.repaint(); } /** @@ -1271,7 +1296,6 @@ public class BasicTreeUI extends TreeUI leftChildIndent = UIManager.getInt("Tree.leftChildIndent"); setRowHeight(UIManager.getInt("Tree.rowHeight")); tree.setRowHeight(getRowHeight()); - tree.requestFocusInWindow(false); tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand")); setExpandedIcon(UIManager.getIcon("Tree.expandedIcon")); setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon")); @@ -1621,7 +1645,14 @@ public class BasicTreeUI extends TreeUI } if (messageTree) - treeModel.valueForPathChanged(tree.getLeadSelectionPath(), newVal); + { + TreeCellEditor editor = getCellEditor(); + if (editor != null) + { + Object value = editor.getCellEditorValue(); + treeModel.valueForPathChanged(tree.getLeadSelectionPath(), value); + } + } } /** @@ -1636,44 +1667,48 @@ public class BasicTreeUI extends TreeUI */ protected boolean startEditing(TreePath path, MouseEvent event) { - int x; - int y; - if (event == null) - { - Rectangle bounds = getPathBounds(tree, path); - x = bounds.x; - y = bounds.y; - } - else - { - x = event.getX(); - y = event.getY(); - } + // Force to recalculate the maximal row height. + maxHeight = 0; + + // Force to recalculate the cached preferred size. + validCachedPreferredSize = false; updateCellEditor(); TreeCellEditor ed = getCellEditor(); - if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event)) + + if (ed != null + && (event == EDIT || ed.shouldSelectCell(event)) + && ed.isCellEditable(event)) { + Rectangle bounds = getPathBounds(tree, path); + + // Extend the right boundary till the tree width. + bounds.width = tree.getWidth() - bounds.x; + editingPath = path; editingRow = tree.getRowForPath(editingPath); - Object val = editingPath.getLastPathComponent(); - cellEditor.addCellEditorListener(cellEditorListener); + Object value = editingPath.getLastPathComponent(); + stopEditingInCompleteEditing = false; boolean expanded = tree.isExpanded(editingPath); isEditing = true; - editingComponent = ed.getTreeCellEditorComponent(tree, val, true, + editingComponent = ed.getTreeCellEditorComponent(tree, value, true, expanded, isLeaf(editingRow), editingRow); - editingComponent.getParent().setVisible(true); - editingComponent.getParent().validate(); - tree.add(editingComponent.getParent()); - editingComponent.getParent().validate(); - validCachedPreferredSize = false; - - ((JTextField) editingComponent).requestFocusInWindow(false); - editorTimer.start(); + + // Remove all previous components (if still present). Only one + // container with the editing component inside is allowed in the tree. + tree.removeAll(); + + // The editing component must be added to its container. We add the + // container, not the editing component itself. + Component container = editingComponent.getParent(); + container.setBounds(bounds); + tree.add(container); + editingComponent.requestFocus(); + return true; } return false; @@ -1922,7 +1957,7 @@ public class BasicTreeUI extends TreeUI tree.clearSelection(); if (tree.isEditing() && !e.getActionCommand().equals("startEditing")) - tree.cancelEditing(); + tree.stopEditing(); tree.scrollPathToVisible(lead); } @@ -1957,51 +1992,7 @@ public class BasicTreeUI extends TreeUI } } - /** - * The timer that updates the editor component. - */ - private class EditorUpdateTimer extends Timer implements ActionListener - { - /** - * Creates a new EditorUpdateTimer object with a default delay of 0.3 - * seconds. - */ - public EditorUpdateTimer() - { - super(300, null); - addActionListener(this); - } - - /** - * Lets the caret blink and repaints the table. - */ - public void actionPerformed(ActionEvent ev) - { - Caret c = ((JTextField) editingComponent).getCaret(); - if (c != null) - c.setVisible(!c.isVisible()); - tree.repaint(); - } - - /** - * Updates the blink delay according to the current caret. - */ - public void update() - { - stop(); - Caret c = ((JTextField) editingComponent).getCaret(); - if (c != null) - { - setDelay(c.getBlinkRate()); - if (((JTextField) editingComponent).isEditable()) - start(); - else - c.setVisible(false); - } - } - } - - /** + /** * Updates the preferred size when scrolling, if necessary. */ public class ComponentHandler extends ComponentAdapter implements @@ -2089,29 +2080,7 @@ public class BasicTreeUI extends TreeUI */ public void editingStopped(ChangeEvent e) { - editingPath = null; - editingRow = -1; - stopEditingInCompleteEditing = false; - if (editingComponent != null) - { - tree.remove(editingComponent.getParent()); - editingComponent = null; - } - if (cellEditor != null) - { - newVal = ((JTextField) getCellEditor().getCellEditorValue()).getText(); - completeEditing(false, false, true); - if (cellEditor instanceof DefaultTreeCellEditor) - tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor); - cellEditor.removeCellEditorListener(cellEditorListener); - setCellEditor(null); - createdCellEditor = false; - } - isEditing = false; - tree.requestFocusInWindow(false); - editorTimer.stop(); - validCachedPreferredSize = false; - tree.repaint(); + stopEditing(tree); } /** @@ -2123,25 +2092,7 @@ public class BasicTreeUI extends TreeUI */ public void editingCanceled(ChangeEvent e) { - editingPath = null; - editingRow = -1; - stopEditingInCompleteEditing = false; - if (editingComponent != null) - tree.remove(editingComponent.getParent()); - editingComponent = null; - if (cellEditor != null) - { - if (cellEditor instanceof DefaultTreeCellEditor) - tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor); - cellEditor.removeCellEditorListener(cellEditorListener); - setCellEditor(null); - createdCellEditor = false; - } - tree.requestFocusInWindow(false); - editorTimer.stop(); - isEditing = false; - validCachedPreferredSize = false; - tree.repaint(); + cancelEditing(tree); } }// CellEditorHandler @@ -2261,7 +2212,15 @@ public class BasicTreeUI extends TreeUI * is the mouse event that occured */ public void mousePressed(MouseEvent e) - { + { + // Any mouse click cancels the previous waiting edit action, initiated + // by the single click on the selected node. + if (startEditTimer != null) + { + startEditTimer.stop(); + startEditTimer = null; + } + Point click = e.getPoint(); TreePath path = getClosestPathForLocation(tree, click.x, click.y); @@ -2298,9 +2257,37 @@ public class BasicTreeUI extends TreeUI { if (inBounds) { - selectPath(tree, path); - if (e.getClickCount() == 2 && !isLeaf(row)) - toggleExpandState(path); + TreePath currentLead = tree.getLeadSelectionPath(); + if ( + currentLead != null && + currentLead.equals(path) && + e.getClickCount() == 1 && + tree.isEditable() + ) + { + // Schedule the editing session. + final TreePath editPath = path; + + if (startEditTimer != null) + startEditTimer.stop(); + + startEditTimer = new Timer(WAIT_TILL_EDITING, + new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + startEditing(editPath, EDIT); + } + }); + startEditTimer.setRepeats(false); + startEditTimer.start(); + } + else + { + selectPath(tree, path); + if (e.getClickCount() == 2 && !isLeaf(row)) + toggleExpandState(path); + } } if (cntlClick) @@ -2686,7 +2673,7 @@ public class BasicTreeUI extends TreeUI public class TreeHomeAction extends AbstractAction { - /** direction is either home or end */ + /** The direction, either home or end */ protected int direction; /** @@ -2983,7 +2970,7 @@ public class BasicTreeUI extends TreeUI public void valueChanged(TreeSelectionEvent event) { if (tree.isEditing()) - tree.cancelEditing(); + tree.stopEditing(); } }// TreeSelectionHandler @@ -3650,25 +3637,14 @@ public class BasicTreeUI extends TreeUI if (row != 0) bounds.x += gap; bounds.width = preferredSize.width + bounds.x; - if (editingComponent != null && editingPath != null && isEditing(tree) - && node.equals(editingPath.getLastPathComponent())) - { - rendererPane.paintComponent(g, editingComponent.getParent(), null, - bounds); - } - else - { - TreeCellRenderer dtcr = tree.getCellRenderer(); - if (dtcr == null) - dtcr = createDefaultCellRenderer(); - - Component c = dtcr.getTreeCellRendererComponent(tree, node, - selected, - isExpanded, isLeaf, - row, - tree.hasFocus()); - rendererPane.paintComponent(g, c, c.getParent(), bounds); - } + TreeCellRenderer dtcr = tree.getCellRenderer(); + if (dtcr == null) + dtcr = createDefaultCellRenderer(); + + Component c = dtcr.getTreeCellRendererComponent(tree, node, selected, + isExpanded, isLeaf, + row, tree.hasFocus()); + rendererPane.paintComponent(g, c, c.getParent(), bounds); } } @@ -3801,4 +3777,21 @@ public class BasicTreeUI extends TreeUI } return null; } + + /** + * Finish the editing session. + */ + void finish() + { + editingPath = null; + editingRow = -1; + stopEditingInCompleteEditing = false; + isEditing = false; + tree.removeAll(); + validCachedPreferredSize = false; + + // Repaint the region, where was the editing component. + tree.repaint(editingComponent.getParent().getBounds()); + editingComponent = null; + } } // BasicTreeUI diff --git a/javax/swing/plaf/metal/MetalBorders.java b/javax/swing/plaf/metal/MetalBorders.java index 28143d51e..99c90acdb 100644 --- a/javax/swing/plaf/metal/MetalBorders.java +++ b/javax/swing/plaf/metal/MetalBorders.java @@ -1,5 +1,5 @@ /* MetalBorders.java - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -249,30 +249,27 @@ public class MetalBorders /** * Returns the insets of the ButtonBorder. * - * @param c the component for which the border is used + * @param c the component for which the border is used (ignored). * - * @return The insets of the ButtonBorder + * @return The insets of the ButtonBorder. */ public Insets getBorderInsets(Component c) { - return getBorderInsets(c, null); + return borderInsets; } /** * Returns the insets of the ButtonBorder in the specified * newInsets object. * - * @param c the component for which the border is used - * @param newInsets the insets object where to put the values (if - * null, a new instance is created). + * @param c the component for which the border is used (ignored). + * @param newInsets the insets object where to put the values ( + * null not permitted). * - * @return The insets. + * @return The newInsets reference. */ public Insets getBorderInsets(Component c, Insets newInsets) { - if (newInsets == null) - newInsets = new Insets(0, 0, 0, 0); - newInsets.bottom = borderInsets.bottom; newInsets.left = borderInsets.left; newInsets.right = borderInsets.right; @@ -352,6 +349,8 @@ public class MetalBorders public static class Flush3DBorder extends AbstractBorder implements UIResource { + private static final Insets borderInsets = new Insets(2, 2, 2, 2); + /** * Creates a new border instance. */ @@ -369,26 +368,25 @@ public class MetalBorders */ public Insets getBorderInsets(Component c) { - return getBorderInsets(c, null); + return borderInsets; } /** * Returns the border insets. * * @param c the component (ignored). - * @return The border insets. + * @param newInsets an existing insets instance, that will be populated + * with the border insets and returned as the result + * (null not permitted). + * + * @return The newInsets reference. */ public Insets getBorderInsets(Component c, Insets newInsets) { - if (newInsets == null) - newInsets = new Insets(2, 2, 2, 2); - else - { - newInsets.top = 2; - newInsets.left = 2; - newInsets.bottom = 2; - newInsets.right = 2; - } + newInsets.top = borderInsets.top; + newInsets.left = borderInsets.left; + newInsets.bottom = borderInsets.bottom; + newInsets.right = borderInsets.right; return newInsets; } @@ -427,6 +425,8 @@ public class MetalBorders public static class PaletteBorder extends AbstractBorder implements UIResource { + private static final Insets borderInsets = new Insets(1, 1, 1, 1); + /** * Creates a new PaletteBorder. */ @@ -444,29 +444,25 @@ public class MetalBorders */ public Insets getBorderInsets(Component c) { - return getBorderInsets(c, null); + return borderInsets; } /** * Returns the border insets. * * @param c the component (ignored). - * @param newInsets the insets object that, if non-null, will - * be populated with the result from this method. - * - * @return The border insets. + * @param newInsets an existing insets instance, that will be populated + * with the border insets and returned as the result + * (null not permitted). + * + * @return The newInsets reference. */ public Insets getBorderInsets(Component c, Insets newInsets) { - if (newInsets == null) - newInsets = new Insets(1, 1, 1, 1); - else - { - newInsets.top = 1; - newInsets.left = 1; - newInsets.bottom = 1; - newInsets.right = 1; - } + newInsets.top = borderInsets.top; + newInsets.left = borderInsets.left; + newInsets.bottom = borderInsets.bottom; + newInsets.right = borderInsets.right; return newInsets; } @@ -555,6 +551,8 @@ public class MetalBorders public static class InternalFrameBorder extends AbstractBorder implements UIResource { + private static final Insets borderInsets = new Insets(5, 5, 5, 5); + /** * Creates a new border instance. */ @@ -572,26 +570,25 @@ public class MetalBorders */ public Insets getBorderInsets(Component c) { - return getBorderInsets(c, null); + return borderInsets; } /** * Returns the border insets. * * @param c the component (ignored). - * @return The border insets. + * @param newInsets an existing insets instance, that will be populated + * with the border insets and returned as the result + * (null not permitted). + * + * @return The newInsets reference. */ public Insets getBorderInsets(Component c, Insets newInsets) { - if (newInsets == null) - newInsets = new Insets(5, 5, 5, 5); - else - { - newInsets.top = 5; - newInsets.left = 5; - newInsets.bottom = 5; - newInsets.right = 5; - } + newInsets.top = borderInsets.top; + newInsets.left = borderInsets.left; + newInsets.bottom = borderInsets.bottom; + newInsets.right = borderInsets.right; return newInsets; } @@ -763,7 +760,7 @@ public class MetalBorders implements UIResource { /** The border insets. */ - protected static Insets borderInsets = new Insets(1, 1, 1, 1); + protected static Insets borderInsets = new Insets(2, 2, 2, 2); /** * Creates a new border instance. diff --git a/javax/swing/plaf/metal/MetalFileChooserUI.java b/javax/swing/plaf/metal/MetalFileChooserUI.java index 967c40d29..76f92f515 100644 --- a/javax/swing/plaf/metal/MetalFileChooserUI.java +++ b/javax/swing/plaf/metal/MetalFileChooserUI.java @@ -1545,8 +1545,6 @@ public class MetalFileChooserUI fileListPanel = new JPanel(new BorderLayout()); fileList = new JList(getModel()); scrollPane = new JScrollPane(fileList); - scrollPane.setVerticalScrollBarPolicy - (JScrollPane.VERTICAL_SCROLLBAR_NEVER); fileList.setLayoutOrientation(JList.VERTICAL_WRAP); fileList.setCellRenderer(new FileRenderer()); } diff --git a/javax/swing/plaf/metal/MetalLookAndFeel.java b/javax/swing/plaf/metal/MetalLookAndFeel.java index 5acccd6e4..1bab5add8 100644 --- a/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -1171,6 +1171,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel "Spinner.arrowButtonInsets", new InsetsUIResource(0, 0, 0, 0), "Spinner.background", getControl(), + "Spinner.border", MetalBorders.getTextFieldBorder(), "Spinner.font", new FontUIResource("Dialog", Font.BOLD, 12), "Spinner.foreground", getControl(), @@ -1342,4 +1343,16 @@ public class MetalLookAndFeel extends BasicLookAndFeel { return theme; } + + /** + * Returns true because the Metal look + * and feel supports window decorations for toplevel + * containers. + * + * @return true + */ + public boolean getSupportsWindowDecorations() + { + return true; + } } diff --git a/javax/swing/plaf/metal/MetalRootPaneUI.java b/javax/swing/plaf/metal/MetalRootPaneUI.java index faed80382..23051e9bc 100644 --- a/javax/swing/plaf/metal/MetalRootPaneUI.java +++ b/javax/swing/plaf/metal/MetalRootPaneUI.java @@ -1,5 +1,5 @@ /* MetalRootPaneUI.java - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,23 +38,842 @@ exception statement from your version. */ package javax.swing.plaf.metal; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.LayoutManager2; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.beans.PropertyChangeEvent; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JButton; import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuBar; import javax.swing.JRootPane; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicRootPaneUI; /** - * A UI delegate for the {@link JRootPane} component. This class is not fully - * implemented. + * A UI delegate for the {@link JRootPane} component. This implementation + * supports the JRootPane windowDecorationStyle property. * + * @author Roman Kennke (kennke@aicas.com) + * * @since 1.4 */ public class MetalRootPaneUI extends BasicRootPaneUI { - // FIXME: maybe replace by a Map of instances when this becomes stateful - /** The shared UI instance for MetalRootPaneUIs */ + /** + * The border that is used on JRootPane when the windowDecorationStyle + * property of the JRootPane is set to a different value than NONE. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private static class MetalFrameBorder + extends AbstractBorder + { + /** + * Returns the border insets. + * + * @param c the component + * @param newInsets the insets to be filled with the return value, may be + * null in which case a new object is created + * + * @return the border insets + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + if (newInsets == null) + newInsets = new Insets(5, 5, 5, 5); + else + { + newInsets.top = 5; + newInsets.left = 5; + newInsets.bottom = 5; + newInsets.right = 5; + } + return newInsets; + } + + /** + * Returns the border insets. + * + * @param c the component + * + * @return the border insets + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Paints the border for the specified component. + * + * @param c the component + * @param g the graphics device + * @param x the x-coordinate + * @param y the y-coordinate + * @param w the width + * @param h the height + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + JRootPane f = (JRootPane) c; + Window frame = SwingUtilities.getWindowAncestor(f); + if (frame.isActive()) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // Fill the border background. + g.fillRect(x, y, w, 5); + g.fillRect(x, y, 5, h); + g.fillRect(x + w - 5, y, 5, h); + g.fillRect(x, y + h - 5, w, 5); + + // Draw a dot in each corner. + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x, y, 1, 1); + g.fillRect(x + w - 1, y, 1, 1); + g.fillRect(x + w - 1, y + h - 1, 1, 1); + g.fillRect(x, y + h - 1, 1, 1); + + // Draw the lines. + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x + 14, y + 2, x + w - 15, y + 2); + g.drawLine(x + 14, y + h - 3, x + w - 15, y + h - 3); + g.drawLine(x + 2, y + 14, x + 2, y + h - 15); + g.drawLine(x + w - 3, y + 14, x + w - 3, y + h - 15); + + // Draw the line highlights. + if (frame.isActive()) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x + 15, y + 3, x + w - 14, y + 3); + g.drawLine(x + 15, y + h - 2, x + w - 14, y + h - 2); + g.drawLine(x + 3, y + 15, x + 3, y + h - 14); + g.drawLine(x + w - 2, y + 15, x + w - 2, y + h - 14); + } + } + + /** + * The component that renders the title bar for frames. This duplicates + * most of {@link MetalInternalFrameTitlePane}. It is not reasonably possible + * to reuse that class because that is bound to the JInternalFrame and we + * need to handle JFrames/JRootPanes here. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private static class MetalTitlePane extends JComponent + { + /** + * The Action responsible for closing the JInternalFrame. + */ + private class CloseAction extends AbstractAction + { + /** + * Creates a new action. + */ + public CloseAction() + { + super("Close"); + } + + /** + * This method is called when something closes the frame. + * + * @param e the ActionEvent + */ + public void actionPerformed(ActionEvent e) + { + Window frame = SwingUtilities.getWindowAncestor(rootPane); + if (frame instanceof JFrame) + { + JFrame jframe = (JFrame) frame; + switch (jframe.getDefaultCloseOperation()) + { + case JFrame.EXIT_ON_CLOSE: + jframe.setVisible(false); + jframe.dispose(); + System.exit(0); + break; + case JFrame.DISPOSE_ON_CLOSE: + jframe.setVisible(false); + jframe.dispose(); + break; + case JFrame.HIDE_ON_CLOSE: + jframe.setVisible(false); + break; + case JFrame.DO_NOTHING_ON_CLOSE: + default: + break; + } + } + else if (frame instanceof JDialog) + { + JDialog jdialog = (JDialog) frame; + switch (jdialog.getDefaultCloseOperation()) + { + case JFrame.DISPOSE_ON_CLOSE: + jdialog.setVisible(false); + jdialog.dispose(); + break; + case JFrame.HIDE_ON_CLOSE: + jdialog.setVisible(false); + break; + case JFrame.DO_NOTHING_ON_CLOSE: + default: + break; + } + } + } + } + + /** + * This helper class is used to create the minimize, maximize and close + * buttons in the top right corner of the Title Pane. These buttons are + * special since they cannot be given focus and have no border. + */ + private class PaneButton extends JButton + { + /** + * Creates a new PaneButton object with the given Action. + * + * @param a The Action that the button uses. + */ + public PaneButton(Action a) + { + super(a); + setMargin(new Insets(0, 0, 0, 0)); + } + + /** + * This method returns true if the Component can be focused. + * + * @return false. + */ + public boolean isFocusable() + { + // These buttons cannot be given focus. + return false; + } + + } + + /** + * The layout for the JRootPane when the windowDecorationStyle + * property is set. In addition to the usual JRootPane.RootLayout behaviour + * this lays out the titlePane. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class MetalTitlePaneLayout implements LayoutManager + { + /** + * Creates a new TitlePaneLayout object. + */ + public MetalTitlePaneLayout() + { + // Do nothing. + } + + /** + * Adds a Component to the Container. + * + * @param name The name to reference the added Component by. + * @param c The Component to add. + */ + public void addLayoutComponent(String name, Component c) + { + // Do nothing. + } + + /** + * This method is called to lay out the children of the Title Pane. + * + * @param c The Container to lay out. + */ + public void layoutContainer(Container c) + { + + Dimension size = c.getSize(); + Insets insets = c.getInsets(); + int width = size.width - insets.left - insets.right; + int height = size.height - insets.top - insets.bottom; + + int loc = width - insets.right - 1; + int top = insets.top + 2; + int buttonHeight = height - 4; + if (closeButton.isVisible()) + { + int buttonWidth = closeIcon.getIconWidth(); + loc -= buttonWidth + 2; + closeButton.setBounds(loc, top, buttonWidth, buttonHeight); + loc -= 6; + } + + if (maxButton.isVisible()) + { + int buttonWidth = maxIcon.getIconWidth(); + loc -= buttonWidth + 4; + maxButton.setBounds(loc, top, buttonWidth, buttonHeight); + } + + if (iconButton.isVisible()) + { + int buttonWidth = minIcon.getIconWidth(); + loc -= buttonWidth + 4; + iconButton.setBounds(loc, top, buttonWidth, buttonHeight); + loc -= 2; + } + + Dimension titlePreferredSize = title.getPreferredSize(); + title.setBounds(insets.left + 5, insets.top, + Math.min(titlePreferredSize.width, loc - insets.left - 10), + height); + + } + + /** + * This method returns the minimum size of the given Container given the + * children that it has. + * + * @param c The Container to get a minimum size for. + * + * @return The minimum size of the Container. + */ + public Dimension minimumLayoutSize(Container c) + { + return preferredLayoutSize(c); + } + + /** + * Returns the preferred size of the given Container taking + * into account the children that it has. + * + * @param c The Container to lay out. + * + * @return The preferred size of the Container. + */ + public Dimension preferredLayoutSize(Container c) + { + return new Dimension(22, 22); + } + + /** + * Removes a Component from the Container. + * + * @param c The Component to remove. + */ + public void removeLayoutComponent(Component c) + { + // Nothing to do here. + } + } + + JRootPane rootPane; + + /** The button that closes the JInternalFrame. */ + JButton closeButton; + + /** The button that iconifies the JInternalFrame. */ + JButton iconButton; + + /** The button that maximizes the JInternalFrame. */ + JButton maxButton; + + Icon minIcon; + + /** The icon displayed in the maximize button. */ + Icon maxIcon; + + /** The icon displayed in the iconify button. */ + private Icon iconIcon; + + /** The icon displayed in the close button. */ + Icon closeIcon; + + /** + * The background color of the TitlePane when the JInternalFrame is not + * selected. + */ + private Color notSelectedTitleColor; + + /** + * The background color of the TitlePane when the JInternalFrame is + * selected. + */ + private Color selectedTitleColor; + + /** + * The label used to display the title. This label is not added to the + * TitlePane. + */ + JLabel title; + + /** The action associated with closing the JInternalFrame. */ + private Action closeAction; + + /** The action associated with iconifying the JInternalFrame. */ + private Action iconifyAction; + + /** The action associated with maximizing the JInternalFrame. */ + private Action maximizeAction; + + /** The JMenuBar that is located at the top left of the Title Pane. */ + private JMenuBar menuBar; + + /** The JMenu inside the menuBar. */ + protected JMenu windowMenu; + + MetalTitlePane(JRootPane rp) + { + rootPane = rp; + setLayout(createLayout()); + title = new JLabel(); + title.setHorizontalAlignment(SwingConstants.LEFT); + title.setHorizontalTextPosition(SwingConstants.LEFT); + title.setOpaque(false); + installTitlePane(); + } + + protected LayoutManager createLayout() + { + return new MetalTitlePaneLayout(); + } + + /** + * This method installs the TitlePane onto the JInternalFrameTitlePane. It + * also creates any children components that need to be created and adds + * listeners to the appropriate components. + */ + protected void installTitlePane() + { + installDefaults(); + installListeners(); + createActions(); + assembleSystemMenu(); + createButtons(); + setButtonIcons(); + addSubComponents(); + enableActions(); + } + + private void enableActions() + { + // TODO: Implement this. + } + + private void addSubComponents() + { + add(menuBar); + add(closeButton); + add(iconButton); + add(maxButton); + } + + private void installListeners() + { + Window window = SwingUtilities.getWindowAncestor(rootPane); + window.addWindowFocusListener(new WindowFocusListener() + { + public void windowGainedFocus(WindowEvent ev) + { + repaint(); + } + public void windowLostFocus(WindowEvent ev) + { + repaint(); + } + }); + } + + private void createActions() + { + closeAction = new CloseAction(); + } + + private void assembleSystemMenu() + { + menuBar = createSystemMenuBar(); + windowMenu = createSystemMenu(); + menuBar.add(windowMenu); + addSystemMenuItems(windowMenu); + enableActions(); + } + + protected JMenuBar createSystemMenuBar() + { + if (menuBar == null) + menuBar = new JMenuBar(); + menuBar.removeAll(); + return menuBar; + } + + protected JMenu createSystemMenu() + { + if (windowMenu == null) + windowMenu = new JMenu(); + windowMenu.removeAll(); + return windowMenu; + } + + private void addSystemMenuItems(JMenu menu) + { + // TODO: Implement this. + } + + protected void createButtons() + { + closeButton = new PaneButton(closeAction); + closeButton.setText(null); + iconButton = new PaneButton(iconifyAction); + iconButton.setText(null); + maxButton = new PaneButton(maximizeAction); + maxButton.setText(null); + closeButton.setBorderPainted(false); + closeButton.setContentAreaFilled(false); + iconButton.setBorderPainted(false); + iconButton.setContentAreaFilled(false); + maxButton.setBorderPainted(false); + maxButton.setContentAreaFilled(false); + } + + protected void setButtonIcons() + { + if (closeIcon != null && closeButton != null) + closeButton.setIcon(closeIcon); + if (iconIcon != null && iconButton != null) + iconButton.setIcon(iconIcon); + if (maxIcon != null && maxButton != null) + maxButton.setIcon(maxIcon); + } + + /** + * Paints a representation of the current state of the internal frame. + * + * @param g the graphics device. + */ + public void paintComponent(Graphics g) + { + Window frame = SwingUtilities.getWindowAncestor(rootPane); + Color savedColor = g.getColor(); + paintTitleBackground(g); + paintChildren(g); + Dimension d = getSize(); + if (frame.isActive()) + g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); + else + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // put a dot in each of the top corners + g.drawLine(0, 0, 0, 0); + g.drawLine(d.width - 1, 0, d.width - 1, 0); + + g.drawLine(0, d.height - 1, d.width - 1, d.height - 1); + + // draw the metal pattern + if (UIManager.get("InternalFrame.activeTitleGradient") != null + && frame.isActive()) + { + MetalUtils.paintGradient(g, 0, 0, getWidth(), getHeight(), + SwingConstants.VERTICAL, + "InternalFrame.activeTitleGradient"); + } + + Rectangle b = title.getBounds(); + int startX = b.x + b.width + 5; + int endX = startX; + if (iconButton.isVisible()) + endX = Math.max(iconButton.getX(), endX); + else if (maxButton.isVisible()) + endX = Math.max(maxButton.getX(), endX); + else if (closeButton.isVisible()) + endX = Math.max(closeButton.getX(), endX); + endX -= 7; + if (endX > startX) + MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, getHeight() - 6, Color.white, Color.gray); + g.setColor(savedColor); + } + + /** + * This method paints the TitlePane's background. + * + * @param g The Graphics object to paint with. + */ + protected void paintTitleBackground(Graphics g) + { + Window frame = SwingUtilities.getWindowAncestor(rootPane); + + if (!isOpaque()) + return; + + Color saved = g.getColor(); + Dimension dims = getSize(); + + Color bg = getBackground(); + if (frame.isActive()) + bg = selectedTitleColor; + else + bg = notSelectedTitleColor; + g.setColor(bg); + g.fillRect(0, 0, dims.width, dims.height); + g.setColor(saved); + } + + /** + * This method installs the defaults determined by the look and feel. + */ + private void installDefaults() + { + title.setFont(UIManager.getFont("InternalFrame.titleFont")); + selectedTitleColor = UIManager.getColor("InternalFrame.activeTitleBackground"); + notSelectedTitleColor = UIManager.getColor("InternalFrame.inactiveTitleBackground"); + closeIcon = UIManager.getIcon("InternalFrame.closeIcon"); + iconIcon = UIManager.getIcon("InternalFrame.iconifyIcon"); + maxIcon = UIManager.getIcon("InternalFrame.maximizeIcon"); + minIcon = MetalIconFactory.getInternalFrameAltMaximizeIcon(16); + Frame frame = (Frame) SwingUtilities.getWindowAncestor(rootPane); + title = new JLabel(frame.getTitle(), + MetalIconFactory.getInternalFrameDefaultMenuIcon(), + SwingConstants.LEFT); + } + } + + private static class MetalRootLayout + implements LayoutManager2 + { + + /** + * The cached layout info for the glass pane. + */ + private Rectangle glassPaneBounds; + + /** + * The cached layout info for the layered pane. + */ + private Rectangle layeredPaneBounds; + + /** + * The cached layout info for the content pane. + */ + private Rectangle contentPaneBounds; + + /** + * The cached layout info for the menu bar. + */ + private Rectangle menuBarBounds; + + /** + * The cached layout info for the title pane. + */ + private Rectangle titlePaneBounds; + + /** + * The cached preferred size. + */ + private Dimension prefSize; + + public void addLayoutComponent(Component component, Object constraints) + { + // Nothing to do here. + } + + public Dimension maximumLayoutSize(Container target) + { + return preferredLayoutSize(target); + } + + public float getLayoutAlignmentX(Container target) + { + return 0.0F; + } + + public float getLayoutAlignmentY(Container target) + { + return 0.0F; + } + + public void invalidateLayout(Container target) + { + synchronized (this) + { + glassPaneBounds = null; + layeredPaneBounds = null; + contentPaneBounds = null; + menuBarBounds = null; + titlePaneBounds = null; + prefSize = null; + } + } + + public void addLayoutComponent(String name, Component component) + { + // Nothing to do here. + } + + public void removeLayoutComponent(Component component) + { + // TODO Auto-generated method stub + + } + + public Dimension preferredLayoutSize(Container parent) + { + JRootPane rp = (JRootPane) parent; + JLayeredPane layeredPane = rp.getLayeredPane(); + Component contentPane = layeredPane.getComponent(0); + Component titlePane = layeredPane.getComponent(1); + Component menuBar = null; + if (layeredPane.getComponentCount() > 2 + && layeredPane.getComponent(2) instanceof JMenuBar) + menuBar = layeredPane.getComponent(2); + + // We must synchronize here, otherwise we cannot guarantee that the + // prefSize is still non-null when returning. + synchronized (this) + { + if (prefSize == null) + { + Insets i = parent.getInsets(); + prefSize = new Dimension(i.left + i.right, i.top + i.bottom); + Dimension contentPrefSize = contentPane.getPreferredSize(); + prefSize.width += contentPrefSize.width; + prefSize.height += contentPrefSize.height + + titlePane.getPreferredSize().height; + if (menuBar != null) + { + Dimension menuBarSize = menuBar.getPreferredSize(); + if (menuBarSize.width > contentPrefSize.width) + prefSize.width += menuBarSize.width - contentPrefSize.width; + prefSize.height += menuBarSize.height; + } + } + // Return a copy here so the cached value won't get trashed by some + // other component. + return new Dimension(prefSize); + } + } + + public Dimension minimumLayoutSize(Container parent) + { + return preferredLayoutSize(parent); + } + + public void layoutContainer(Container parent) + { + JRootPane rp = (JRootPane) parent; + JLayeredPane layeredPane = rp.getLayeredPane(); + Component contentPane = layeredPane.getComponent(0); + Component titlePane = layeredPane.getComponent(1); + Component menuBar = null; + if (layeredPane.getComponentCount() > 2 + && layeredPane.getComponent(2) instanceof JMenuBar) + menuBar = layeredPane.getComponent(2); + Component glassPane = rp.getGlassPane(); + + if (glassPaneBounds == null || layeredPaneBounds == null + || contentPaneBounds == null || menuBarBounds == null) + { + Insets i = rp.getInsets(); + int containerWidth = parent.getBounds().width - i.left - i.right; + int containerHeight = parent.getBounds().height - i.top - i.bottom; + + // 1. The glassPane fills entire viewable region (bounds - insets). + // 2. The layeredPane filles entire viewable region. + // 3. The titlePane is placed at the upper edge of the layeredPane. + // 4. The menuBar is positioned at the upper edge of layeredPane. + // 5. The contentPane fills viewable region minus menuBar minus + // titlePane, if present. + + // +-------------------------------+ + // | JLayeredPane | + // | +--------------------------+ | + // | | titlePane + | + // | +--------------------------+ | + // | +--------------------------+ | + // | | menuBar | | + // | +--------------------------+ | + // | +--------------------------+ | + // | |contentPane | | + // | | | | + // | | | | + // | | | | + // | +--------------------------+ | + // +-------------------------------+ + + // Setup titlePaneBounds. + if (titlePaneBounds == null) + titlePaneBounds = new Rectangle(); + titlePaneBounds.width = containerWidth; + titlePaneBounds.height = titlePane.getPreferredSize().height; + + // Setup menuBarBounds. + if (menuBarBounds == null) + menuBarBounds = new Rectangle(); + menuBarBounds.setBounds(0, + titlePaneBounds.y + titlePaneBounds.height, + containerWidth, 0); + if (menuBar != null) + { + Dimension menuBarSize = menuBar.getPreferredSize(); + if (menuBarSize.height > containerHeight) + menuBarBounds.height = containerHeight; + else + menuBarBounds.height = menuBarSize.height; + } + + // Setup contentPaneBounds. + if (contentPaneBounds == null) + contentPaneBounds = new Rectangle(); + contentPaneBounds.setBounds(0, + menuBarBounds.y + menuBarBounds.height, + containerWidth, + containerHeight - menuBarBounds.y + - menuBarBounds.height); + glassPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight); + layeredPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight); + } + + // Layout components. + glassPane.setBounds(glassPaneBounds); + layeredPane.setBounds(layeredPaneBounds); + if (menuBar != null) + menuBar.setBounds(menuBarBounds); + contentPane.setBounds(contentPaneBounds); + titlePane.setBounds(titlePaneBounds); + } + + } + + /** + * The shared UI instance for MetalRootPaneUIs. + */ private static MetalRootPaneUI instance = null; /** @@ -78,4 +897,84 @@ public class MetalRootPaneUI instance = new MetalRootPaneUI(); return instance; } + + /** + * Installs this UI to the root pane. If the + * windowDecorationsStyle property is set on the root pane, + * the Metal window decorations are installed on the root pane. + * + * @param c + */ + public void installUI(JComponent c) + { + super.installUI(c); + JRootPane rp = (JRootPane) c; + if (rp.getWindowDecorationStyle() != JRootPane.NONE) + installWindowDecorations(rp); + } + + /** + * Uninstalls the UI from the root pane. This performs the superclass + * behaviour and uninstalls the window decorations that have possibly been + * installed by {@link #installUI}. + * + * @param c the root pane + */ + public void uninstallUI(JComponent c) + { + JRootPane rp = (JRootPane) c; + if (rp.getWindowDecorationStyle() != JRootPane.NONE) + uninstallWindowDecorations(rp); + super.uninstallUI(c); + } + + /** + * Receives notification if any of the JRootPane's property changes. In + * particular this catches changes to the windowDecorationStyle + * property and installs the window decorations accordingly. + * + * @param ev the property change event + */ + public void propertyChange(PropertyChangeEvent ev) + { + String propertyName = ev.getPropertyName(); + if (propertyName.equals("windowDecorationStyle")) + { + JRootPane rp = (JRootPane) ev.getSource(); + if (rp.getWindowDecorationStyle() != JRootPane.NONE) + installWindowDecorations(rp); + else + uninstallWindowDecorations(rp); + } + } + + /** + * Installs the window decorations to the root pane. This sets up a border, + * a title pane and a layout manager that can layout the root pane with that + * title pane. + * + * @param rp the root pane. + */ + private void installWindowDecorations(JRootPane rp) + { + rp.setBorder(new MetalFrameBorder()); + rp.setLayout(new MetalRootLayout()); + // We should have a contentPane already. + assert rp.getLayeredPane().getComponentCount() == 1 + : "We should have a contentPane already"; + rp.getLayeredPane().add(new MetalTitlePane(rp), + JLayeredPane.FRAME_CONTENT_LAYER); + } + + /** + * Uninstalls the window decorations from the root pane. This should rarely + * be necessary, but we do it anyway. + * + * @param rp the root pane + */ + private void uninstallWindowDecorations(JRootPane rp) + { + rp.setBorder(null); + rp.getLayeredPane().remove(1); + } } diff --git a/javax/swing/plaf/metal/MetalSplitPaneDivider.java b/javax/swing/plaf/metal/MetalSplitPaneDivider.java index 34a964cb3..9c592bd51 100644 --- a/javax/swing/plaf/metal/MetalSplitPaneDivider.java +++ b/javax/swing/plaf/metal/MetalSplitPaneDivider.java @@ -42,11 +42,13 @@ import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; +import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Point; import javax.swing.JSplitPane; import javax.swing.SwingConstants; +import javax.swing.border.Border; import javax.swing.plaf.basic.BasicArrowButton; import javax.swing.plaf.basic.BasicSplitPaneDivider; @@ -93,6 +95,12 @@ class MetalSplitPaneDivider extends BasicSplitPaneDivider public void paint(Graphics g) { Dimension s = getSize(); + + // Paint border if one exists. + Border border = getBorder(); + if (border != null) + border.paintBorder(this, g, 0, 0, s.width, s.height); + MetalUtils.fillMetalPattern(splitPane, g, 2, 2, s.width - 4, s.height - 4, light, dark); if (splitPane.isOneTouchExpandable()) diff --git a/javax/swing/plaf/synth/ColorType.java b/javax/swing/plaf/synth/ColorType.java new file mode 100644 index 000000000..954e309e1 --- /dev/null +++ b/javax/swing/plaf/synth/ColorType.java @@ -0,0 +1,130 @@ +/* ColorType.java -- En enumeration of color types + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.synth; + +/** + * A typesafe enumeration of color types. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class ColorType +{ + + /** + * A constant used to identify the foreground color of a component. + */ + public static final ColorType FOREGROUND = new ColorType("Foreground"); + + /** + * A constant used to identify the background color of a component. + */ + public static final ColorType BACKGROUND = new ColorType("Background"); + + /** + * A constant used to identify the foreground color of text of a component. + */ + public static final ColorType TEXT_FOREGROUND + = new ColorType("TextForeground"); + + /** + * A constant used to identify the background color of text of a component. + */ + public static final ColorType TEXT_BACKGROUND + = new ColorType("TextBackground"); + + /** + * A constant used to identify the focus color of a component. + */ + public static final ColorType FOCUS = new ColorType("Focus"); + + /** + * The maximum number of color types. + */ + public static final int MAX_COUNT = 5; + + /** + * A counter used to assign an ID to the created color types. + */ + private static int count = 0; + + /** + * The ID of the color type. + */ + private int id; + + /** + * The description of the color type. + */ + private String description; + + /** + * Creates a new Color color type with the specified + * description. + * + * @param desc the textual description of the color type + */ + protected ColorType(String desc) + { + description = desc; + id = count; + count++; + } + + /** + * Returns the unique ID of the color type. + * + * @return the unique ID of the color type + */ + public final int getID() + { + return id; + } + + /** + * Returns the textual description of the color type. + * + * @return the textual description of the color type + */ + public String toString() + { + return description; + } +} diff --git a/javax/swing/plaf/synth/Region.java b/javax/swing/plaf/synth/Region.java new file mode 100644 index 000000000..7ede65fc8 --- /dev/null +++ b/javax/swing/plaf/synth/Region.java @@ -0,0 +1,474 @@ +/* Region.java -- Describes a region within a component + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.synth; + +/** + * Describes a region of a component or the complete component. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class Region +{ + + // FIXME: What should ui be for the non-component regions that have + // subregion==false? + + /** + * Specifies an arrow button region. + */ + public static final Region ARROW_BUTTON = + new Region("ArrowButton", null, false); + + /** + * Specifies the region of a standard button. + */ + public static final Region BUTTON = + new Region("Button", "ButtonUI", false); + + /** + * Specifies the region of a check box. + */ + public static final Region CHECK_BOX = + new Region("CheckBox", "CheckBoxUI", false); + + /** + * Specifies the region of a check box menu item. + */ + public static final Region CHECK_BOX_MENU_ITEM = + new Region("CheckBoxMenuItem", "CheckBoxMenuItemUI", false); + + /** + * Specifies the region of a colorchooser. + */ + public static final Region COLOR_CHOOSER = + new Region("ColorChooser", "ColorChooserUI", false); + + /** + * Specifies the region of a combo box. + */ + public static final Region COMBO_BOX = + new Region("ComboBox", "ComboBoxUI", false); + + /** + * Specifies the region of a desktop pane. + */ + public static final Region DESKTOP_PANE = + new Region("DesktopPane", "DesktopPaneUI", false); + + /** + * Specifies the region of a desktop icon. + */ + public static final Region DESKTOP_ICON = + new Region("DesktopIcon", "DesktopIconUI", false); + + /** + * Specifies the region of an editor pane. + */ + public static final Region EDITOR_PANE = + new Region("EditorPane", "EditorPaneUI", false); + + /** + * Specifies the region of a file chooser. + */ + public static final Region FILECHOOSER = + new Region("FileChooser", "FileChooserUI", false); + + /** + * Specifies the region of a formatted text field. + */ + public static final Region FormattedTextField = + new Region("FormattedTextField", "FormattedTextFieldUI", false); + + /** + * Specifies the region of an internal frame. + */ + public static final Region INTERNAL_FRAME = + new Region("InternalFrame", "InternalFrameUI", false); + + /** + * Specifies the region of the title pane of an internal frame. + */ + public static final Region INTERNAL_FRAME_TITLE_PANE = + new Region("InternalFrameTitlePane", "InternalFrameTitlePaneUI", false); + + /** + * Specifies the region of a label. + */ + public static final Region LABEL = + new Region("Label", "LabelUI", false); + + /** + * Specifies the region of a list. + */ + public static final Region LIST = + new Region("List", "ListUI", false); + + /** + * Specifies the region of a menu. + */ + public static final Region MENU = + new Region("Menu", "MenuUI", false); + + /** + * Specifies the region of a menu bar. + */ + public static final Region MENU_BAR = + new Region("MenuBar", "MenuBarUI", false); + + /** + * Specifies the region of a menu item. + */ + public static final Region MENU_ITEM = + new Region("MenuItem", "MenuItemUI", false); + + /** + * Specifies the region of a menu item accelerator. This is a subregion + * of menu item. + */ + public static final Region MENU_ITEM_ACCELERATOR = + new Region("MenuItemAccelerator", null, true); + + /** + * Specifies the region of an option pane. + */ + public static final Region OPTION_PANE = + new Region("OptionPane", "OptionPaneUI", false); + + /** + * Specifies the region of a panel. + */ + public static final Region PANEL = + new Region("Panel", "PanelUI", false); + + /** + * Specifies the region of a password field. + */ + public static final Region PASSWORD_FIELD = + new Region("PasswordField", "PasswordFieldUI", false); + + /** + * Specifies the region of a popup menu. + */ + public static final Region POPUP_MENU = + new Region("PopupMenu", "PopupMenuUI", false); + + /** + * Specifies the region of a popup menu separator. + */ + public static final Region POPUP_MENU_SEPARATOR = + new Region("PopupMenuSeparator", null, false); + + /** + * Specifies the region of a progress bar. + */ + public static final Region PROGRESS_BAR = + new Region("ProgressBar", "ProgressBarUI", false); + + /** + * Specifies the region of a radio button. + */ + public static final Region RADIO_BUTTON = + new Region("RadioButton", "RadioButtonUI", false); + + /** + * Specifies the region of a radio button menu item. + */ + public static final Region RADIO_BUTTON_MENU_ITEM = + new Region("RadioButtonMenuItem", "RadioButtonMenuItemUI", false); + + /** + * Specifies the region of a root pane. + */ + public static final Region ROOT_PANE = + new Region("RootPane", "RootPaneUI", false); + + /** + * Specifies the region of a scroll bar. + */ + public static final Region SCROLL_BAR = + new Region("ScrollBar", "ScrollBarUI", false); + + /** + * Specifies the region of a scroll bar track. This is a subregion of + * scroll bars. + */ + public static final Region SCROLL_BAR_TRACK = + new Region("ScrollBarTrack", null, true); + + /** + * Specifies the region of a scroll bar thumb. This is a subregion of + * scroll bars. + */ + public static final Region SCROLL_BAR_THUMB = + new Region("ScrollBarThumb", null, true); + + /** + * Specifies the region of a scroll pane. + */ + public static final Region SCROLL_PANE = + new Region("ScrollPane", "ScrollPaneUI", false); + + /** + * Specifies the region of a separator. + */ + public static final Region SEPARATOR = + new Region("Separator", "SeparatorUI", false); + + /** + * Specifies the region of a slider. + */ + public static final Region SLIDER = + new Region("Slider", "SliderUI", false); + + /** + * Specifies the region of a slider track. This is a subregion of a slider. + */ + public static final Region SLIDER_TRACK = + new Region("SliderTrack", null, true); + + /** + * Specifies the region of a slider thumb. This is a subregion of a slider. + */ + public static final Region SLIDER_THUMB = + new Region("SliderThumb", null, true); + + /** + * Specifies the region of a spinner. + */ + public static final Region SPINNER = + new Region("Spinner", "SpinnerUI", false); + + /** + * Specifies the region of a split pane. + */ + public static final Region SPLIT_PANE = + new Region("SplitPane", "SplitPaneUI", false); + + /** + * Specifies the region of a split pane divider. This is a subregion of + * a split pane. + */ + public static final Region SPLIT_PANE_DIVIDER = + new Region("SplitPaneDivider", null, true); + + /** + * Specifies the region of a tabbed pane. + */ + public static final Region TABBED_PANE = + new Region("TabbedPane", "TabbedPaneUI", false); + + /** + * This specifies the region of a tab of a tabbed pane. This is a subregion + * of a tabbed pane. + */ + public static final Region TABBED_PANE_TAB = + new Region("TabbedPaneTab", null, true); + + /** + * This specifies the region underneath the tabs of a tabbed pane. This is a + * subregion of a tabbed pane. + */ + public static final Region TABBED_PANE_TAB_AREA = + new Region("TabbedPaneTabArea", null, true); + + /** + * This specifies the region for the content of a tabbed pane. This is a + * subregion of a tabbed pane. + */ + public static final Region TABBED_PANE_CONTENT = + new Region("TabbedPaneContent", null, true); + + /** + * Specifies the region of a table. + */ + public static final Region TABLE = + new Region("Table", "TableUI", false); + + /** + * Specifies the region of a table header. + */ + public static final Region TABLE_HEADER = + new Region("TableHeader", "TableHeaderUI", false); + + /** + * Specifies the region of a text area. + */ + public static final Region TEXT_AREA = + new Region("TextArea", "TextAreaUI", false); + + /** + * Specifies the region of a text field. + */ + public static final Region TEXT_FIELD = + new Region("TextField", "TextFieldUI", false); + + /** + * Specifies the region of a text pane. + */ + public static final Region TEXT_PANE = + new Region("TextPane", "TextPaneUI", false); + + /** + * Specifies the region of a toggle button. + */ + public static final Region TOGGLE_BUTTON = + new Region("ToggleButton", "ToggleButtonUI", false); + + /** + * Specifies the region of a tool bar. + */ + public static final Region TOOL_BAR = + new Region("ToolBar", "ToolBarUI", false); + + /** + * Specifies the content region of a tool bar. This is a subregion of a tool + * bar. + */ + public static final Region TOOL_BAR_CONTENT = + new Region("ToolBarContent", null, true); + + /** + * Specifies the drag window region of a tool bar. This is a subregion of a + * tool bar. + */ + public static final Region TOOL_BAR_DRAG_WINDOW = + new Region("ToolBarDragWindow", null, false); + + /** + * Specifies the region of a tool tip. + */ + public static final Region TOOL_TIP = + new Region("ToolTip", "ToolTipUI", false); + + /** + * Specifies the region of a separator of a tool bar. This is a subregion of + * a tool bar. + */ + public static final Region TOOL_BAR_SEPARATOR = + new Region("ToolBarSeparator", null, false); + + /** + * Specifies the region of a tree. + */ + public static final Region TREE = + new Region("Tree", "TreeUI", false); + + /** + * Specifies the region of a tree cell. This is a subregion of a tree. + */ + public static final Region TREE_CELL = + new Region("TreeCell", null, true); + + /** + * Specifies the region of a viewport. + */ + public static final Region VIEWPORT = + new Region("Viewport", "ViewportUI", false); + + + /** + * The UI class id for the region. This is package private because this will + * be used by other classes in that package. + */ + String ui; + + /** + * The name of the region. + */ + private String name; + + /** + * If this region is a subregion or not. + */ + private boolean subregion; + + /** + * Creates a new Region with the specified name and ui ID. + * The ui must be the same what + * {@link javax.swing.JComponent#getUIClassID()} returns for toplevel regions. For + * subregions this should be null. + * + * @param name the name of the region + * @param ui the UI class ID of the region or null for + * subregions + * @param subregion true if this region is a subregion, + * false otherwise + */ + protected Region(String name, String ui, boolean subregion) + { + this.name = name; + this.ui = ui; + this.subregion = subregion; + } + + /** + * Returns true if this region describes a subregion of a + * component, false if it describes a component region itself. + * + * @return true if this region describes a subregion of a + * component, false if it describes a component region + * itself + */ + public boolean isSubregion() + { + return subregion; + } + + /** + * Returns the name of the region. + * + * @return the name of the region + */ + public String getName() + { + return name; + } + + /** + * Returns the name of the region. + * + * @return the name of the region + */ + public String toString() + { + return name; + } +} diff --git a/javax/swing/plaf/synth/SynthConstants.java b/javax/swing/plaf/synth/SynthConstants.java new file mode 100644 index 000000000..306024c00 --- /dev/null +++ b/javax/swing/plaf/synth/SynthConstants.java @@ -0,0 +1,85 @@ +/* SynthConstants.java -- A couple of constants used by Synth + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.synth; + +/** + * A couple of constants used by the Synth Look and Feel. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public interface SynthConstants +{ + /** + * A primary state indicating that a component is enabled. + */ + static final int ENABLED = 1; + + /** + * A primary state indicating that a component is disabled. + */ + static final int DISABLED = 8; + + /** + * A primary state indicating that the mouse is over a region. + */ + static final int MOUSE_OVER = 2; + + /** + * A primary state indicating that the component is in a pressed state (which + * does not necessarily mean that the mouse is pressed over the component). + */ + static final int PRESSED = 4; + + /** + * Indicates that a region has focus. + */ + static final int FOCUSED = 256; + + /** + * Indicates that a region is selected. + */ + static final int SELECTED = 512; + + /** + * Indicates that a region is in its default state. + */ + static final int DEFAULT = 1024; +} diff --git a/javax/swing/plaf/synth/SynthContext.java b/javax/swing/plaf/synth/SynthContext.java new file mode 100644 index 000000000..83536dae9 --- /dev/null +++ b/javax/swing/plaf/synth/SynthContext.java @@ -0,0 +1,134 @@ +/* SynthContext.java -- Contextual information about a region + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.synth; + +import javax.swing.JComponent; + +/** + * Contains some contextual information about a region. The information passed + * in objects of this class can only be considered valid during the method call + * that it was passed to. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class SynthContext +{ + + /** + * The component. + */ + private JComponent component; + + /** + * The region of the component. + */ + private Region region; + + /** + * The style of the component. + */ + private SynthStyle style; + + /** + * The state of the component. + */ + private int state; + + /** + * Creates a new SynthContext object. + * + * @param component the component for which this context is used + * @param region the region of the component + * @param style the style associated with the component + * @param state a or'ed bitmask of the constants from {@link SynthConstants} + */ + public SynthContext(JComponent component, Region region, SynthStyle style, + int state) + { + this.component = component; + this.region = region; + this.style = style; + this.state = state; + } + + /** + * Returns the component that contains the region. + * + * @return the component that contains the region + */ + public JComponent getComponent() + { + return component; + } + + /** + * Returns the region that identifies this state. + * + * @return the region that identifies this state + */ + public Region getRegion() + { + return region; + } + + /** + * Returns the style of the region. + * + * @return the style of the region + */ + public SynthStyle getStyle() + { + return style; + } + + /** + * Returns the state of the component. This is a or'ed bitmask of the + * constants defined in {@link SynthConstants}. + * + * @return the state of the component + * + * @see SynthConstants + */ + public int getComponentState() + { + return state; + } +} diff --git a/javax/swing/plaf/synth/SynthGraphicsUtils.java b/javax/swing/plaf/synth/SynthGraphicsUtils.java new file mode 100644 index 000000000..a68b6f6ec --- /dev/null +++ b/javax/swing/plaf/synth/SynthGraphicsUtils.java @@ -0,0 +1,283 @@ +/* SynthGraphicsUtils.java -- Wrapper for graphics primitives used in Synth + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.synth; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.Icon; +import javax.swing.SwingUtilities; + +/** + * Wrapper for graphics primitives used in Synth. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class SynthGraphicsUtils + +{ + /** + * Creates a new SynthGraphicsUtils object. + */ + public SynthGraphicsUtils() + { + // Nothing to do here. + } + + /** + * Draws a line from (x1,y1) to (x2,y2). + * + * @param ctx the synth context, identifies the region + * @param paintKey identifies the portion of the component to be painted, may + * be null + * @param g the graphics context to use for painting + * @param x1 the x coordinate of the start point + * @param y1 the y coordinate of the start point + * @param x2 the x coordinate of the end point + * @param y2 the y coordinate of the end point + */ + public void drawLine(SynthContext ctx, Object paintKey, Graphics g, int x1, + int y1, int x2, int y2) + { + // TODO: Correct? + g.drawLine(x1, y1, x2, y2); + } + + /** + * Lays out a label and (if non-null) an icon. The calculated coordinates are + * then stored in viewR, iconR and + * textR. + * + * The alignment and position parameters may be one of the alignment or + * position constants defined in {@link javax.swing.SwingConstants}. + * + * @param ctx the synth context, identifies the current region + * @param fm the font metrics to use to fetch the text measures + * @param text the text to lay out, may be null + * @param icon the icon to lay out, may be null + * @param hAlign the horizontal alignment of the label + * @param vAlign the vertical alignment of the label + * @param hTextPos the horizontal text position + * @param vTextPos the vertical text position + * @param viewR the view rectangle (return parameter) + * @param iconR the icon rectangle (return parameter) + * @param textR the text rectangle (return parameter) + * @param iconTextGap the gap between text and label + * + * @return the label text, may be shortened + */ + public String layoutText(SynthContext ctx, FontMetrics fm, String text, + Icon icon, int hAlign, int vAlign, int hTextPos, + int vTextPos, Rectangle viewR, Rectangle iconR, + Rectangle textR, int iconTextGap) + { + return SwingUtilities.layoutCompoundLabel(fm, text, icon, vAlign, hAlign, + vTextPos, hTextPos, viewR, iconR, + textR, iconTextGap); + } + + /** + * Returns the width of the string text for the specified font + * and font metrics. + * + * @param ctx identifies the current region + * @param font the font + * @param fm the font metrics to use + * @param text the text to be measured + * + * @return the width of the string text for the specified font + * and font metrics + */ + public int computeStringWidth(SynthContext ctx, Font font, FontMetrics fm, + String text) + { + return fm.stringWidth(text); + } + + /** + * Calculates the minimums size that is needed to render the label with + * text and icon correctly. + * + * @param ctx identifies the current region + * @param font the font to use + * @param text the label text + * @param icon the label icon + * @param hAlign the horizontal alignment + * @param vAlign the vertical alignment + * @param hTextPosition the horizontal text position + * @param vTextPosition the vertical text position + * @param iconTextGap the gap between icon and text + * @param mnemonicIndex index to the mnemonic character within + * text + * + * @return the minimums size that is needed to render the label with + * text and icon correctly + */ + public Dimension getMinimumSize(SynthContext ctx, Font font, String text, + Icon icon, int hAlign, int vAlign, + int hTextPosition,int vTextPosition, + int iconTextGap,int mnemonicIndex) + { + // FIXME: Implement this correctly. + return new Dimension(0, 0); + } + + /** + * Calculates the preferred size that is needed to render the label with + * text and icon correctly. + * + * @param ctx identifies the current region + * @param font the font to use + * @param text the label text + * @param icon the label icon + * @param hAlign the horizontal alignment + * @param vAlign the vertical alignment + * @param hTextPosition the horizontal text position + * @param vTextPosition the vertical text position + * @param iconTextGap the gap between icon and text + * @param mnemonicIndex index to the mnemonic character within + * text + * + * @return the preferred size that is needed to render the label with + * text and icon correctly + */ + public Dimension getPreferredSize(SynthContext ctx, Font font, String text, + Icon icon, int hAlign, int vAlign, + int hTextPosition,int vTextPosition, + int iconTextGap,int mnemonicIndex) + { + // FIXME: Implement this correctly. + return new Dimension(0, 0); + } + + /** + * Calculates the maximum size that is needed to render the label with + * text and icon correctly. + * + * @param ctx identifies the current region + * @param font the font to use + * @param text the label text + * @param icon the label icon + * @param hAlign the horizontal alignment + * @param vAlign the vertical alignment + * @param hTextPosition the horizontal text position + * @param vTextPosition the vertical text position + * @param iconTextGap the gap between icon and text + * @param mnemonicIndex index to the mnemonic character within + * text + * + * @return the maximum size that is needed to render the label with + * text and icon correctly + */ + public Dimension getMaximumSize(SynthContext ctx, Font font, String text, + Icon icon, int hAlign, int vAlign, + int hTextPosition,int vTextPosition, + int iconTextGap,int mnemonicIndex) + { + // FIXME: Implement this correctly. + return new Dimension(0, 0); + } + + /** + * Returns the maximum character height of the font from the component of the + * passed in context. + * + * @param context identifies the current component and region + * + * @return the maximum character height of the font from the component of the + * passed in context + */ + public int getMaximumCharHeight(SynthContext context) + { + Component comp = context.getComponent(); + Font font = comp.getFont(); + return comp.getFontMetrics(font).getHeight(); + } + + /** + * Renders the specified text within the bounds. + * + * @param ctx identifies the component and region + * @param g the graphics context for drawing the tetx + * @param text the text to be rendered + * @param bounds the bounds within which the text should be rendered + * @param mnemonicIndex the index of the mnemonic character within + * text + */ + public void paintText(SynthContext ctx, Graphics g, String text, + Rectangle bounds, int mnemonicIndex) + { + // FIXME: This is very primitive and should be improved to paint the + // mnemonic char. + g.drawString(text, bounds.x, bounds.y); + } + + /** + * Renders the specified text at the specified location. + * + * @param ctx identifies the component and region + * @param g the graphics context for drawing the tetx + * @param text the text to be rendered + * @param x the X location where the text should be rendered + * @param y the Y location where the text should be rendered + * @param mnemonicIndex the index of the mnemonic character within + * text + */ + public void paintText(SynthContext ctx, Graphics g, String text, + int x, int y, int mnemonicIndex) + { + // FIXME: This is very primitive and should be improved to paint the + // mnemonic char. + g.drawString(text, x, y); + } + + public void paintText(SynthContext ctx, Graphics g, String text, Icon icon, + int hAlign, int vAlign, int hTextPosition, + int vTextPosition, int iconTextGap, int mnemonicIndex, + int textOffset) + { + // FIXME: Implement this correctly. + } +} diff --git a/javax/swing/plaf/synth/SynthLookAndFeel.java b/javax/swing/plaf/synth/SynthLookAndFeel.java new file mode 100644 index 000000000..8d0596d41 --- /dev/null +++ b/javax/swing/plaf/synth/SynthLookAndFeel.java @@ -0,0 +1,272 @@ +/* SynthLookAndFeel.java -- A skinnable Swing look and feel + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.synth; + +import java.awt.Component; +import java.io.InputStream; +import java.text.ParseException; + +import javax.swing.JComponent; +import javax.swing.UIDefaults; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicLookAndFeel; + + +/** + * A look and feel that can be customized either by providing a file to + * {@link #load} or by setting a {@link SynthStyleFactory} using + * {@link #setStyleFactory}. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public class SynthLookAndFeel + extends BasicLookAndFeel +{ + + /** + * The style factory that will be used by the UI classes to load their + * style sets from. + */ + private static SynthStyleFactory styleFactory; + + /** + * Creates a new instance of SynthLookAndFeel. In order to use + * the Synth look and feel you either need to call {@link #load} to load a + * set of styles from an XML file, or you need to call + * {@link #setStyleFactory} to provide your own style factory. + */ + public SynthLookAndFeel() + { + // FIXME: What to do here, if anything? + } + + /** + * Sets the style factory that the UI classes of Synth will use to load their + * sets of styles. + * + * @param sf the style factory to set + */ + public static void setStyleFactory(SynthStyleFactory sf) + { + styleFactory = sf; + } + + /** + * Returns the current style factory that the UI classes of Synth will use to + * load their sets of styles. + * + * @return the current style factory + */ + public static SynthStyleFactory getStyleFactory() + { + return styleFactory; + } + + /** + * Returns the style for the specified component and region. + * + * @param c the component for which to return the style + * @param r the region of the component for which to return the style + * + * @return the style for the specified component and region + */ + public static SynthStyle getStyle(JComponent c, Region r) + { + return getStyleFactory().getStyle(c, r); + } + + /** + * Updates all style information of the component and it's children. + * + * @param c the componenent for which to update the style + */ + public static void updateStyles(Component c) + { + // FIXME: Implement this properly. + } + + /** + * Returns the region for a given Swing component. + * + * @param c the Swing component for which to fetch the region + * + * @return the region for a given Swing component + */ + public static Region getRegion(JComponent c) + { + // FIXME: This can be implemented as soon as we have the component UI + // classes in place, since this region will be matched via the UI classes. + return null; + } + + /** + * Creates the Synth look and feel component UI instance for the given + * component. + * + * @param c the component for which to create a UI instance + * + * @return the Synth look and feel component UI instance for the given + * component + */ + public static ComponentUI createUI(JComponent c) + { + // FIXME: This can be implemented as soon as we have the component UI + // classes in place. + return null; + } + + /** + * Initializes this look and feel. + */ + public void initialize() + { + super.initialize(); + // TODO: Implement at least the following here: + // if (styleFactory != null) + // styleFactory = new DefaultStyleFactory(); + } + + /** + * Uninitializes the look and feel. + */ + public void uninitialize() + { + super.uninitialize(); + // TODO: What to do here? + } + + /** + * Returns the UI defaults of this look and feel. + * + * @return the UI defaults of this look and feel + */ + public UIDefaults getDefaults() + { + // FIXME: This is certainly wrong. The defaults should be fetched/merged + // from the file from which the l&f is loaded. + return super.getDefaults(); + } + + /** + * FIXME: DOCUMENT ME! + * + * @return FIXME + */ + public boolean shouldUpdateStyleOnAncestorChanged() + { + return false; + } + + /** + * Loads a set of {@link SynthStyle}s that are used for the look and feel of + * the components. The resourceBase parameter is used to resolve + * references against, like icons and other files. + * + * @param in the input stream from where to load the styles + * @param resourceBase the base against which references are resolved. + * + * @throws ParseException if the input stream cannot be parsed + * @throws IllegalArgumentException if one of the parameters is + * null + */ + // FIXME: The signature in the JDK has a Class here. Should be fixed as + // soon as we switch to the generics branch. + public void load(InputStream in, Class resourceBase) + throws ParseException, IllegalArgumentException + { + // FIXME: Implement this correctly. + } + + /** + * Returns a textual description of the Synth look and feel. This returns + * "Synt look and feel". + * + * @return a textual description of the Synth look and feel + */ + public String getDescription() + { + return "Synth look and feel"; + } + + /** + * Returns the ID of the Synth look and feel. This returns "Synth". + * + * @return the ID of the Synth look and feel + */ + public String getID() + { + return "Synth"; + } + + /** + * Returns the name of the Synth look and feel. This returns + * "Synt look and feel". + * + * @return the name of the Synth look and feel + */ + public String getName() + { + return "Synth look and feel"; + } + + /** + * Returns false since the Synth look and feel is not a native + * look and feel. + * + * @return false + */ + public boolean isNativeLookAndFeel() + { + return false; + } + + /** + * Returns true since the Synth look and feel is always a + * supported look and feel. + * + * @return true + */ + public boolean isSupportedLookAndFeel() + { + return true; + } + +} diff --git a/javax/swing/plaf/synth/SynthPainter.java b/javax/swing/plaf/synth/SynthPainter.java new file mode 100644 index 000000000..0d63c6db7 --- /dev/null +++ b/javax/swing/plaf/synth/SynthPainter.java @@ -0,0 +1,80 @@ +/* SynthPainter.java -- An abstract painter for synth components + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.synth; + +import java.awt.Graphics; + +/** + * The abstract definition of a delegate that takes the responsibility of + * painting for the components. + * + * This class is defined to be abstract and all methods are no-ops. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public abstract class SynthPainter +{ + + /** + * Creates a new SynthPainter object. + */ + public SynthPainter() + { + // Nothing to do here. + } + + /** + * Paints the background of an arrow button. + * + * @param ctx the synth context identifying the component and region for + * painting + * @param g the graphics context to use for painting + * @param x the X coordinate of the area to paint + * @param y the Y coordinate of the area to paint + * @param w the width of the area to paint + * @param h the height of the area to paint + */ + public void paintArrowButtonBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } +} diff --git a/javax/swing/plaf/synth/SynthStyle.java b/javax/swing/plaf/synth/SynthStyle.java new file mode 100644 index 000000000..e0a8dbcc7 --- /dev/null +++ b/javax/swing/plaf/synth/SynthStyle.java @@ -0,0 +1,144 @@ +/* SynthStyle.java -- A set of style properties + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.synth; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Insets; + +import javax.swing.Icon; + +/** + * A set of style properties that can be installed on a component. + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.5 + */ +public abstract class SynthStyle +{ + + /** + * Creates a new SynthStyle object. + */ + public SynthStyle() + { + // FIXME: Implement this correctly. + } + + public SynthGraphicsUtils getGraphicsUtils(SynthContext ctx) + { + // FIXME: Implement this correctly. + return null; + } + + public Color getColor(SynthContext ctx, ColorType type) + { + // FIXME: Implement this correctly. + return null; + } + + public abstract Color getColorForState(SynthContext ctx, ColorType type); + + public Font getFont(SynthContext ctx) + { + // FIXME: Implement this correctly. + return null; + } + + public abstract Font getFontForState(SynthContext ctx); + + public Insets getInsets(SynthContext ctx) + { + // FIXME: Implement this correctly. + return null; + } + + public SynthPainter getPainted(SynthContext ctx) + { + // FIXME: Implement this correctly. + return null; + } + + public boolean isOpaque(SynthContext ctx) + { + // FIXME: Implement this correctly. + return true; + } + + public Object get(SynthContext ctx, Object key) + { + // FIXME: Implement this correctly. + return null; + } + + public void installDefaults(SynthContext ctx) + { + // FIXME: Implement this correctly. + } + + public void uninstallDefaults(SynthContext ctx) + { + // FIXME: Implement this correctly. + } + + public int getInt(SynthContext ctx, Object key, int defaultValue) + { + // FIXME: Implement this correctly. + return -1; + } + + public boolean getBoolean(SynthContext ctx, Object key, boolean defaultValue) + { + // FIXME: Implement this correctly. + return false; + } + + public Icon getIcon(SynthContext ctx, Object key) + { + // FIXME: Implement this correctly. + return null; + } + + public String getString(SynthContext ctx, Object key, String defaultValue) + { + // FIXME: Implement this correctly. + return null; + } +} diff --git a/javax/swing/plaf/synth/SynthStyleFactory.java b/javax/swing/plaf/synth/SynthStyleFactory.java new file mode 100644 index 000000000..569753d8a --- /dev/null +++ b/javax/swing/plaf/synth/SynthStyleFactory.java @@ -0,0 +1,64 @@ +/* SynthStyleFactory.java -- A factory for SynthStyles + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.synth; + +import javax.swing.JComponent; + +public abstract class SynthStyleFactory +{ + + /** + * Creates a new SynthStyleFactory. + */ + public SynthStyleFactory() + { + // Nothing to do here. + } + + /** + * Returns a {@link SynthStyle} for the specified region of the specified + * component. + * + * @param c the component for which to create a style + * @param id the region of the component + * + * @return a style for the specified region of the specified component + */ + public abstract SynthStyle getStyle(JComponent c, Region id); +} diff --git a/javax/swing/plaf/synth/package.html b/javax/swing/plaf/synth/package.html new file mode 100644 index 000000000..b977e468c --- /dev/null +++ b/javax/swing/plaf/synth/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - javax.swing.plaf.synth + + +

      Provides a look and feel that can be customized by and XML file or by + providing a custom {@link SynthStyleFactory}. +

      + + diff --git a/javax/swing/table/DefaultTableCellRenderer.java b/javax/swing/table/DefaultTableCellRenderer.java index 233528c7d..0d9b62567 100644 --- a/javax/swing/table/DefaultTableCellRenderer.java +++ b/javax/swing/table/DefaultTableCellRenderer.java @@ -127,7 +127,8 @@ public class DefaultTableCellRenderer extends JLabel * Get the string value of the object and pass it to setText(). * * @param table the JTable - * @param value the value of the object + * @param value the value of the object. For the text content, + * null is rendered as an empty cell. * @param isSelected is the cell selected? * @param hasFocus has the cell the focus? * @param row the row to render @@ -140,13 +141,7 @@ public class DefaultTableCellRenderer extends JLabel boolean hasFocus, int row, int column) { - if (value != null) - { - if (value instanceof JTextField) - return new JTextField(((JTextField)value).getText()); - super.setText(value.toString()); - } - + setValue(value); setOpaque(true); if (table == null) @@ -274,6 +269,10 @@ public class DefaultTableCellRenderer extends JLabel */ protected void setValue(Object value) { - super.setText((value!=null) ? value.toString() : ""); + if (value != null) + setText(value.toString()); + else + // null is rendered as an empty cell. + setText(""); } } diff --git a/javax/swing/table/DefaultTableModel.java b/javax/swing/table/DefaultTableModel.java index 6844f2a27..c281caa07 100644 --- a/javax/swing/table/DefaultTableModel.java +++ b/javax/swing/table/DefaultTableModel.java @@ -486,7 +486,10 @@ public class DefaultTableModel extends AbstractTableModel } /** - * Returns the name of the specified column. + * Get the name of the column. If the column has the column identifier set, + * the return value is the result of the .toString() method call on that + * identifier. If the identifier is not explicitly set, the returned value + * is calculated by {@link AbstractTableModel#getColumnName(int)}. * * @param column the column index. * diff --git a/javax/swing/table/JTableHeader.java b/javax/swing/table/JTableHeader.java index 163509a45..4e8dcd7b7 100644 --- a/javax/swing/table/JTableHeader.java +++ b/javax/swing/table/JTableHeader.java @@ -67,6 +67,11 @@ import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.plaf.TableHeaderUI; +/** + * Represents the table header. The header displays the column header values, + * is always visible event if the rest of the table scrolls up and down and + * supports column reordering and resizing with mouse. + */ public class JTableHeader extends JComponent implements TableColumnModelListener, Accessible { @@ -306,7 +311,10 @@ public class JTableHeader extends JComponent } }; } - + + /** + * Use serialVersionUid for interoperability. + */ private static final long serialVersionUID = 5144633983372967710L; /** @@ -409,9 +417,10 @@ public class JTableHeader extends JComponent } /** - * Get the value of the {@link #draggedColumn} property. + * Get the column that is currently being dragged. This is used when + * handling the column reordering with mouse. * - * @return The current value of the property + * @return the column being dragged, null if none. */ public TableColumn getDraggedColumn() { @@ -429,29 +438,34 @@ public class JTableHeader extends JComponent } /** - * Get the value of the {@link #reorderingAllowed} property. + * Check if it is possible to reorder the table columns by dragging column + * header with mouse. The table reordering is enabled by default, but can be + * disabled with {@link #setReorderingAllowed(boolean)}. * - * @return The current value of the property - */ + * @return true if reordering is allowed, false otherwise. + */ public boolean getReorderingAllowed() { return reorderingAllowed; } /** - * Get the value of the {@link #resizingAllowed} property. + * Check if it is possible to resize the table columns by dragging the column + * boundary in the table header with mouse. The resizing is enabled + * by default, but can be disabled with {@link #setResizingAllowed(boolean)}. * - * @return The current value of the property - */ + * @return true if resizing is allowed, false otherwise. + */ public boolean getResizingAllowed() { return resizingAllowed; } /** - * Get the value of the {@link #resizingColumn} property. + * Get the column that is currently being resized. This is used when + * handling the column resizing with mouse. * - * @return The current value of the property + * @return the column being currently resized, null if none. */ public TableColumn getResizingColumn() { @@ -459,9 +473,9 @@ public class JTableHeader extends JComponent } /** - * Get the value of the {@link #table} property. + * Get the table, having this header. * - * @return The current value of the property + * @return the table, having this header. */ public JTable getTable() { @@ -501,13 +515,15 @@ public class JTableHeader extends JComponent } /** - * Set the value of the {@link #draggedColumn} property. + * Set the column that is currently being dragged. This is used when + * dragging the column with mouse. Setting to null will stop the + * dragging session immediately. * - * @param d The new value of the property + * @param draggingIt the column being currently dragged, null if none. */ - public void setDraggedColumn(TableColumn d) + public void setDraggedColumn(TableColumn draggingIt) { - draggedColumn = d; + draggedColumn = draggingIt; } /** @@ -531,33 +547,39 @@ public class JTableHeader extends JComponent } /** - * Set the value of the {@link #reorderingAllowed} property. + * Set the table ability to reorder columns by dragging column header + * with mouse. The table reordering is enabled by default, but can be + * disabled with this method. * - * @param r The new value of the property + * @param allowed true if reordering is allowed, false otherwise. */ - public void setReorderingAllowed(boolean r) + public void setReorderingAllowed(boolean allowed) { - reorderingAllowed = r; + reorderingAllowed = allowed; } /** - * Set the value of the {@link #resizingAllowed} property. + * Set the table ability to resize columns by dragging the column + * boundary in the table header with mouse. The resizing is enabled + * by default, but can be disabled using this method. * - * @param r The new value of the property + * @param allowed true if resizing is allowed, false otherwise. */ - public void setResizingAllowed(boolean r) + public void setResizingAllowed(boolean allowed) { - resizingAllowed = r; + resizingAllowed = allowed; } /** - * Set the value of the {@link #resizingColumn} property. + * The the column that is currently being resized. This property is used + * when handling table resizing with mouse. Setting to null would stop + * the resizing session immediately. * - * @param r The new value of the property + * @param resizingIt the column being currently resized */ - public void setResizingColumn(TableColumn r) + public void setResizingColumn(TableColumn resizingIt) { - resizingColumn = r; + resizingColumn = resizingIt; } /** @@ -609,7 +631,14 @@ public class JTableHeader extends JComponent { this.cellRenderer = cellRenderer; } - + + /** + * Get the rectangle, occupied by the header of the given column. + * + * @param column the column, for that the header area is requested. + * + * @return the column header area. + */ public Rectangle getHeaderRect(int column) { Rectangle r = getTable().getCellRect(-1, column, false); diff --git a/javax/swing/text/AbstractDocument.java b/javax/swing/text/AbstractDocument.java index 395f39e4c..be6134974 100644 --- a/javax/swing/text/AbstractDocument.java +++ b/javax/swing/text/AbstractDocument.java @@ -538,18 +538,24 @@ public abstract class AbstractDocument implements Document, Serializable DefaultDocumentEvent event = new DefaultDocumentEvent(offset, text.length(), DocumentEvent.EventType.INSERT); - - writeLock(); - UndoableEdit undo = content.insertString(offset, text); - if (undo != null) - event.addEdit(undo); - insertUpdate(event, attributes); - writeUnlock(); + try + { + writeLock(); + UndoableEdit undo = content.insertString(offset, text); + if (undo != null) + event.addEdit(undo); - fireInsertUpdate(event); - if (undo != null) - fireUndoableEditUpdate(new UndoableEditEvent(this, undo)); + insertUpdate(event, attributes); + + fireInsertUpdate(event); + if (undo != null) + fireUndoableEditUpdate(new UndoableEditEvent(this, undo)); + } + finally + { + writeUnlock(); + } } /** @@ -640,6 +646,12 @@ public abstract class AbstractDocument implements Document, Serializable // more times than you've previously called lock, but it doesn't make // sure that the threads calling unlock were the same ones that called lock + // If the current thread holds the write lock, and attempted to also obtain + // a readLock, then numReaders hasn't been incremented and we don't need + // to unlock it here. + if (currentWriter == Thread.currentThread()) + return; + // FIXME: the reference implementation throws a // javax.swing.text.StateInvariantError here if (numReaders == 0) @@ -675,18 +687,21 @@ public abstract class AbstractDocument implements Document, Serializable new DefaultDocumentEvent(offset, length, DocumentEvent.EventType.REMOVE); - removeUpdate(event); - - boolean shouldFire = content.getString(offset, length).length() != 0; - - writeLock(); - UndoableEdit temp = content.remove(offset, length); - writeUnlock(); - - postRemoveUpdate(event); - - if (shouldFire) - fireRemoveUpdate(event); + try + { + writeLock(); + + // The order of the operations below is critical! + removeUpdate(event); + UndoableEdit temp = content.remove(offset, length); + + postRemoveUpdate(event); + fireRemoveUpdate(event); + } + finally + { + writeUnlock(); + } } /** @@ -841,7 +856,7 @@ public abstract class AbstractDocument implements Document, Serializable */ protected void writeLock() { - if (currentWriter!= null && currentWriter.equals(Thread.currentThread())) + if (currentWriter != null && currentWriter.equals(Thread.currentThread())) return; synchronized (documentCV) { @@ -1330,11 +1345,11 @@ public abstract class AbstractDocument implements Document, Serializable public Object getAttribute(Object key) { Object result = attributes.getAttribute(key); - if (result == null && element_parent != null) + if (result == null) { - AttributeSet parentSet = element_parent.getAttributes(); - if (parentSet != null) - result = parentSet.getAttribute(key); + AttributeSet resParent = getResolveParent(); + if (resParent != null) + result = resParent.getAttribute(key); } return result; } @@ -1371,9 +1386,7 @@ public abstract class AbstractDocument implements Document, Serializable */ public AttributeSet getResolveParent() { - if (attributes.getResolveParent() != null) - return attributes.getResolveParent(); - return element_parent.getAttributes(); + return attributes.getResolveParent(); } /** @@ -1695,9 +1708,12 @@ public abstract class AbstractDocument implements Document, Serializable */ public int getEndOffset() { + int end = 0; if (getElementCount() == 0) - throw new NullPointerException("This BranchElement has no children."); - return children[children.length - 1].getEndOffset(); + end = getLength(); // FIXME: That ain't correct, fix it. + else + end = children[children.length - 1].getEndOffset(); + return end; } /** @@ -1722,9 +1738,12 @@ public abstract class AbstractDocument implements Document, Serializable */ public int getStartOffset() { + int start = 0; if (getElementCount() == 0) - throw new NullPointerException("This BranchElement has no children."); - return children[0].getStartOffset(); + start = 0; // FIXME: That ain't correct, fix it. + else + start = children[0].getStartOffset(); + return start; } /** diff --git a/javax/swing/text/AsyncBoxView.java b/javax/swing/text/AsyncBoxView.java new file mode 100644 index 000000000..1988bbadc --- /dev/null +++ b/javax/swing/text/AsyncBoxView.java @@ -0,0 +1,1480 @@ +/* AsyncBoxView.java -- A box view that performs layout asynchronously + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.ArrayList; + +import javax.swing.event.DocumentEvent; +import javax.swing.text.Position.Bias; + +/** + * A {@link View} implementation that lays out its child views in a box, either + * vertically or horizontally. The difference to {@link BoxView} is that the + * layout is performed in an asynchronous manner. This helps to keep the + * eventqueue free from non-GUI related tasks. + * + * This view is currently not used in standard text components. In order to + * use it you would have to implement a special {@link EditorKit} with a + * {@link ViewFactory} that returns this view. For example: + * + *
      + * static class AsyncEditorKit extends StyledEditorKit implements ViewFactory
      + * {
      + *   public View create(Element el)
      + *   {
      + *     if (el.getName().equals(AbstractDocument.SectionElementName))
      + *       return new AsyncBoxView(el, View.Y_AXIS);
      + *     return super.getViewFactory().create(el);
      + *   }
      + *   public ViewFactory getViewFactory() {
      + *     return this;
      + *   }
      + * }
      + * 
      + * + * @author Roman Kennke (kennke@aicas.com) + * + * @since 1.3 + */ +public class AsyncBoxView + extends View +{ + + /** + * Manages the effective position of child views. That keeps the visible + * layout stable while the AsyncBoxView might be changing until the layout + * thread decides to publish the new layout. + */ + public class ChildLocator + { + + /** + * The last valid location. + */ + protected ChildState lastValidOffset; + + /** + * The last allocation. + */ + protected Rectangle lastAlloc; + + /** + * A Rectangle used for child allocation calculation to avoid creation + * of lots of garbage Rectangle objects. + */ + protected Rectangle childAlloc; + + /** + * Creates a new ChildLocator. + */ + public ChildLocator() + { + lastAlloc = new Rectangle(); + childAlloc = new Rectangle(); + } + + /** + * Receives notification that a child has changed. This is called by + * child state objects that have changed it's major span. + * + * This sets the {@link #lastValidOffset} field to cs if + * the new child state's view start offset is smaller than the start offset + * of the current child state's view or when lastValidOffset + * is null. + * + * @param cs the child state object that has changed + */ + public synchronized void childChanged(ChildState cs) + { + if (lastValidOffset == null + || cs.getChildView().getStartOffset() + < lastValidOffset.getChildView().getStartOffset()) + { + lastValidOffset = cs; + } + } + + /** + * Returns the view index of the view that occupies the specified area, or + * -1 if there is no such child view. + * + * @param x the x coordinate (relative to a) + * @param y the y coordinate (relative to a) + * @param a the current allocation of this view + * + * @return the view index of the view that occupies the specified area, or + * -1 if there is no such child view + */ + public int getViewIndexAtPoint(float x, float y, Shape a) + { + setAllocation(a); + float targetOffset = (getMajorAxis() == X_AXIS) ? x - lastAlloc.x + : y - lastAlloc.y; + int index = getViewIndexAtVisualOffset(targetOffset); + return index; + } + + /** + * Returns the current allocation for a child view. This updates the + * offsets for all children before the requested child view. + * + * @param index the index of the child view + * @param a the current allocation of this view + * + * @return the current allocation for a child view + */ + public synchronized Shape getChildAllocation(int index, Shape a) + { + if (a == null) + return null; + setAllocation(a); + ChildState cs = getChildState(index); + if (cs.getChildView().getStartOffset() + > lastValidOffset.getChildView().getStartOffset()) + { + updateChildOffsetsToIndex(index); + } + Shape ca = getChildAllocation(index); + return ca; + } + + /** + * Paints all child views. + * + * @param g the graphics context to use + */ + public synchronized void paintChildren(Graphics g) + { + Rectangle clip = g.getClipBounds(); + float targetOffset = (getMajorAxis() == X_AXIS) ? clip.x - lastAlloc.x + : clip.y - lastAlloc.y; + int index = getViewIndexAtVisualOffset(targetOffset); + int n = getViewCount(); + float offs = getChildState(index).getMajorOffset(); + for (int i = index; i < n; i++) + { + ChildState cs = getChildState(i); + cs.setMajorOffset(offs); + Shape ca = getChildAllocation(i); + if (ca.intersects(clip)) + { + synchronized (cs) + { + View v = cs.getChildView(); + v.paint(g, ca); + } + } + else + { + // done painting intersection + break; + } + offs += cs.getMajorSpan(); + } + } + + /** + * Returns the current allocation of the child view with the specified + * index. Note that this will not update any location information. + * + * @param index the index of the requested child view + * + * @return the current allocation of the child view with the specified + * index + */ + protected Shape getChildAllocation(int index) + { + ChildState cs = getChildState(index); + if (! cs.isLayoutValid()) + cs.run(); + + if (getMajorAxis() == X_AXIS) + { + childAlloc.x = lastAlloc.x + (int) cs.getMajorOffset(); + childAlloc.y = lastAlloc.y + (int) cs.getMinorOffset(); + childAlloc.width = (int) cs.getMajorSpan(); + childAlloc.height = (int) cs.getMinorSpan(); + } + else + { + childAlloc.y = lastAlloc.y + (int) cs.getMajorOffset(); + childAlloc.x = lastAlloc.x + (int) cs.getMinorOffset(); + childAlloc.height = (int) cs.getMajorSpan(); + childAlloc.width = (int) cs.getMinorSpan(); + } + return childAlloc; + } + + /** + * Sets the current allocation for this view. + * + * @param a the allocation to set + */ + protected void setAllocation(Shape a) + { + if (a instanceof Rectangle) + lastAlloc.setBounds((Rectangle) a); + else + lastAlloc.setBounds(a.getBounds()); + + setSize(lastAlloc.width, lastAlloc.height); + } + + /** + * Returns the index of the view at the specified offset along the major + * layout axis. + * + * @param targetOffset the requested offset + * + * @return the index of the view at the specified offset along the major + * layout axis + */ + protected int getViewIndexAtVisualOffset(float targetOffset) + { + int n = getViewCount(); + if (n > 0) + { + if (lastValidOffset == null) + lastValidOffset = getChildState(0); + if (targetOffset > majorSpan) + return 0; + else if (targetOffset > lastValidOffset.getMajorOffset()) + return updateChildOffsets(targetOffset); + else + { + float offs = 0f; + for (int i = 0; i < n; i++) + { + ChildState cs = getChildState(i); + float nextOffs = offs + cs.getMajorSpan(); + if (targetOffset < nextOffs) + return i; + offs = nextOffs; + } + } + } + return n - 1; + } + + /** + * Updates all the child view offsets up to the specified targetOffset. + * + * @param targetOffset the offset up to which the child view offsets are + * updated + * + * @return the index of the view at the specified offset + */ + private int updateChildOffsets(float targetOffset) + { + int n = getViewCount(); + int targetIndex = n - 1;; + int pos = lastValidOffset.getChildView().getStartOffset(); + int startIndex = getViewIndexAtPosition(pos, Position.Bias.Forward); + float start = lastValidOffset.getMajorOffset(); + float lastOffset = start; + for (int i = startIndex; i < n; i++) + { + ChildState cs = getChildState(i); + cs.setMajorOffset(lastOffset); + lastOffset += cs.getMajorSpan(); + if (targetOffset < lastOffset) + { + targetIndex = i; + lastValidOffset = cs; + break; + } + } + return targetIndex; + } + + /** + * Updates the offsets of the child views up to the specified index. + * + * @param index the index up to which the offsets are updated + */ + private void updateChildOffsetsToIndex(int index) + { + int pos = lastValidOffset.getChildView().getStartOffset(); + int startIndex = getViewIndexAtPosition(pos, Position.Bias.Forward); + float lastOffset = lastValidOffset.getMajorOffset(); + for (int i = startIndex; i <= index; i++) + { + ChildState cs = getChildState(i); + cs.setMajorOffset(lastOffset); + lastOffset += cs.getMajorSpan(); + } + } + } + + /** + * Represents the layout state of a child view. + */ + public class ChildState + implements Runnable + { + + /** + * The child view for this state record. + */ + private View childView; + + /** + * Indicates if the minor axis requirements of this child view are valid + * or not. + */ + private boolean minorValid; + + /** + * Indicates if the major axis requirements of this child view are valid + * or not. + */ + private boolean majorValid; + + /** + * Indicates if the current child size is valid. This is package private + * to avoid synthetic accessor method. + */ + boolean childSizeValid; + + /** + * The child views minimumSpan. This is package private to avoid accessor + * method. + */ + float minimum; + + /** + * The child views preferredSpan. This is package private to avoid accessor + * method. + */ + float preferred; + + /** + * The current span of the child view along the major axis. + */ + private float majorSpan; + + /** + * The current offset of the child view along the major axis. + */ + private float majorOffset; + + /** + * The current span of the child view along the minor axis. + */ + private float minorSpan; + + /** + * The current offset of the child view along the major axis. + */ + private float minorOffset; + + /** + * The child views maximumSpan. + */ + private float maximum; + + /** + * Creates a new ChildState object for the specified child + * view. + * + * @param view the child view for which to create the state record + */ + public ChildState(View view) + { + childView = view; + } + + /** + * Returns the child view for which this ChildState represents + * the layout state. + * + * @return the child view for this child state object + */ + public View getChildView() + { + return childView; + } + + /** + * Returns true if the current layout information is valid, + * false otherwise. + * + * @return true if the current layout information is valid, + * false otherwise + */ + public boolean isLayoutValid() + { + return minorValid && majorValid && childSizeValid; + } + + /** + * Performs the layout update for the child view managed by this + * ChildState. + */ + public void run() + { + Document doc = getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument abstractDoc = (AbstractDocument) doc; + abstractDoc.readLock(); + } + + try + { + + if (!(minorValid && majorValid && childSizeValid) + && childView.getParent() == AsyncBoxView.this) + { + synchronized(AsyncBoxView.this) + { + changing = this; + } + update(); + synchronized(AsyncBoxView.this) + { + changing = null; + } + // Changing the major axis may cause the minor axis + // requirements to have changed, so we need to do this again. + update(); + } + } + finally + { + if (doc instanceof AbstractDocument) + { + AbstractDocument abstractDoc = (AbstractDocument) doc; + abstractDoc.readUnlock(); + } + } + } + + /** + * Performs the actual update after the run methods has made its checks + * and locked the document. + */ + private void update() + { + int majorAxis = getMajorAxis(); + boolean minorUpdated = false; + synchronized (this) + { + if (! minorValid) + { + int minorAxis = getMinorAxis(); + minimum = childView.getMinimumSpan(minorAxis); + preferred = childView.getPreferredSpan(minorAxis); + maximum = childView.getMaximumSpan(minorAxis); + minorValid = true; + minorUpdated = true; + } + } + if (minorUpdated) + minorRequirementChange(this); + + boolean majorUpdated = false; + float delta = 0.0F; + synchronized (this) + { + if (! majorValid) + { + float oldSpan = majorSpan; + majorSpan = childView.getPreferredSpan(majorAxis); + delta = majorSpan - oldSpan; + majorValid = true; + majorUpdated = true; + } + } + if (majorUpdated) + { + majorRequirementChange(this, delta); + locator.childChanged(this); + } + + synchronized (this) + { + if (! childSizeValid) + { + float w; + float h; + if (majorAxis == X_AXIS) + { + w = majorSpan; + h = getMinorSpan(); + } + else + { + w = getMinorSpan(); + h = majorSpan; + } + childSizeValid = true; + childView.setSize(w, h); + } + } + } + + /** + * Returns the span of the child view along the minor layout axis. + * + * @return the span of the child view along the minor layout axis + */ + public float getMinorSpan() + { + float retVal; + if (maximum < minorSpan) + retVal = maximum; + else + retVal = Math.max(minimum, minorSpan); + return retVal; + } + + /** + * Returns the offset of the child view along the minor layout axis. + * + * @return the offset of the child view along the minor layout axis + */ + public float getMinorOffset() + { + float retVal; + if (maximum < minorSpan) + { + float align = childView.getAlignment(getMinorAxis()); + retVal = ((minorSpan - maximum) * align); + } + else + retVal = 0f; + + return retVal; + } + + /** + * Returns the span of the child view along the major layout axis. + * + * @return the span of the child view along the major layout axis + */ + + public float getMajorSpan() + { + return majorSpan; + } + + /** + * Returns the offset of the child view along the major layout axis. + * + * @return the offset of the child view along the major layout axis + */ + public float getMajorOffset() + { + return majorOffset; + } + + /** + * Sets the offset of the child view along the major layout axis. This + * should only be called by the ChildLocator of that child view. + * + * @param offset the offset to set + */ + public void setMajorOffset(float offset) + { + majorOffset = offset; + } + + /** + * Mark the preferences changed for that child. This forwards to + * {@link AsyncBoxView#preferenceChanged}. + * + * @param width true if the width preference has changed + * @param height true if the height preference has changed + */ + public void preferenceChanged(boolean width, boolean height) + { + if (getMajorAxis() == X_AXIS) + { + if (width) + majorValid = false; + if (height) + minorValid = false; + } + else + { + if (width) + minorValid = false; + if (height) + majorValid = false; + } + childSizeValid = false; + } + } + + /** + * Flushes the requirements changes upwards asynchronously. + */ + private class FlushTask implements Runnable + { + /** + * Starts the flush task. This obtains a readLock on the document + * and then flushes all the updates using + * {@link AsyncBoxView#flushRequirementChanges()} after updating the + * requirements. + */ + public void run() + { + try + { + // Acquire a lock on the document. + Document doc = getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument abstractDoc = (AbstractDocument) doc; + abstractDoc.readLock(); + } + + int n = getViewCount(); + if (minorChanged && (n > 0)) + { + LayoutQueue q = getLayoutQueue(); + ChildState min = getChildState(0); + ChildState pref = getChildState(0); + for (int i = 1; i < n; i++) + { + ChildState cs = getChildState(i); + if (cs.minimum > min.minimum) + min = cs; + if (cs.preferred > pref.preferred) + pref = cs; + } + synchronized (AsyncBoxView.this) + { + minReq = min; + prefReq = pref; + } + } + + flushRequirementChanges(); + } + finally + { + // Release the lock on the document. + Document doc = getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument abstractDoc = (AbstractDocument) doc; + abstractDoc.readUnlock(); + } + } + } + + } + + /** + * The major layout axis. + */ + private int majorAxis; + + /** + * The top inset. + */ + private float topInset; + + /** + * The bottom inset. + */ + private float bottomInset; + + /** + * The left inset. + */ + private float leftInset; + + /** + * Indicates if the major span should be treated as beeing estimated or not. + */ + private boolean estimatedMajorSpan; + + /** + * The right inset. + */ + private float rightInset; + + /** + * The children and their layout statistics. + */ + private ArrayList childStates; + + /** + * The currently changing child state. May be null if there is no child state + * updating at the moment. This is package private to avoid a synthetic + * accessor method inside ChildState. + */ + ChildState changing; + + /** + * Represents the minimum requirements. This is used in + * {@link #getMinimumSpan(int)}. + */ + ChildState minReq; + + /** + * Represents the minimum requirements. This is used in + * {@link #getPreferredSpan(int)}. + */ + ChildState prefReq; + + /** + * Indicates that the major axis requirements have changed. + */ + private boolean majorChanged; + + /** + * Indicates that the minor axis requirements have changed. This is package + * private to avoid synthetic accessor method. + */ + boolean minorChanged; + + /** + * The current span along the major layout axis. This is package private to + * avoid synthetic accessor method. + */ + float majorSpan; + + /** + * The current span along the minor layout axis. This is package private to + * avoid synthetic accessor method. + */ + float minorSpan; + + /** + * This tasked is placed on the layout queue to flush updates up to the + * parent view. + */ + private Runnable flushTask; + + /** + * The child locator for this view. + */ + protected ChildLocator locator; + + /** + * Creates a new AsyncBoxView that represents the specified + * element and layouts its children along the specified axis. + * + * @param elem the element + * @param axis the layout axis + */ + public AsyncBoxView(Element elem, int axis) + { + super(elem); + majorAxis = axis; + childStates = new ArrayList(); + flushTask = new FlushTask(); + locator = new ChildLocator(); + minorSpan = Short.MAX_VALUE; + } + + /** + * Returns the major layout axis. + * + * @return the major layout axis + */ + public int getMajorAxis() + { + return majorAxis; + } + + /** + * Returns the minor layout axis, that is the axis orthogonal to the major + * layout axis. + * + * @return the minor layout axis + */ + public int getMinorAxis() + { + return majorAxis == X_AXIS ? Y_AXIS : X_AXIS; + } + + /** + * Returns the view at the specified index. + * + * @param index the index of the requested child view + * + * @return the view at the specified index + */ + public View getView(int index) + { + View view = null; + synchronized(childStates) + { + if ((index >= 0) && (index < childStates.size())) + { + ChildState cs = (ChildState) childStates.get(index); + view = cs.getChildView(); + } + } + return view; + } + + /** + * Returns the number of child views. + * + * @return the number of child views + */ + public int getViewCount() + { + synchronized(childStates) + { + return childStates.size(); + } + } + + /** + * Returns the view index of the child view that represents the specified + * model position. + * + * @param pos the model position for which we search the view index + * @param bias the bias + * + * @return the view index of the child view that represents the specified + * model position + */ + public int getViewIndex(int pos, Position.Bias bias) + { + int retVal = -1; + + if (bias == Position.Bias.Backward) + pos = Math.max(0, pos - 1); + + // TODO: A possible optimization would be to implement a binary search + // here. + int numChildren = childStates.size(); + if (numChildren > 0) + { + for (int i = 0; i < numChildren; ++i) + { + View child = ((ChildState) childStates.get(i)).getChildView(); + if (child.getStartOffset() <= pos && child.getEndOffset() > pos) + { + retVal = i; + break; + } + } + } + return retVal; + } + + /** + * Returns the top inset. + * + * @return the top inset + */ + public float getTopInset() + { + return topInset; + } + + /** + * Sets the top inset. + * + * @param top the top inset + */ + public void setTopInset(float top) + { + topInset = top; + } + + /** + * Returns the bottom inset. + * + * @return the bottom inset + */ + public float getBottomInset() + { + return bottomInset; + } + + /** + * Sets the bottom inset. + * + * @param bottom the bottom inset + */ + public void setBottomInset(float bottom) + { + bottomInset = bottom; + } + + /** + * Returns the left inset. + * + * @return the left inset + */ + public float getLeftInset() + { + return leftInset; + } + + /** + * Sets the left inset. + * + * @param left the left inset + */ + public void setLeftInset(float left) + { + leftInset = left; + } + + /** + * Returns the right inset. + * + * @return the right inset + */ + public float getRightInset() + { + return rightInset; + } + + /** + * Sets the right inset. + * + * @param right the right inset + */ + public void setRightInset(float right) + { + rightInset = right; + } + + /** + * Loads the child views of this view. This is triggered by + * {@link #setParent(View)}. + * + * @param f the view factory to build child views with + */ + protected void loadChildren(ViewFactory f) + { + Element e = getElement(); + int n = e.getElementCount(); + if (n > 0) + { + View[] added = new View[n]; + for (int i = 0; i < n; i++) + { + added[i] = f.create(e.getElement(i)); + } + replace(0, 0, added); + } + } + + /** + * Returns the span along an axis that is taken up by the insets. + * + * @param axis the axis + * + * @return the span along an axis that is taken up by the insets + * + * @since 1.4 + */ + protected float getInsetSpan(int axis) + { + float span; + if (axis == X_AXIS) + span = leftInset + rightInset; + else + span = topInset + bottomInset; + return span; + } + + /** + * Sets the estimatedMajorSpan property that determines if + * the major span should be treated as beeing estimated. + * + * @param estimated if the major span should be treated as estimated or not + * + * @since 1.4 + */ + public void setEstimatedMajorSpan(boolean estimated) + { + estimatedMajorSpan = estimated; + } + + /** + * Determines whether the major span should be treated as estimated or as + * beeing accurate. + * + * @return true if the major span should be treated as + * estimated, false if the major span should be treated + * as accurate + * + * @since 1.4 + */ + public boolean getEstimatedMajorSpan() + { + return estimatedMajorSpan; + } + + /** + * Receives notification from the child states that the requirements along + * the minor axis have changed. + * + * @param cs the child state from which this notification is messaged + */ + protected synchronized void minorRequirementChange(ChildState cs) + { + minorChanged = true; + } + + /** + * Receives notification from the child states that the requirements along + * the major axis have changed. + * + * @param cs the child state from which this notification is messaged + */ + protected void majorRequirementChange(ChildState cs, float delta) + { + if (! estimatedMajorSpan) + majorSpan += delta; + majorChanged = true; + } + + /** + * Sets the parent for this view. This calls loadChildren if + * parent is not null and there have not been any + * child views initializes. + * + * @param parent the new parent view; null if this view is + * removed from the view hierarchy + * + * @see View#setParent(View) + */ + public void setParent(View parent) + { + super.setParent(parent); + if ((parent != null) && (getViewCount() == 0)) + { + ViewFactory f = getViewFactory(); + loadChildren(f); + } + } + + /** + * Sets the size of this view. This is ususally called before {@link #paint} + * is called to make sure the view has a valid layout. + * + * This implementation queues layout requests for every child view if the + * minor axis span has changed. (The major axis span is requested to never + * change for this view). + * + * @param width the width of the view + * @param height the height of the view + */ + public void setSize(float width, float height) + { + float targetSpan; + if (majorAxis == X_AXIS) + targetSpan = height - getTopInset() - getBottomInset(); + else + targetSpan = width - getLeftInset() - getRightInset(); + + if (targetSpan != minorSpan) + { + minorSpan = targetSpan; + + int n = getViewCount(); + LayoutQueue q = getLayoutQueue(); + for (int i = 0; i < n; i++) + { + ChildState cs = getChildState(i); + cs.childSizeValid = false; + q.addTask(cs); + } + q.addTask(flushTask); + } + } + + /** + * Replaces child views with new child views. + * + * This creates ChildState objects for all the new views and adds layout + * requests for them to the layout queue. + * + * @param offset the offset at which to remove/insert + * @param length the number of child views to remove + * @param views the new child views to insert + */ + public void replace(int offset, int length, View[] views) + { + synchronized(childStates) + { + LayoutQueue q = getLayoutQueue(); + for (int i = 0; i < length; i++) + childStates.remove(offset); + + for (int i = views.length - 1; i >= 0; i--) + childStates.add(offset, createChildState(views[i])); + + // We need to go through the new child states _after_ they have been + // added to the childStates list, otherwise the layout tasks may find + // an incomplete child list. That means we have to loop through + // them again, but what else can we do? + if (views.length != 0) + { + for (int i = 0; i < views.length; i++) + { + ChildState cs = (ChildState) childStates.get(i + offset); + cs.getChildView().setParent(this); + q.addTask(cs); + } + q.addTask(flushTask); + } + } + } + + /** + * Paints the view. This requests the {@link ChildLocator} to paint the views + * after setting the allocation on it. + * + * @param g the graphics context to use + * @param s the allocation for this view + */ + public void paint(Graphics g, Shape s) + { + synchronized (locator) + { + locator.setAllocation(s); + locator.paintChildren(g); + } + } + + /** + * Returns the preferred span of this view along the specified layout axis. + * + * @return the preferred span of this view along the specified layout axis + */ + public float getPreferredSpan(int axis) + { + float retVal; + if (majorAxis == axis) + retVal = majorSpan; + + else if (prefReq != null) + { + View child = prefReq.getChildView(); + retVal = child.getPreferredSpan(axis); + } + + // If we have no layout information yet, then return insets + 30 as + // an estimation. + else + { + if (axis == X_AXIS) + retVal = getLeftInset() + getRightInset() + 30; + else + retVal = getTopInset() + getBottomInset() + 30; + } + return retVal; + } + + /** + * Maps a model location to view coordinates. + * + * @param pos the model location + * @param a the current allocation of this view + * @param b the bias + * + * @return the view allocation for the specified model location + */ + public Shape modelToView(int pos, Shape a, Bias b) + throws BadLocationException + { + int index = getViewIndexAtPosition(pos, b); + Shape ca = locator.getChildAllocation(index, a); + + ChildState cs = getChildState(index); + synchronized (cs) + { + View cv = cs.getChildView(); + Shape v = cv.modelToView(pos, ca, b); + return v; + } + } + + /** + * Maps view coordinates to a model location. + * + * @param x the x coordinate (relative to a) + * @param y the y coordinate (relative to a) + * @param b holds the bias of the model location on method exit + * + * @return the model location for the specified view location + */ + public int viewToModel(float x, float y, Shape a, Bias[] b) + { + int pos; + int index; + Shape ca; + + synchronized (locator) + { + index = locator.getViewIndexAtPoint(x, y, a); + ca = locator.getChildAllocation(index, a); + } + + ChildState cs = getChildState(index); + synchronized (cs) + { + View v = cs.getChildView(); + pos = v.viewToModel(x, y, ca, b); + } + return pos; + } + + /** + * Returns the child allocation for the child view with the specified + * index. + * + * @param index the index of the child view + * @param a the current allocation of this view + * + * @return the allocation of the child view + */ + public Shape getChildAllocation(int index, Shape a) + { + Shape ca = locator.getChildAllocation(index, a); + return ca; + } + + /** + * Returns the maximum span of this view along the specified axis. + * This is implemented to return the preferredSpan for the + * major axis (that means the box can't be resized along the major axis) and + * {@link Short#MAX_VALUE} for the minor axis. + * + * @param axis the axis + * + * @return the maximum span of this view along the specified axis + */ + public float getMaximumSpan(int axis) + { + float max; + if (axis == majorAxis) + max = getPreferredSpan(axis); + else + max = Short.MAX_VALUE; + return max; + } + + /** + * Returns the minimum span along the specified axis. + */ + public float getMinimumSpan(int axis) + { + float min; + if (axis == majorAxis) + min = getPreferredSpan(axis); + else + { + if (minReq != null) + { + View child = minReq.getChildView(); + min = child.getMinimumSpan(axis); + } + else + { + // No layout information yet. Return insets + 5 as some kind of + // estimation. + if (axis == X_AXIS) + min = getLeftInset() + getRightInset() + 5; + else + min = getTopInset() + getBottomInset() + 5; + } + } + return min; + } + + /** + * Receives notification that one of the child views has changed its + * layout preferences along one or both axis. + * + * This queues a layout request for that child view if necessary. + * + * @param view the view that has changed its preferences + * @param width true if the width preference has changed + * @param height true if the height preference has changed + */ + public synchronized void preferenceChanged(View view, boolean width, + boolean height) + { + if (view == null) + getParent().preferenceChanged(this, width, height); + else + { + if (changing != null) + { + View cv = changing.getChildView(); + if (cv == view) + { + changing.preferenceChanged(width, height); + return; + } + } + int index = getViewIndexAtPosition(view.getStartOffset(), + Position.Bias.Forward); + ChildState cs = getChildState(index); + cs.preferenceChanged(width, height); + LayoutQueue q = getLayoutQueue(); + q.addTask(cs); + q.addTask(flushTask); + } + } + + /** + * Updates the layout for this view. This is implemented to trigger + * {link ChildLocator#childChanged} for the changed view, if there is + * any. + * + * @param ec the element change, may be null if there were + * no changes to the element of this view + * @param e the document event + * @param a the current allocation of this view + */ + protected void updateLayout(DocumentEvent.ElementChange ec, + DocumentEvent e, Shape a) + { + if (ec != null) + { + int index = Math.max(ec.getIndex() - 1, 0); + ChildState cs = getChildState(index); + locator.childChanged(cs); + } + } + + + /** + * Returns the ChildState object associated with the child view + * at the specified index. + * + * @param index the index of the child view for which to query the state + * + * @return the child state for the specified child view + */ + protected ChildState getChildState(int index) { + synchronized (childStates) + { + return (ChildState) childStates.get(index); + } + } + + /** + * Returns the LayoutQueue used for layouting the box view. + * This simply returns {@link LayoutQueue#getDefaultQueue()}. + * + * @return the LayoutQueue used for layouting the box view + */ + protected LayoutQueue getLayoutQueue() + { + return LayoutQueue.getDefaultQueue(); + } + + /** + * Returns the child view index of the view that represents the specified + * position in the document model. + * + * @param pos the position in the model + * @param b the bias + * + * @return the child view index of the view that represents the specified + * position in the document model + */ + protected synchronized int getViewIndexAtPosition(int pos, Position.Bias b) + { + if (b == Position.Bias.Backward) + pos = Math.max(0, pos - 1); + Element elem = getElement(); + return elem.getElementIndex(pos); + } + + /** + * Creates a ChildState object for the specified view. + * + * @param v the view for which to create a child state object + * + * @return the created child state + */ + protected ChildState createChildState(View v) + { + return new ChildState(v); + } + + /** + * Flushes the requirements changes upwards to the parent view. This is + * called from the layout thread. + */ + protected synchronized void flushRequirementChanges() + { + if (majorChanged || minorChanged) + { + View p = getParent(); + if (p != null) + { + boolean horizontal; + boolean vertical; + if (majorAxis == X_AXIS) + { + horizontal = majorChanged; + vertical = minorChanged; + } + else + { + vertical = majorChanged; + horizontal = minorChanged; + } + + p.preferenceChanged(this, horizontal, vertical); + majorChanged = false; + minorChanged = false; + + Component c = getContainer(); + if (c != null) + c.repaint(); + } + } + } +} diff --git a/javax/swing/text/BoxView.java b/javax/swing/text/BoxView.java index 5c9587dfe..b5907dcbb 100644 --- a/javax/swing/text/BoxView.java +++ b/javax/swing/text/BoxView.java @@ -43,6 +43,7 @@ import java.awt.Rectangle; import java.awt.Shape; import javax.swing.SizeRequirements; +import javax.swing.event.DocumentEvent; /** * An implementation of {@link CompositeView} that arranges its children in @@ -58,49 +59,37 @@ public class BoxView /** * The axis along which this BoxView is laid out. */ - int myAxis; + private int myAxis; /** - * Indicates wether the layout in X_AXIS is valid. + * Indicates if the layout is valid along X_AXIS or Y_AXIS. */ - boolean xLayoutValid; + private boolean[] layoutValid = new boolean[2]; /** - * Indicates whether the layout in Y_AXIS is valid. + * The spans along the X_AXIS and Y_AXIS. */ - boolean yLayoutValid; + private int[][] spans = new int[2][]; /** - * The spans in X direction of the children. + * The offsets of the children along the X_AXIS and Y_AXIS. */ - int[] spansX; + private int[][] offsets = new int[2][]; /** - * The spans in Y direction of the children. + * The size requirements along the X_AXIS and Y_AXIS. */ - int[] spansY; + private SizeRequirements[] requirements = new SizeRequirements[2]; /** - * The offsets of the children in X direction relative to this BoxView's - * inner bounds. + * The current span along X_AXIS or Y_AXIS. */ - int[] offsetsX; + private int[] span = new int[2]; /** - * The offsets of the children in Y direction relative to this BoxView's - * inner bounds. + * The SizeRequirements of the child views along the X_AXIS and Y_AXIS. */ - int[] offsetsY; - - /** - * The current width. - */ - int width; - - /** - * The current height. - */ - int height; + private SizeRequirements[][] childReqs = new SizeRequirements[2][]; /** * Creates a new BoxView for the given @@ -114,23 +103,26 @@ public class BoxView { super(element); myAxis = axis; - xLayoutValid = false; - yLayoutValid = false; + layoutValid[0] = false; + layoutValid[1] = false; + span[0] = 0; + span[1] = 0; + requirements[0] = new SizeRequirements(); + requirements[1] = new SizeRequirements(); // Initialize the cache arrays. - spansX = new int[0]; - spansY = new int[0]; - offsetsX = new int[0]; - offsetsY = new int[0]; - - width = 0; - height = 0; + spans[0] = new int[0]; + spans[1] = new int[0]; + offsets[0] = new int[0]; + offsets[1] = new int[0]; } /** * Returns the axis along which this BoxView is laid out. * * @return the axis along which this BoxView is laid out + * + * @since 1.3 */ public int getAxis() { @@ -144,6 +136,8 @@ public class BoxView * {@link View#Y_AXIS}. * * @param axis the axis along which this BoxView is laid out + * + * @since 1.3 */ public void setAxis(int axis) { @@ -163,20 +157,14 @@ public class BoxView * {@link View#Y_AXIS}. * * @param axis an int value + * + * @since 1.3 */ public void layoutChanged(int axis) { - switch (axis) - { - case X_AXIS: - xLayoutValid = false; - break; - case Y_AXIS: - yLayoutValid = false; - break; - default: - throw new IllegalArgumentException("Invalid axis parameter."); - } + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Invalid axis parameter."); + layoutValid[axis] = false; } /** @@ -190,22 +178,14 @@ public class BoxView * * @return true if the layout along the specified * axis is valid, false otherwise + * + * @since 1.4 */ protected boolean isLayoutValid(int axis) { - boolean valid = false; - switch (axis) - { - case X_AXIS: - valid = xLayoutValid; - break; - case Y_AXIS: - valid = yLayoutValid; - break; - default: - throw new IllegalArgumentException("Invalid axis parameter."); - } - return valid; + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Invalid axis parameter."); + return layoutValid[axis]; } /** @@ -242,40 +222,44 @@ public class BoxView */ public void replace(int offset, int length, View[] views) { + int numViews = 0; + if (views != null) + numViews = views.length; + // Resize and copy data for cache arrays. // The spansX cache. int oldSize = getViewCount(); - int[] newSpansX = new int[oldSize - length + views.length]; - System.arraycopy(spansX, 0, newSpansX, 0, offset); - System.arraycopy(spansX, offset + length, newSpansX, - offset + views.length, + int[] newSpansX = new int[oldSize - length + numViews]; + System.arraycopy(spans[X_AXIS], 0, newSpansX, 0, offset); + System.arraycopy(spans[X_AXIS], offset + length, newSpansX, + offset + numViews, oldSize - (offset + length)); - spansX = newSpansX; + spans[X_AXIS] = newSpansX; // The spansY cache. - int[] newSpansY = new int[oldSize - length + views.length]; - System.arraycopy(spansY, 0, newSpansY, 0, offset); - System.arraycopy(spansY, offset + length, newSpansY, - offset + views.length, + int[] newSpansY = new int[oldSize - length + numViews]; + System.arraycopy(spans[Y_AXIS], 0, newSpansY, 0, offset); + System.arraycopy(spans[Y_AXIS], offset + length, newSpansY, + offset + numViews, oldSize - (offset + length)); - spansY = newSpansY; + spans[Y_AXIS] = newSpansY; // The offsetsX cache. - int[] newOffsetsX = new int[oldSize - length + views.length]; - System.arraycopy(offsetsX, 0, newOffsetsX, 0, offset); - System.arraycopy(offsetsX, offset + length, newOffsetsX, - offset + views.length, + int[] newOffsetsX = new int[oldSize - length + numViews]; + System.arraycopy(offsets[X_AXIS], 0, newOffsetsX, 0, offset); + System.arraycopy(offsets[X_AXIS], offset + length, newOffsetsX, + offset + numViews, oldSize - (offset + length)); - offsetsX = newOffsetsX; + offsets[X_AXIS] = newOffsetsX; // The offsetsY cache. - int[] newOffsetsY = new int[oldSize - length + views.length]; - System.arraycopy(offsetsY, 0, newOffsetsY, 0, offset); - System.arraycopy(offsetsY, offset + length, newOffsetsY, - offset + views.length, + int[] newOffsetsY = new int[oldSize - length + numViews]; + System.arraycopy(offsets[Y_AXIS], 0, newOffsetsY, 0, offset); + System.arraycopy(offsets[Y_AXIS], offset + length, newOffsetsY, + offset + numViews, oldSize - (offset + length)); - offsetsY = newOffsetsY; + offsets[Y_AXIS] = newOffsetsY; // Actually perform the replace. super.replace(offset, length, views); @@ -294,13 +278,10 @@ public class BoxView */ public void paint(Graphics g, Shape a) { - // Adjust size if the size is changed. - Rectangle bounds = a.getBounds(); - - if (bounds.width != getWidth() || bounds.height != getHeight()) - setSize(bounds.width, bounds.height); - Rectangle inside = getInsideAllocation(a); + // TODO: Used for debugging. + //g.drawRect(inside.x, inside.y, inside.width, inside.height); + Rectangle copy = new Rectangle(inside); int count = getViewCount(); for (int i = 0; i < count; ++i) @@ -323,22 +304,50 @@ public class BoxView */ public float getPreferredSpan(int axis) { - SizeRequirements sr = new SizeRequirements(); - int pref = baselineRequirements(axis, sr).preferred; - return (float) pref; + updateRequirements(axis); + return requirements[axis].preferred; } + /** + * Returns the maximum span of this view along the specified axis. + * This returns Integer.MAX_VALUE for the minor axis + * and the preferred span for the major axis. + * + * @param axis the axis + * + * @return the maximum span of this view along the specified axis + */ public float getMaximumSpan(int axis) { - if (axis == getAxis()) - return getPreferredSpan(axis); + float max; + if (axis == myAxis) + max = getPreferredSpan(axis); else - return Integer.MAX_VALUE; + max = Integer.MAX_VALUE; + return max; } /** - * Calculates the size requirements for this BoxView along - * the specified axis. + * Returns the minimum span of this view along the specified axis. + * This calculates the minimum span using + * {@link #calculateMajorAxisRequirements} or + * {@link #calculateMinorAxisRequirements} (depending on the axis) and + * returns the resulting minimum span. + * + * @param axis the axis + * + * @return the minimum span of this view along the specified axis + */ + public float getMinimumSpan(int axis) + { + updateRequirements(axis); + return requirements[axis].minimum; + } + + /** + * This method is obsolete and no longer in use. It is replaced by + * {@link #calculateMajorAxisRequirements(int, SizeRequirements)} and + * {@link #calculateMinorAxisRequirements(int, SizeRequirements)}. * * @param axis the axis that is examined * @param sr the SizeRequirements object to hold the result, @@ -350,12 +359,45 @@ public class BoxView protected SizeRequirements baselineRequirements(int axis, SizeRequirements sr) { - SizeRequirements result; - if (axis == myAxis) - result = calculateMajorAxisRequirements(axis, sr); - else - result = calculateMinorAxisRequirements(axis, sr); - return result; + updateChildRequirements(axis); + + SizeRequirements res = sr; + if (res == null) + res = new SizeRequirements(); + + float minLeft = 0; + float minRight = 0; + float prefLeft = 0; + float prefRight = 0; + float maxLeft = 0; + float maxRight = 0; + for (int i = 0; i < childReqs[axis].length; i++) + { + float myMinLeft = childReqs[axis][i].minimum * childReqs[axis][i].alignment; + float myMinRight = childReqs[axis][i].minimum - myMinLeft; + minLeft = Math.max(myMinLeft, minLeft); + minRight = Math.max(myMinRight, minRight); + float myPrefLeft = childReqs[axis][i].preferred * childReqs[axis][i].alignment; + float myPrefRight = childReqs[axis][i].preferred - myPrefLeft; + prefLeft = Math.max(myPrefLeft, prefLeft); + prefRight = Math.max(myPrefRight, prefRight); + float myMaxLeft = childReqs[axis][i].maximum * childReqs[axis][i].alignment; + float myMaxRight = childReqs[axis][i].maximum - myMaxLeft; + maxLeft = Math.max(myMaxLeft, maxLeft); + maxRight = Math.max(myMaxRight, maxRight); + } + int minSize = (int) (minLeft + minRight); + int prefSize = (int) (prefLeft + prefRight); + int maxSize = (int) (maxLeft + maxRight); + float align = prefLeft / (prefRight + prefLeft); + if (Float.isNaN(align)) + align = 0; + + res.alignment = align; + res.maximum = maxSize; + res.preferred = prefSize; + res.minimum = minSize; + return res; } /** @@ -370,10 +412,13 @@ public class BoxView protected void baselineLayout(int span, int axis, int[] offsets, int[] spans) { - if (axis == myAxis) - layoutMajorAxis(span, axis, offsets, spans); - else - layoutMinorAxis(span, axis, offsets, spans); + updateChildRequirements(axis); + updateRequirements(axis); + + // Calculate the spans and offsets using the SizeRequirements uility + // methods. + SizeRequirements.calculateAlignedPositions(span, requirements[axis], + childReqs[axis], offsets, spans); } /** @@ -390,8 +435,34 @@ public class BoxView protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements sr) { - SizeRequirements[] childReqs = getChildRequirements(axis); - return SizeRequirements.getTiledSizeRequirements(childReqs); + updateChildRequirements(axis); + + SizeRequirements result = sr; + if (result == null) + result = new SizeRequirements(); + + long minimum = 0; + long preferred = 0; + long maximum = 0; + for (int i = 0; i < children.length; i++) + { + minimum += childReqs[axis][i].minimum; + preferred += childReqs[axis][i].preferred; + maximum += childReqs[axis][i].maximum; + } + // Overflow check. + if (minimum > Integer.MAX_VALUE) + minimum = Integer.MAX_VALUE; + if (preferred > Integer.MAX_VALUE) + preferred = Integer.MAX_VALUE; + if (maximum > Integer.MAX_VALUE) + maximum = Integer.MAX_VALUE; + + result.minimum = (int) minimum; + result.preferred = (int) preferred; + result.maximum = (int) maximum; + result.alignment = 0.5F; + return result; } /** @@ -407,11 +478,49 @@ public class BoxView * the specified axis */ protected SizeRequirements calculateMinorAxisRequirements(int axis, - SizeRequirements sr) + SizeRequirements sr) { - SizeRequirements[] childReqs = getChildRequirements(axis); - return SizeRequirements.getAlignedSizeRequirements(childReqs); + updateChildRequirements(axis); + + SizeRequirements res = sr; + if (res == null) + res = new SizeRequirements(); + + float minLeft = 0; + float minRight = 0; + float prefLeft = 0; + float prefRight = 0; + float maxLeft = 0; + float maxRight = 0; + for (int i = 0; i < childReqs[axis].length; i++) + { + float myMinLeft = childReqs[axis][i].minimum * childReqs[axis][i].alignment; + float myMinRight = childReqs[axis][i].minimum - myMinLeft; + minLeft = Math.max(myMinLeft, minLeft); + minRight = Math.max(myMinRight, minRight); + float myPrefLeft = childReqs[axis][i].preferred * childReqs[axis][i].alignment; + float myPrefRight = childReqs[axis][i].preferred - myPrefLeft; + prefLeft = Math.max(myPrefLeft, prefLeft); + prefRight = Math.max(myPrefRight, prefRight); + float myMaxLeft = childReqs[axis][i].maximum * childReqs[axis][i].alignment; + float myMaxRight = childReqs[axis][i].maximum - myMaxLeft; + maxLeft = Math.max(myMaxLeft, maxLeft); + maxRight = Math.max(myMaxRight, maxRight); + } + int minSize = (int) (minLeft + minRight); + int prefSize = (int) (prefLeft + prefRight); + int maxSize = (int) (maxLeft + maxRight); + float align = prefLeft / (prefRight + prefLeft); + if (Float.isNaN(align)) + align = 0; + + res.alignment = align; + res.maximum = maxSize; + res.preferred = prefSize; + res.minimum = minSize; + return res; } + /** * Returns true if the specified point lies before the @@ -511,10 +620,10 @@ public class BoxView if (! isAllocationValid()) layout(a.width, a.height); - a.x += offsetsX[index]; - a.y += offsetsY[index]; - a.width = spansX[index]; - a.height = spansY[index]; + a.x += offsets[X_AXIS][index]; + a.y += offsets[Y_AXIS][index]; + a.width = spans[X_AXIS][index]; + a.height = spans[Y_AXIS][index]; } /** @@ -528,8 +637,49 @@ public class BoxView */ protected void layout(int width, int height) { - baselineLayout(width, X_AXIS, offsetsX, spansX); - baselineLayout(height, Y_AXIS, offsetsY, spansY); + int[] newSpan = new int[]{ width, height }; + int count = getViewCount(); + + // Update minor axis as appropriate. We need to first update the minor + // axis layout because that might affect the children's preferences along + // the major axis. + int minorAxis = myAxis == X_AXIS ? Y_AXIS : X_AXIS; + if ((! isLayoutValid(minorAxis)) || newSpan[minorAxis] != span[minorAxis]) + { + layoutValid[minorAxis] = false; + span[minorAxis] = newSpan[minorAxis]; + layoutMinorAxis(span[minorAxis], minorAxis, offsets[minorAxis], + spans[minorAxis]); + + // Update the child view's sizes. + for (int i = 0; i < count; ++i) + { + getView(i).setSize(spans[X_AXIS][i], spans[Y_AXIS][i]); + } + layoutValid[minorAxis] = true; + } + + + // Update major axis as appropriate. + if ((! isLayoutValid(myAxis)) || newSpan[myAxis] != span[myAxis]) + { + layoutValid[myAxis] = false; + span[myAxis] = newSpan[myAxis]; + layoutMajorAxis(span[myAxis], myAxis, offsets[myAxis], + spans[myAxis]); + + // Update the child view's sizes. + for (int i = 0; i < count; ++i) + { + getView(i).setSize(spans[X_AXIS][i], spans[Y_AXIS][i]); + } + layoutValid[myAxis] = true; + } + + if (layoutValid[myAxis] == false) + System.err.println("WARNING: Major axis layout must be valid after layout"); + if (layoutValid[minorAxis] == false) + System.err.println("Minor axis layout must be valid after layout"); } /** @@ -544,12 +694,15 @@ public class BoxView protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { - SizeRequirements[] childReqs = getChildRequirements(axis); + updateChildRequirements(axis); + updateRequirements(axis); + // Calculate the spans and offsets using the SizeRequirements uility // methods. - SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs, + SizeRequirements.calculateTiledPositions(targetSpan, requirements[axis], + childReqs[axis], offsets, spans); - validateLayout(axis); + } /** @@ -564,18 +717,14 @@ public class BoxView protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) { - SizeRequirements[] childReqs = getChildRequirements(axis); + updateChildRequirements(axis); + updateRequirements(axis); + // Calculate the spans and offsets using the SizeRequirements uility // methods. - // TODO: This might be an opportunity for performance optimization. Here - // we could use a cached instance of SizeRequirements instead of passing - // null to baselineRequirements. However, this would involve rewriting - // the baselineRequirements() method to not use the SizeRequirements - // utility method, since they cannot reuse a cached instance. - SizeRequirements total = baselineRequirements(axis, null); - SizeRequirements.calculateAlignedPositions(targetSpan, total, childReqs, - offsets, spans); - validateLayout(axis); + SizeRequirements.calculateAlignedPositions(targetSpan, requirements[axis], + childReqs[axis], offsets, + spans); } /** @@ -597,7 +746,7 @@ public class BoxView */ public int getWidth() { - return width; + return span[X_AXIS]; } /** @@ -607,7 +756,7 @@ public class BoxView */ public int getHeight() { - return height; + return span[Y_AXIS]; } /** @@ -619,54 +768,7 @@ public class BoxView */ public void setSize(float width, float height) { - if (this.width != (int) width) - layoutChanged(X_AXIS); - if (this.height != (int) height) - layoutChanged(Y_AXIS); - - this.width = (int) width; - this.height = (int) height; - - Rectangle outside = new Rectangle(0, 0, this.width, this.height); - Rectangle inside = getInsideAllocation(outside); - if (!isAllocationValid()) - layout(inside.width, inside.height); - } - - /** - * Sets the layout to valid for a specific axis. - * - * @param axis the axis for which to validate the layout - */ - void validateLayout(int axis) - { - if (axis == X_AXIS) - xLayoutValid = true; - if (axis == Y_AXIS) - yLayoutValid = true; - } - - /** - * Returns the size requirements of this view's children for the major - * axis. - * - * @return the size requirements of this view's children for the major - * axis - */ - SizeRequirements[] getChildRequirements(int axis) - { - // Allocate SizeRequirements for each child view. - int count = getViewCount(); - SizeRequirements[] childReqs = new SizeRequirements[count]; - for (int i = 0; i < count; ++i) - { - View view = getView(i); - childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis), - (int) view.getPreferredSpan(axis), - (int) view.getMaximumSpan(axis), - view.getAlignment(axis)); - } - return childReqs; + layout((int) width, (int) height); } /** @@ -682,10 +784,9 @@ public class BoxView */ protected int getSpan(int axis, int childIndex) { - if (axis == X_AXIS) - return spansX[childIndex]; - else - return spansY[childIndex]; + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Illegal axis argument"); + return spans[axis][childIndex]; } /** @@ -701,10 +802,9 @@ public class BoxView */ protected int getOffset(int axis, int childIndex) { - if (axis == X_AXIS) - return offsetsX[childIndex]; - else - return offsetsY[childIndex]; + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Illegal axis argument"); + return offsets[axis][childIndex]; } /** @@ -719,10 +819,15 @@ public class BoxView */ public float getAlignment(int axis) { + float align; if (axis == myAxis) - return 0.5F; + align = 0.5F; else - return baselineRequirements(axis, null).alignment; + { + updateRequirements(axis); + align = requirements[axis].alignment; + } + return align; } /** @@ -732,12 +837,12 @@ public class BoxView * @param height indicates that the preferred height of the child changed. * @param child the child View. */ - public void preferenceChanged (View child, boolean width, boolean height) + public void preferenceChanged(View child, boolean width, boolean height) { if (width) - xLayoutValid = false; + layoutValid[X_AXIS] = false; if (height) - yLayoutValid = false; + layoutValid[Y_AXIS] = false; super.preferenceChanged(child, width, height); } @@ -751,11 +856,118 @@ public class BoxView throws BadLocationException { // Make sure everything is allocated properly and then call super - if (!isAllocationValid()) + if (! isAllocationValid()) { Rectangle bounds = a.getBounds(); - setSize(bounds.width, bounds.height); + layout(bounds.width, bounds.height); } return super.modelToView(pos, a, bias); } + + /** + * Returns the resize weight of this view. A value of 0 or less + * means this view is not resizeable. Positive values make the view + * resizeable. This implementation returns 0 for the major + * axis and 1 for the minor axis of this box view. + * + * @param axis the axis + * + * @return the resizability of this view along the specified axis + * + * @throws IllegalArgumentException if axis is invalid + */ + public int getResizeWeight(int axis) + { + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException("Illegal axis argument"); + int weight = 1; + if (axis == myAxis) + weight = 0; + return weight; + } + + /** + * Returns the child allocation for the child view with the specified + * index. If the layout is invalid, this returns + * null. + * + * @param index the child view index + * @param a the allocation to this view + * + * @return the child allocation for the child view with the specified + * index or null if the layout is invalid + * or a is null + */ + public Shape getChildAllocation(int index, Shape a) + { + Shape ret = null; + if (isAllocationValid() && a != null) + ret = super.getChildAllocation(index, a); + return ret; + } + + protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent e, + Shape a, ViewFactory vf) + { + // FIXME: What to do here? + super.forwardUpdate(ec, e, a, vf); + } + + public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) + { + // FIXME: What to do here? + return super.viewToModel(x, y, a, bias); + } + + protected boolean flipEastAndWestEnds(int position, Position.Bias bias) + { + // FIXME: What to do here? + return super.flipEastAndWestAtEnds(position, bias); + } + + /** + * Updates the child requirements along the specified axis. The requirements + * are only updated if the layout for the specified axis is marked as + * invalid. + * + * @param axis the axis to be updated + */ + private void updateChildRequirements(int axis) + { + if (! isLayoutValid(axis)) + { + int numChildren = getViewCount(); + if (childReqs[axis] == null || childReqs[axis].length != numChildren) + childReqs[axis] = new SizeRequirements[numChildren]; + for (int i = 0; i < numChildren; ++i) + { + View child = getView(i); + childReqs[axis][i] = + new SizeRequirements((int) child.getMinimumSpan(axis), + (int) child.getPreferredSpan(axis), + (int) child.getMaximumSpan(axis), + child.getAlignment(axis)); + } + } + } + + /** + * Updates the view's cached requirements along the specified axis if + * necessary. The requirements are only updated if the layout for the + * specified axis is marked as invalid. + * + * @param axis the axis + */ + private void updateRequirements(int axis) + { + if (! layoutValid[axis]) + { + if (axis == myAxis) + requirements[axis] = calculateMajorAxisRequirements(axis, + requirements[axis]); + else + requirements[axis] = calculateMinorAxisRequirements(axis, + requirements[axis]); + } + } } diff --git a/javax/swing/text/ComponentView.java b/javax/swing/text/ComponentView.java index 2846f8b53..a7d237ab7 100644 --- a/javax/swing/text/ComponentView.java +++ b/javax/swing/text/ComponentView.java @@ -228,8 +228,9 @@ public class ComponentView extends View * * @param p the parent view to set */ - void setParentImpl(View p) + private void setParentImpl(View p) { + super.setParent(p); if (p != null) { Component c = getComponent(); diff --git a/javax/swing/text/CompositeView.java b/javax/swing/text/CompositeView.java index cd6645215..49abbb2c8 100644 --- a/javax/swing/text/CompositeView.java +++ b/javax/swing/text/CompositeView.java @@ -218,20 +218,43 @@ public abstract class CompositeView throws BadLocationException { int childIndex = getViewIndex(pos, bias); + Shape ret = null; if (childIndex != -1) { View child = getView(childIndex); - Rectangle r = a.getBounds(); - childAllocation(childIndex, r); - Shape result = child.modelToView(pos, r, bias); - if (result == null) - throw new AssertionError("" + child.getClass().getName() - + ".modelToView() must not return null"); - return result; + Shape childAlloc = getChildAllocation(childIndex, a); + if (childAlloc == null) + ret = createDefaultLocation(a, bias); + Shape result = child.modelToView(pos, childAlloc, bias); + if (result != null) + ret = result; + else + ret = createDefaultLocation(a, bias); } else - throw new BadLocationException("No child view for the specified location", - pos); + ret = createDefaultLocation(a, bias); + return ret; + } + + /** + * A helper method for {@link #modelToView(int, Position.Bias, int, + * Position.Bias, Shape)}. This creates a default location when there is + * no child view that can take responsibility for mapping the position to + * view coordinates. Depending on the specified bias this will be the + * left or right edge of this view's allocation. + * + * @param a the allocation for this view + * @param bias the bias + * + * @return a default location + */ + private Shape createDefaultLocation(Shape a, Position.Bias bias) + { + Rectangle alloc = a.getBounds(); + Rectangle location = new Rectangle(alloc.x, alloc.y, 1, alloc.height); + if (bias == Position.Bias.Forward) + location.x = alloc.x + alloc.width; + return location; } /** diff --git a/javax/swing/text/DefaultCaret.java b/javax/swing/text/DefaultCaret.java index 45bb33e60..5a5bb429e 100644 --- a/javax/swing/text/DefaultCaret.java +++ b/javax/swing/text/DefaultCaret.java @@ -148,14 +148,16 @@ public class DefaultCaret extends Rectangle */ public void removeUpdate(DocumentEvent event) { - if (policy == ALWAYS_UPDATE || - (SwingUtilities.isEventDispatchThread() && - policy == UPDATE_WHEN_ON_EDT)) + if (policy == ALWAYS_UPDATE + || (SwingUtilities.isEventDispatchThread() + && policy == UPDATE_WHEN_ON_EDT)) { int dot = getDot(); setDot(dot - event.getLength()); } - else if (policy == NEVER_UPDATE) + else if (policy == NEVER_UPDATE + || (! SwingUtilities.isEventDispatchThread() + && policy == UPDATE_WHEN_ON_EDT)) { int docLength = event.getDocument().getLength(); if (getDot() > docLength) @@ -575,6 +577,38 @@ public class DefaultCaret extends Rectangle { return mark; } + + private void clearHighlight() + { + Highlighter highlighter = textComponent.getHighlighter(); + + if (highlighter == null) + return; + + if (selectionVisible) + { + try + { + if (highlightEntry == null) + highlightEntry = highlighter.addHighlight(0, 0, getSelectionPainter()); + else + highlighter.changeHighlight(highlightEntry, 0, 0); + } + catch (BadLocationException e) + { + // This should never happen. + throw new InternalError(); + } + } + else + { + if (highlightEntry != null) + { + highlighter.removeHighlight(highlightEntry); + highlightEntry = null; + } + } + } private void handleHighlight() { @@ -586,7 +620,7 @@ public class DefaultCaret extends Rectangle int p0 = Math.min(dot, mark); int p1 = Math.max(dot, mark); - if (selectionVisible && p0 != p1) + if (selectionVisible) { try { @@ -812,7 +846,11 @@ public class DefaultCaret extends Rectangle { if (dot >= 0) { - this.dot = dot; + Document doc = textComponent.getDocument(); + if (doc != null) + this.dot = Math.min(dot, doc.getLength()); + this.dot = Math.max(this.dot, 0); + handleHighlight(); adjustVisibility(this); appear(); @@ -836,8 +874,9 @@ public class DefaultCaret extends Rectangle if (doc != null) this.dot = Math.min(dot, doc.getLength()); this.dot = Math.max(this.dot, 0); - this.mark = dot; - handleHighlight(); + this.mark = this.dot; + + clearHighlight(); adjustVisibility(this); appear(); } diff --git a/javax/swing/text/DefaultEditorKit.java b/javax/swing/text/DefaultEditorKit.java index 88094b898..c0056963c 100644 --- a/javax/swing/text/DefaultEditorKit.java +++ b/javax/swing/text/DefaultEditorKit.java @@ -707,16 +707,14 @@ public class DefaultEditorKit extends EditorKit JTextComponent t = getTextComponent(event); try { - // TODO: There is a more efficent solution, but - // viewToModel doesn't work properly. - Point p = t.modelToView(t.getCaret().getDot()).getLocation(); - int cur = t.getCaretPosition(); - int y = p.y; - while (y == p.y && cur > 0) - y = t.modelToView(--cur).getLocation().y; - if (cur != 0) - cur++; - t.setCaretPosition(cur); + int offs = Utilities.getRowStart(t, t.getCaretPosition()); + + if (offs > -1) + { + Caret c = t.getCaret(); + c.setDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } } catch (BadLocationException ble) { @@ -729,17 +727,16 @@ public class DefaultEditorKit extends EditorKit public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); - try + try { - Point p = t.modelToView(t.getCaret().getDot()).getLocation(); - int cur = t.getCaretPosition(); - int y = p.y; - int length = t.getDocument().getLength(); - while (y == p.y && cur < length) - y = t.modelToView(++cur).getLocation().y; - if (cur != length) - cur--; - t.setCaretPosition(cur); + int offs = Utilities.getRowEnd(t, t.getCaretPosition()); + + if (offs > -1) + { + Caret c = t.getCaret(); + c.setDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } } catch (BadLocationException ble) { @@ -756,11 +753,17 @@ public class DefaultEditorKit extends EditorKit { try { - int pos = t.getCaret().getDot(); - if (pos < t.getDocument().getEndPosition().getOffset()) - { - t.getDocument().remove(t.getCaret().getDot(), 1); - } + int pos = t.getSelectionStart(); + int len = t.getSelectionEnd() - pos; + + if (len > 0) + t.getDocument().remove(pos, len); + else if (pos < t.getDocument().getLength()) + t.getDocument().remove(pos, 1); + + Caret c = t.getCaret(); + c.setDot(pos); + c.setMagicCaretPosition(t.modelToView(pos).getLocation()); } catch (BadLocationException e) { @@ -778,11 +781,18 @@ public class DefaultEditorKit extends EditorKit { try { - int pos = t.getCaret().getDot(); - if (pos > t.getDocument().getStartPosition().getOffset()) + int pos = t.getSelectionStart(); + int len = t.getSelectionEnd() - pos; + + if (len > 0) + t.getDocument().remove(pos, len); + else if (pos > 0) { - t.getDocument().remove(pos - 1, 1); - t.getCaret().setDot(pos - 1); + pos--; + t.getDocument().remove(pos, 1); + Caret c = t.getCaret(); + c.setDot(pos); + c.setMagicCaretPosition(t.modelToView(pos).getLocation()); } } catch (BadLocationException e) @@ -799,8 +809,21 @@ public class DefaultEditorKit extends EditorKit JTextComponent t = getTextComponent(event); if (t != null) { - t.getCaret().setDot(Math.max(t.getCaret().getDot() - 1, - t.getDocument().getStartPosition().getOffset())); + int offs = t.getCaretPosition() - 1; + if (offs >= 0) + { + Caret c = t.getCaret(); + c.setDot(offs); + + try + { + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch (BadLocationException ble) + { + // Should not happen. + } + } } } }, @@ -811,8 +834,74 @@ public class DefaultEditorKit extends EditorKit JTextComponent t = getTextComponent(event); if (t != null) { - t.getCaret().setDot(Math.min(t.getCaret().getDot() + 1, - t.getDocument().getEndPosition().getOffset())); + int offs = t.getCaretPosition() + 1; + if (offs <= t.getDocument().getLength()) + { + Caret c = t.getCaret(); + c.setDot(offs); + + try + { + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch (BadLocationException ble) + { + // Should not happen. + } + } + } + + } + }, + new TextAction(upAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + if (t != null) + { + Caret c = t.getCaret(); + // The magic caret position may be null when the caret + // has not moved yet. + Point mcp = c.getMagicCaretPosition(); + int x = (mcp != null) ? mcp.x : 0; + int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x); + + if (pos > -1) + t.setCaretPosition(pos); + } + } + catch(BadLocationException ble) + { + // FIXME: Swallowing allowed? + } + } + }, + new TextAction(downAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + if (t != null) + { + Caret c = t.getCaret(); + // The magic caret position may be null when the caret + // has not moved yet. + Point mcp = c.getMagicCaretPosition(); + int x = (mcp != null) ? mcp.x : 0; + int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x); + + if (pos > -1) + t.setCaretPosition(pos); + } + } + catch(BadLocationException ble) + { + // FIXME: Swallowing allowed? } } }, @@ -823,8 +912,21 @@ public class DefaultEditorKit extends EditorKit JTextComponent t = getTextComponent(event); if (t != null) { - t.getCaret().moveDot(Math.max(t.getCaret().getDot() - 1, - t.getDocument().getStartPosition().getOffset())); + int offs = t.getCaretPosition() - 1; + + if(offs >= 0) + { + Caret c = t.getCaret(); + c.moveDot(offs); + try + { + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } } } }, @@ -835,11 +937,167 @@ public class DefaultEditorKit extends EditorKit JTextComponent t = getTextComponent(event); if (t != null) { - t.getCaret().moveDot(Math.min(t.getCaret().getDot() + 1, - t.getDocument().getEndPosition().getOffset())); + int offs = t.getCaretPosition() + 1; + + if(offs <= t.getDocument().getLength()) + { + Caret c = t.getCaret(); + c.moveDot(offs); + try + { + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + } + }, + new TextAction(selectionUpAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + if (t != null) + { + Caret c = t.getCaret(); + // The magic caret position may be null when the caret + // has not moved yet. + Point mcp = c.getMagicCaretPosition(); + int x = (mcp != null) ? mcp.x : 0; + int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x); + + if (pos > -1) + t.moveCaretPosition(pos); + } + } + catch(BadLocationException ble) + { + // FIXME: Swallowing allowed? + } + } + }, + new TextAction(selectionDownAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + if (t != null) + { + Caret c = t.getCaret(); + // The magic caret position may be null when the caret + // has not moved yet. + Point mcp = c.getMagicCaretPosition(); + int x = (mcp != null) ? mcp.x : 0; + int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x); + + if (pos > -1) + t.moveCaretPosition(pos); + } + } + catch(BadLocationException ble) + { + // FIXME: Swallowing allowed? } } }, + new TextAction(selectionBeginLineAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + + try + { + // TODO: There is a more efficent solution, but + // viewToModel doesn't work properly. + Point p = t.modelToView(t.getCaret().getDot()).getLocation(); + + int cur = t.getCaretPosition(); + int y = p.y; + + while (y == p.y && cur > 0) + y = t.modelToView(--cur).getLocation().y; + if (cur != 0) + cur++; + + Caret c = t.getCaret(); + c.moveDot(cur); + c.setMagicCaretPosition(t.modelToView(cur).getLocation()); + } + catch (BadLocationException ble) + { + // Do nothing here. + } + } + }, + new TextAction(selectionEndLineAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + Point p = t.modelToView(t.getCaret().getDot()).getLocation(); + int cur = t.getCaretPosition(); + int y = p.y; + int length = t.getDocument().getLength(); + while (y == p.y && cur < length) + y = t.modelToView(++cur).getLocation().y; + if (cur != length) + cur--; + + Caret c = t.getCaret(); + c.moveDot(cur); + c.setMagicCaretPosition(t.modelToView(cur).getLocation()); + } + catch (BadLocationException ble) + { + // Nothing to do here + } + } + }, + new TextAction(selectionEndAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + int offs = t.getDocument().getLength(); + Caret c = t.getCaret(); + c.moveDot(offs); + try + { + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + }, + new TextAction(selectionBeginAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + Caret c = t.getCaret(); + c.moveDot(0); + try + { + c.setMagicCaretPosition(t.modelToView(0).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } }; /** diff --git a/javax/swing/text/DefaultFormatter.java b/javax/swing/text/DefaultFormatter.java index dfeac12b7..ec8969615 100644 --- a/javax/swing/text/DefaultFormatter.java +++ b/javax/swing/text/DefaultFormatter.java @@ -219,7 +219,6 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter commitsOnValidEdit = true; overwriteMode = true; allowsInvalid = true; - valueClass = Object.class; } /** diff --git a/javax/swing/text/DefaultHighlighter.java b/javax/swing/text/DefaultHighlighter.java index 40ea4f80a..33b5fcab8 100644 --- a/javax/swing/text/DefaultHighlighter.java +++ b/javax/swing/text/DefaultHighlighter.java @@ -1,5 +1,5 @@ /* DefaultHighlighter.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,9 +40,12 @@ package javax.swing.text; import java.awt.Color; import java.awt.Graphics; +import java.awt.Insets; import java.awt.Rectangle; import java.awt.Shape; -import java.util.Vector; +import java.util.ArrayList; + +import javax.swing.plaf.TextUI; public class DefaultHighlighter extends LayeredHighlighter { @@ -84,7 +87,7 @@ public class DefaultHighlighter extends LayeredHighlighter // This should never occur. return; } - + if (r0 == null || r1 == null) return; @@ -100,7 +103,7 @@ public class DefaultHighlighter extends LayeredHighlighter paintHighlight(g, r0); return; } - + // First line, from p0 to end-of-line. r0.width = rect.x + rect.width - r0.x; paintHighlight(g, r0); @@ -109,15 +112,19 @@ public class DefaultHighlighter extends LayeredHighlighter // have the same height -- not a good assumption with JEditorPane/JTextPane). r0.y += r0.height; r0.x = rect.x; - + r0.width = rect.width; + while (r0.y < r1.y) { paintHighlight(g, r0); r0.y += r0.height; } - // Last line, from beginnin-of-line to p1. - paintHighlight(g, r1); + // Last line, from beginning-of-line to p1. + // The "-1" is neccessary else we would paint one pixel column more + // than in the case where the selection is only on one line. + r0.width = r1.x + r1.width - 1; + paintHighlight(g, r0); } public Shape paintLayer(Graphics g, int p0, int p1, Shape bounds, @@ -127,7 +134,7 @@ public class DefaultHighlighter extends LayeredHighlighter } } - private class HighlightEntry + private class HighlightEntry implements Highlighter.Highlight { int p0; int p1; @@ -140,12 +147,12 @@ public class DefaultHighlighter extends LayeredHighlighter this.painter = painter; } - public int getStartPosition() + public int getStartOffset() { return p0; } - public int getEndPosition() + public int getEndOffset() { return p1; } @@ -163,7 +170,7 @@ public class DefaultHighlighter extends LayeredHighlighter new DefaultHighlightPainter(null); private JTextComponent textComponent; - private Vector highlights = new Vector(); + private ArrayList highlights = new ArrayList(); private boolean drawsLayeredHighlights = true; public DefaultHighlighter() @@ -208,12 +215,20 @@ public class DefaultHighlighter extends LayeredHighlighter checkPositions(p0, p1); HighlightEntry entry = new HighlightEntry(p0, p1, painter); highlights.add(entry); + + textComponent.getUI().damageRange(textComponent, p0, p1); + return entry; } public void removeHighlight(Object tag) { highlights.remove(tag); + + HighlightEntry entry = (HighlightEntry) tag; + textComponent.getUI().damageRange(textComponent, + entry.p0, + entry.p1); } public void removeAllHighlights() @@ -223,16 +238,93 @@ public class DefaultHighlighter extends LayeredHighlighter public Highlighter.Highlight[] getHighlights() { - return null; + return (Highlighter.Highlight[]) + highlights.toArray(new Highlighter.Highlight[highlights.size()]); } - public void changeHighlight(Object tag, int p0, int p1) + public void changeHighlight(Object tag, int n0, int n1) throws BadLocationException { - checkPositions(p0, p1); + int o0, o1; + + checkPositions(n0, n1); HighlightEntry entry = (HighlightEntry) tag; - entry.p0 = p0; - entry.p1 = p1; + o0 = entry.p0; + o1 = entry.p1; + + // Prevent useless write & repaint operations. + if (o0 == n0 && o1 == n1) + return; + + entry.p0 = n0; + entry.p1 = n1; + + TextUI ui = textComponent.getUI(); + + // Special situation where the old area has to be cleared simply. + if (n0 == n1) + ui.damageRange(textComponent, o0, o1); + // Calculates the areas where a change is really neccessary + else if ((o1 > n0 && o1 <= n1) + || (n1 > o0 && n1 <= o1)) + { + // [fds, fde) - the first damage region + // [sds, sde] - the second damage region + int fds, sds; + int fde, sde; + + // Calculate first damaged region. + if(o0 < n0) + { + // Damaged region will be cleared as + // the old highlight region starts first. + fds = o0; + fde = n0; + } + else + { + // Damaged region will be painted as + // the new highlight region starts first. + fds = n0; + fde = o0; + } + + if (o1 < n1) + { + // Final region will be painted as the + // old highlight region finishes first + sds = o1; + sde = n1; + } + else + { + // Final region will be cleared as the + // new highlight region finishes first. + sds = n1; + sde = o1; + } + + // If there is no undamaged region in between + // call damageRange only once. + if (fde == sds) + ui.damageRange(textComponent, fds, sde); + else + { + if (fds != fde) + ui.damageRange(textComponent, fds, fde); + + if (sds != sde) + ui.damageRange(textComponent, sds, sde); + } + } + else + { + // The two regions do not overlap. So mark + // both areas as damaged. + ui.damageRange(textComponent, o0, o1); + ui.damageRange(textComponent, n0, n1); + } + } public void paintLayeredHighlights(Graphics g, int p0, int p1, @@ -244,13 +336,21 @@ public class DefaultHighlighter extends LayeredHighlighter public void paint(Graphics g) { + int size = highlights.size(); + // Check if there are any highlights. - if (highlights.size() == 0) + if (size == 0) return; + + // Prepares the rectangle of the inner drawing area. + Insets insets = textComponent.getInsets(); + Shape bounds = + new Rectangle(insets.left, + insets.top, + textComponent.getWidth() - insets.left - insets.right, + textComponent.getHeight() - insets.top - insets.bottom); - Shape bounds = textComponent.getBounds(); - - for (int index = 0; index < highlights.size(); ++index) + for (int index = 0; index < size; ++index) { HighlightEntry entry = (HighlightEntry) highlights.get(index); entry.painter.paint(g, entry.p0, entry.p1, bounds, textComponent); diff --git a/javax/swing/text/DefaultStyledDocument.java b/javax/swing/text/DefaultStyledDocument.java index bc459b5d4..e774b4e07 100644 --- a/javax/swing/text/DefaultStyledDocument.java +++ b/javax/swing/text/DefaultStyledDocument.java @@ -53,27 +53,25 @@ import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.UndoableEdit; /** - * The default implementation of {@link StyledDocument}. - * - * The document is modeled as an {@link Element} tree, which has - * a {@link SectionElement} as single root, which has one or more - * {@link AbstractDocument.BranchElement}s as paragraph nodes - * and each paragraph node having one or more + * The default implementation of {@link StyledDocument}. The document is + * modeled as an {@link Element} tree, which has a {@link SectionElement} as + * single root, which has one or more {@link AbstractDocument.BranchElement}s + * as paragraph nodes and each paragraph node having one or more * {@link AbstractDocument.LeafElement}s as content nodes. - * + * * @author Michael Koch (konqueror@gmx.de) * @author Roman Kennke (roman@kennke.org) */ -public class DefaultStyledDocument extends AbstractDocument - implements StyledDocument +public class DefaultStyledDocument extends AbstractDocument implements + StyledDocument { + /** * An {@link UndoableEdit} that can undo attribute changes to an element. - * + * * @author Roman Kennke (kennke@aicas.com) */ - public static class AttributeUndoableEdit - extends AbstractUndoableEdit + public static class AttributeUndoableEdit extends AbstractUndoableEdit { /** * A copy of the old attributes. @@ -98,11 +96,13 @@ public class DefaultStyledDocument extends AbstractDocument /** * Creates a new AttributeUndoableEdit. - * - * @param el the element that changes attributes - * @param newAtts the new attributes - * @param replacing if the new attributes replace the old or only append to - * them + * + * @param el + * the element that changes attributes + * @param newAtts + * the new attributes + * @param replacing + * if the new attributes replace the old or only append to them */ public AttributeUndoableEdit(Element el, AttributeSet newAtts, boolean replacing) @@ -149,21 +149,19 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Carries specification information for new {@link Element}s that should - * be created in {@link ElementBuffer}. This allows the parsing process - * to be decoupled from the Element creation process. + * Carries specification information for new {@link Element}s that should be + * created in {@link ElementBuffer}. This allows the parsing process to be + * decoupled from the Element creation process. */ public static class ElementSpec { /** - * This indicates a start tag. This is a possible value for - * {@link #getType}. + * This indicates a start tag. This is a possible value for {@link #getType}. */ public static final short StartTagType = 1; /** - * This indicates an end tag. This is a possible value for - * {@link #getType}. + * This indicates an end tag. This is a possible value for {@link #getType}. */ public static final short EndTagType = 2; @@ -175,22 +173,19 @@ public class DefaultStyledDocument extends AbstractDocument /** * This indicates that the data associated with this spec should be joined - * with what precedes it. This is a possible value for - * {@link #getDirection}. + * with what precedes it. This is a possible value for {@link #getDirection}. */ public static final short JoinPreviousDirection = 4; /** * This indicates that the data associated with this spec should be joined - * with what follows it. This is a possible value for - * {@link #getDirection}. + * with what follows it. This is a possible value for {@link #getDirection}. */ public static final short JoinNextDirection = 5; /** - * This indicates that the data associated with this spec should be used - * to create a new element. This is a possible value for - * {@link #getDirection}. + * This indicates that the data associated with this spec should be used to + * create a new element. This is a possible value for {@link #getDirection}. */ public static final short OriginateDirection = 6; @@ -234,9 +229,11 @@ public class DefaultStyledDocument extends AbstractDocument /** * Creates a new ElementSpec with no content, length or * offset. This is most useful for start and end tags. - * - * @param a the attributes for the element to be created - * @param type the type of the tag + * + * @param a + * the attributes for the element to be created + * @param type + * the type of the tag */ public ElementSpec(AttributeSet a, short type) { @@ -247,27 +244,34 @@ public class DefaultStyledDocument extends AbstractDocument * Creates a new ElementSpec that specifies the length but * not the offset of an element. Such ElementSpecs are * processed sequentially from a known starting point. - * - * @param a the attributes for the element to be created - * @param type the type of the tag - * @param len the length of the element + * + * @param a + * the attributes for the element to be created + * @param type + * the type of the tag + * @param len + * the length of the element */ public ElementSpec(AttributeSet a, short type, int len) { this(a, type, null, 0, len); } - + /** * Creates a new ElementSpec with document content. - * - * @param a the attributes for the element to be created - * @param type the type of the tag - * @param txt the actual content - * @param offs the offset into the txt array - * @param len the length of the element + * + * @param a + * the attributes for the element to be created + * @param type + * the type of the tag + * @param txt + * the actual content + * @param offs + * the offset into the txt array + * @param len + * the length of the element */ - public ElementSpec(AttributeSet a, short type, char[] txt, int offs, - int len) + public ElementSpec(AttributeSet a, short type, char[] txt, int offs, int len) { attributes = a; this.type = type; @@ -279,8 +283,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Sets the type of the element. - * - * @param type the type of the element to be set + * + * @param type + * the type of the element to be set */ public void setType(short type) { @@ -289,7 +294,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the type of the element. - * + * * @return the type of the element */ public short getType() @@ -299,8 +304,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Sets the direction of the element. - * - * @param dir the direction of the element to be set + * + * @param dir + * the direction of the element to be set */ public void setDirection(short dir) { @@ -309,7 +315,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the direction of the element. - * + * * @return the direction of the element */ public short getDirection() @@ -319,7 +325,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the attributes of the element. - * + * * @return the attributes of the element */ public AttributeSet getAttributes() @@ -329,7 +335,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the actual content of the element. - * + * * @return the actual content of the element */ public char[] getArray() @@ -339,7 +345,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the offset of the content. - * + * * @return the offset of the content */ public int getOffset() @@ -349,7 +355,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the length of the content. - * + * * @return the length of the content */ public int getLength() @@ -413,7 +419,8 @@ public class DefaultStyledDocument extends AbstractDocument /** * Performs all structural
      changes to the Element - * hierarchy. + * hierarchy. This class was implemented with much help from the document: + * http://java.sun.com/products/jfc/tsc/articles/text/element_buffer/index.html. */ public class ElementBuffer implements Serializable { @@ -426,25 +433,20 @@ public class DefaultStyledDocument extends AbstractDocument /** Holds the offset for structural changes. */ private int offset; + /** Holds the end offset for structural changes. */ + private int endOffset; + /** Holds the length of structural changes. */ private int length; - - /** Holds the end offset for structural changes. **/ - private int endOffset; - /** - * The number of inserted end tags. This is a counter which always gets - * incremented when an end tag is inserted. This is evaluated before - * content insertion to go up the element stack. - */ - private int numEndTags; + /** Holds the position of the change. */ + private int pos; - /** - * The number of inserted start tags. This is a counter which always gets - * incremented when an end tag is inserted. This is evaluated before - * content insertion to go up the element stack. - */ - private int numStartTags; + /** Holds the element that was last fractured. */ + private Element lastFractured; + + /** True if a fracture was not created during a insertFracture call. */ + private boolean fracNotCreated; /** * The current position in the element tree. This is used for bulk inserts @@ -452,14 +454,6 @@ public class DefaultStyledDocument extends AbstractDocument */ private Stack elementStack; - /** - * Holds fractured elements during insertion of end and start tags. - * Inserting an end tag may lead to fracturing of the current paragraph - * element. The elements that have been cut off may be added to the - * next paragraph that is created in the next start tag. - */ - Element[] fracture; - /** * The ElementChange that describes the latest changes. */ @@ -468,8 +462,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Creates a new ElementBuffer for the specified * root element. - * - * @param root the root element for this ElementBuffer + * + * @param root + * the root element for this ElementBuffer */ public ElementBuffer(Element root) { @@ -479,7 +474,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the root element of this ElementBuffer. - * + * * @return the root element of this ElementBuffer */ public Element getRootElement() @@ -488,21 +483,23 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Updates the element structure of the document in response to removal of - * content. It removes the affected {@link Element}s from the document - * structure. - * - * This method sets some internal parameters and delegates the work - * to {@link #removeUpdate}. - * - * @param offs the offset from which content is remove - * @param len the length of the removed content - * @param ev the document event that records the changes + * Removes the content. This method sets some internal parameters and + * delegates the work to {@link #removeUpdate}. + * + * @param offs + * the offset from which content is remove + * @param len + * the length of the removed content + * @param ev + * the document event that records the changes */ public void remove(int offs, int len, DefaultDocumentEvent ev) { + if (len == 0) + return; offset = offs; length = len; + pos = offset; documentEvent = ev; removeUpdate(); } @@ -519,9 +516,9 @@ public class DefaultStyledDocument extends AbstractDocument Element[] empty = new Element[0]; int removeStart = -1; int removeEnd = -1; - for (int i = startParagraph; i < endParagraph; i++) + for (int i = startParagraph; i < endParagraph; i++) { - Element paragraph = root.getElement(i); + BranchElement paragraph = (BranchElement) root.getElement(i); int contentStart = paragraph.getElementIndex(offset); int contentEnd = paragraph.getElementIndex(offset + length); if (contentStart == paragraph.getStartOffset() @@ -546,10 +543,8 @@ public class DefaultStyledDocument extends AbstractDocument Element[] removed = new Element[removeLen]; for (int j = contentStart; j < contentEnd; j++) removed[j] = paragraph.getElement(j); - ((BranchElement) paragraph).replace(contentStart, removeLen, - empty); - documentEvent.addEdit(new ElementEdit(paragraph, contentStart, - removed, empty)); + Edit edit = getEditForParagraphAndIndex(paragraph, contentStart); + edit.addRemovedElements(removed); } } // Now we remove paragraphs from the root that have been tagged for @@ -560,265 +555,235 @@ public class DefaultStyledDocument extends AbstractDocument Element[] removed = new Element[removeLen]; for (int i = removeStart; i < removeEnd; i++) removed[i] = root.getElement(i); - ((BranchElement) root).replace(removeStart, removeLen, empty); - documentEvent.addEdit(new ElementEdit(root, removeStart, removed, - empty)); + Edit edit = getEditForParagraphAndIndex((BranchElement) root, + removeStart); + edit.addRemovedElements(removed); } } /** - * Modifies the element structure so that the specified interval starts - * and ends at an element boundary. Content and paragraph elements - * are split and created as necessary. - * - * This also updates the DefaultDocumentEvent to reflect the - * structural changes. - * - * The bulk work is delegated to {@link #changeUpdate()}. - * - * @param offset the start index of the interval to be changed - * @param length the length of the interval to be changed - * @param ev the DefaultDocumentEvent describing the change - */ - public void change(int offset, int length, DefaultDocumentEvent ev) - { - this.offset = offset; - this.length = length; - documentEvent = ev; - changeUpdate(); - } - - /** - * Performs the actual work for {@link #change}. - * The elements at the interval boundaries are split up (if necessary) - * so that the interval boundaries are located at element boundaries. + * Performs the actual work for {@link #change}. The elements at the + * interval boundaries are split up (if necessary) so that the interval + * boundaries are located at element boundaries. */ protected void changeUpdate() { // Split up the element at the start offset if necessary. Element el = getCharacterElement(offset); - Element[] res = split(el, offset, 0); + Element[] res = split(el, offset, 0, el.getElementIndex(offset)); BranchElement par = (BranchElement) el.getParentElement(); + int index = par.getElementIndex(offset); + Edit edit = getEditForParagraphAndIndex(par, index); if (res[1] != null) { - int index = par.getElementIndex(offset); Element[] removed; Element[] added; if (res[0] == null) { removed = new Element[0]; - added = new Element[]{ res[1] }; + added = new Element[] { res[1] }; index++; } else { - removed = new Element[]{ el }; - added = new Element[]{ res[0], res[1] }; + removed = new Element[] { el }; + added = new Element[] { res[0], res[1] }; } - par.replace(index, removed.length, added); - addEdit(par, index, removed, added); + edit.addRemovedElements(removed); + + edit.addAddedElements(added); } int endOffset = offset + length; el = getCharacterElement(endOffset); - res = split(el, endOffset, 0); + res = split(el, endOffset, 0, el.getElementIndex(endOffset)); par = (BranchElement) el.getParentElement(); - if (res[1] != null) + if (res[0] != null) { - int index = par.getElementIndex(offset); Element[] removed; Element[] added; if (res[1] == null) { removed = new Element[0]; - added = new Element[]{ res[1] }; + added = new Element[] { res[1] }; } else { - removed = new Element[]{ el }; - added = new Element[]{ res[0], res[1] }; + removed = new Element[] { el }; + added = new Element[] { res[0], res[1] }; } - par.replace(index, removed.length, added); - addEdit(par, index, removed, added); + edit.addRemovedElements(removed); + edit.addAddedElements(added); } } /** - * Splits an element if offset is not alread at its boundary. + * Modifies the element structure so that the specified interval starts and + * ends at an element boundary. Content and paragraph elements are split and + * created as necessary. This also updates the + * DefaultDocumentEvent to reflect the structural changes. + * The bulk work is delegated to {@link #changeUpdate()}. + * + * @param offset + * the start index of the interval to be changed + * @param length + * the length of the interval to be changed + * @param ev + * the DefaultDocumentEvent describing the change + */ + public void change(int offset, int length, DefaultDocumentEvent ev) + { + if (length == 0) + return; + this.offset = offset; + this.pos = offset; + this.length = length; + documentEvent = ev; + changeUpdate(); + } + + /** + * Creates and returns a deep clone of the specified clonee + * with the specified parent as new parent. * - * @param el the Element to possibly split - * @param offset the offset at which to possibly split - * @param space the amount of space to create between the splitted parts + * This method can only clone direct instances of {@link BranchElement} + * or {@link LeafElement}. * - * @return An array of elements which represent the split result. This - * array has two elements, the two parts of the split. The first - * element might be null, which means that the element which should - * be splitted can remain in place. The second element might also - * be null, which means that the offset is already at an element - * boundary and the element doesn't need to be splitted. - * + * @param parent the new parent + * @param clonee the element to be cloned + * + * @return the cloned element with the new parent */ - private Element[] split(Element el, int offset, int space) + public Element clone(Element parent, Element clonee) { - // If we are at an element boundary, then return an empty array. - if ((offset == el.getStartOffset() || offset == el.getEndOffset()) - && space == 0 && el.isLeaf()) - return new Element[2]; - - // If the element is an instance of BranchElement, then we recursivly - // call this method to perform the split. - Element[] res = new Element[2]; - if (el instanceof BranchElement) + Element clone = clonee; + // We can only handle AbstractElements here. + if (clonee instanceof BranchElement) { - int index = el.getElementIndex(offset); - Element child = el.getElement(index); - Element[] result = split(child, offset, space); - Element[] removed; - Element[] added; - Element[] newAdded; - - int count = el.getElementCount(); - if (!(result[1] == null)) - { - // This is the case when we can keep the first element. - if (result[0] == null) - { - removed = new Element[count - index - 1]; - newAdded = new Element[count - index - 1]; - added = new Element[]{}; - } - // This is the case when we may not keep the first element. - else - { - removed = new Element[count - index]; - newAdded = new Element[count - index]; - added = new Element[]{result[0]}; - } - newAdded[0] = result[1]; - for (int i = index; i < count; i++) - { - Element el2 = el.getElement(i); - int ind = i - count + removed.length; - removed[ind] = el2; - if (ind != 0) - newAdded[ind] = el2; - } - - ((BranchElement) el).replace(index, removed.length, added); - addEdit(el, index, removed, added); - BranchElement newPar = - (BranchElement) createBranchElement(el.getParentElement(), - el.getAttributes()); - newPar.replace(0, 0, newAdded); - res = new Element[]{ null, newPar }; - } - else + BranchElement branchEl = (BranchElement) clonee; + BranchElement branchClone = + new BranchElement(parent, branchEl.getAttributes()); + // Also clone all of the children. + int numChildren = branchClone.getElementCount(); + Element[] cloneChildren = new Element[numChildren]; + for (int i = 0; i < numChildren; ++i) { - removed = new Element[count - index]; - for (int i = index; i < count; ++i) - removed[i - index] = el.getElement(i); - added = new Element[0]; - ((BranchElement) el).replace(index, removed.length, - added); - addEdit(el, index, removed, added); - BranchElement newPar = - (BranchElement) createBranchElement(el.getParentElement(), - el.getAttributes()); - newPar.replace(0, 0, removed); - res = new Element[]{ null, newPar }; + cloneChildren[i] = clone(branchClone, + branchClone.getElement(i)); } + branchClone.replace(0, 0, cloneChildren); + clone = branchClone; } - else if (el instanceof LeafElement) + else if (clonee instanceof LeafElement) { - BranchElement par = (BranchElement) el.getParentElement(); - Element el1 = createLeafElement(par, el.getAttributes(), - el.getStartOffset(), offset); - Element el2 = createLeafElement(par, el.getAttributes(), - offset + space, el.getEndOffset()); - res = new Element[]{ el1, el2 }; + clone = new LeafElement(parent, clonee.getAttributes(), + clonee.getStartOffset(), + clonee.getEndOffset()); } - return res; + return clone; } /** * Inserts new Element in the document at the specified - * position. - * - * Most of the work is done by {@link #insertUpdate}, after some fields - * have been prepared for it. - * - * @param offset the location in the document at which the content is - * inserted - * @param length the length of the inserted content - * @param data the element specifications for the content to be inserted - * @param ev the document event that is updated to reflect the structural - * changes + * position. Most of the work is done by {@link #insertUpdate}, after some + * fields have been prepared for it. + * + * @param offset + * the location in the document at which the content is inserted + * @param length + * the length of the inserted content + * @param data + * the element specifications for the content to be inserted + * @param ev + * the document event that is updated to reflect the structural + * changes */ public void insert(int offset, int length, ElementSpec[] data, DefaultDocumentEvent ev) { if (length == 0) return; + this.offset = offset; - this.length = length; + this.pos = offset; this.endOffset = offset + length; + this.length = length; documentEvent = ev; - // Push the root and the paragraph at offset onto the element stack. - elementStack.clear(); - elementStack.push(root); - elementStack.push(root.getElement(root.getElementIndex(offset))); - numEndTags = 0; - numStartTags = 0; + + edits.removeAllElements(); + elementStack.removeAllElements(); + lastFractured = null; + fracNotCreated = false; insertUpdate(data); + + // This for loop applies all the changes that were made and updates the + // DocumentEvent. + int size = edits.size(); + for (int i = 0; i < size; i++) + { + Edit curr = (Edit) edits.get(i); + BranchElement e = (BranchElement) curr.e; + Element[] removed = curr.getRemovedElements(); + Element[] added = curr.getAddedElements(); + // FIXME: We probably shouldn't create the empty Element[] in the + // first place. + if (removed.length > 0 || added.length > 0) + { + if (curr.index + removed.length <= e.getElementCount()) + { + e.replace(curr.index, removed.length, added); + ElementEdit ee = new ElementEdit(e, curr.index, removed, added); + ev.addEdit(ee); + } + else + { + System.err.println("WARNING: Tried to replace elements "); + System.err.print("beyond boundaries: elementCount: "); + System.err.println(e.getElementCount()); + System.err.print("index: " + curr.index); + System.err.println(", removed.length: " + removed.length); + } + } + } } /** - * Performs the actual structural change for {@link #insert}. This - * creates a bunch of {@link Element}s as specified by data - * and inserts it into the document as specified in the arguments to - * {@link #insert}. - * - * @param data the element specifications for the elements to be inserte - */ + * Inserts new content + * + * @param data + * the element specifications for the elements to be inserted + */ protected void insertUpdate(ElementSpec[] data) { - if (data[0].getType() == ElementSpec.EndTagType) + // Push the root and the paragraph at offset onto the element stack. + Element current = root; + int index; + while (!current.isLeaf()) { - // fracture deepest child here - BranchElement paragraph = (BranchElement) elementStack.peek(); - Element curr = paragraph.getParentElement(); - int index = curr.getElementIndex(offset); - while (!curr.isLeaf()) - { - index = curr.getElementIndex(offset); - curr = curr.getElement(index); - } - Element parent = curr.getParentElement(); - Element newEl1 = createLeafElement(parent, - curr.getAttributes(), - curr.getStartOffset(), offset); - Element grandParent = parent.getParentElement(); - BranchElement nextBranch = - (BranchElement) grandParent.getElement - (grandParent.getElementIndex(parent.getEndOffset())); - Element firstLeaf = nextBranch.getElement(0); - while (!firstLeaf.isLeaf()) - { - firstLeaf = firstLeaf.getElement(0); - } - BranchElement parent2 = (BranchElement) firstLeaf.getParentElement(); - Element newEl2 = - createLeafElement(parent2, - firstLeaf.getAttributes(), - offset, firstLeaf.getEndOffset()); - parent2.replace(0, 1, new Element[] { newEl2 }); - - - ((BranchElement) parent). - replace(index, 1, new Element[] { newEl1 }); + index = current.getElementIndex(offset); + elementStack.push(current); + current = current.getElement(index); } - for (int i = 0; i < data.length; i++) + int i = 0; + int type = data[0].getType(); + if (type == ElementSpec.ContentType) + { + // If the first tag is content we must treat it separately to allow + // for joining properly to previous Elements and to ensure that + // no extra LeafElements are erroneously inserted. + insertFirstContentTag(data); + pos += data[0].length; + i = 1; + } + else + { + createFracture(data); + i = 0; + } + + // Handle each ElementSpec individually. + for (; i < data.length; i++) { BranchElement paragraph = (BranchElement) elementStack.peek(); switch (data[i].getType()) @@ -827,19 +792,39 @@ public class DefaultStyledDocument extends AbstractDocument switch (data[i].getDirection()) { case ElementSpec.JoinFractureDirection: + // Fracture the tree and ensure the appropriate element + // is on top of the stack. + fracNotCreated = false; insertFracture(data[i]); + if (fracNotCreated) + { + if (lastFractured != null) + elementStack.push(lastFractured.getParentElement()); + else + elementStack.push(paragraph.getElement(0)); + } break; case ElementSpec.JoinNextDirection: - int index = paragraph.getElementIndex(offset); - elementStack.push(paragraph.getElement(index)); - break; - case ElementSpec.OriginateDirection: - Element current = (Element) elementStack.peek(); - Element newParagraph = - insertParagraph((BranchElement) current, offset); - elementStack.push(newParagraph); + // Push the next paragraph element onto the stack so + // future insertions are added to it. + int ix = paragraph.getElementIndex(pos) + 1; + elementStack.push(paragraph.getElement(ix)); break; default: + Element br = null; + if (data.length > i + 1) + { + // leaves will be added to paragraph later + int x = paragraph.getElementIndex(pos) + 1; + Edit e = getEditForParagraphAndIndex(paragraph, x); + br = (BranchElement) createBranchElement(paragraph, + data[i].getAttributes()); + e.added.add(br); + elementStack.push(br); + } + else + // need to add leaves to paragraph now + br = insertParagraph(paragraph, pos); break; } break; @@ -848,50 +833,27 @@ public class DefaultStyledDocument extends AbstractDocument break; case ElementSpec.ContentType: insertContentTag(data[i]); + offset = pos; break; } } - endEdit(); - } - - /** - * Finishes an insertion by possibly evaluating the outstanding start and - * end tags. However, this is only performed if the event has received any - * modifications. - */ - private void endEdit() - { - if (documentEvent.modified) - prepareContentInsertion(); } /** - * Evaluates the number of inserted end tags and performs the corresponding - * structural changes. + * Inserts a new paragraph. + * + * @param par - + * the parent + * @param offset - + * the offset + * @return the new paragraph */ - private void prepareContentInsertion() - { - while (numEndTags > 0) - { - elementStack.pop(); - numEndTags--; - } - - while (numStartTags > 0) - { - Element current = (Element) elementStack.peek(); - Element newParagraph = - insertParagraph((BranchElement) current, offset); - elementStack.push(newParagraph); - numStartTags--; - } - } - private Element insertParagraph(BranchElement par, int offset) { - Element current = par.getElement(par.getElementIndex(offset)); - Element[] res = split(current, offset, 0); int index = par.getElementIndex(offset); + Element current = par.getElement(index); + Element[] res = split(current, offset, 0, 0); + Edit e = getEditForParagraphAndIndex(par, index + 1); Element ret; if (res[1] != null) { @@ -902,334 +864,756 @@ public class DefaultStyledDocument extends AbstractDocument removed = new Element[0]; if (res[1] instanceof BranchElement) { - added = new Element[]{ res[1] }; + added = new Element[] { res[1] }; ret = res[1]; } else { ret = createBranchElement(par, null); - added = new Element[]{ ret, res[1] }; + added = new Element[] { ret, res[1] }; } index++; } else { - removed = new Element[]{ current }; + removed = new Element[] { current }; if (res[1] instanceof BranchElement) { ret = res[1]; - added = new Element[]{ res[0], res[1] }; + added = new Element[] { res[0], res[1] }; } else { ret = createBranchElement(par, null); - added = new Element[]{ res[0], ret, res[1] }; + added = new Element[] { res[0], ret, res[1] }; + } + } + + e.addAddedElements(added); + e.addRemovedElements(removed); + } + else + { + ret = createBranchElement(par, null); + e.addAddedElement(ret); + } + return ret; + } + + /** + * Inserts the first tag into the document. + * + * @param data - + * the data to be inserted. + */ + private void insertFirstContentTag(ElementSpec[] data) + { + ElementSpec first = data[0]; + BranchElement paragraph = (BranchElement) elementStack.peek(); + int index = paragraph.getElementIndex(offset); + Element current = paragraph.getElement(index); + int newEndOffset = offset + first.length; + boolean onlyContent = data.length == 1; + Edit edit = getEditForParagraphAndIndex(paragraph, index); + + switch (first.getDirection()) + { + case ElementSpec.JoinPreviousDirection: + if (current.getEndOffset() != newEndOffset && !onlyContent) + { + Element newEl1 = createLeafElement(paragraph, + current.getAttributes(), + current.getStartOffset(), + newEndOffset); + edit.addAddedElement(newEl1); + edit.addRemovedElement(current); + offset = newEndOffset; + } + break; + case ElementSpec.JoinNextDirection: + if (offset != 0) + { + Element newEl1 = createLeafElement(paragraph, + current.getAttributes(), + current.getStartOffset(), + offset); + edit.addAddedElement(newEl1); + Element next = paragraph.getElement(index + 1); + + if (onlyContent) + newEl1 = createLeafElement(paragraph, next.getAttributes(), + offset, next.getEndOffset()); + else + { + newEl1 = createLeafElement(paragraph, next.getAttributes(), + offset, newEndOffset); + offset = newEndOffset; } + edit.addAddedElement(newEl1); + edit.addRemovedElement(current); + edit.addRemovedElement(next); + } + break; + default: + if (current.getStartOffset() != offset) + { + Element newEl = createLeafElement(paragraph, + current.getAttributes(), + current.getStartOffset(), + offset); + edit.addAddedElement(newEl); + } + edit.addRemovedElement(current); + Element newEl1 = createLeafElement(paragraph, first.getAttributes(), + offset, newEndOffset); + edit.addAddedElement(newEl1); + if (current.getEndOffset() != endOffset) + recreateLeaves(newEndOffset, paragraph, onlyContent); + else + offset = newEndOffset; + break; + } + } + + /** + * Inserts a content element into the document structure. + * + * @param tag - + * the element spec + */ + private void insertContentTag(ElementSpec tag) + { + BranchElement paragraph = (BranchElement) elementStack.peek(); + int len = tag.getLength(); + int dir = tag.getDirection(); + AttributeSet tagAtts = tag.getAttributes(); + + if (dir == ElementSpec.JoinNextDirection) + { + int index = paragraph.getElementIndex(pos); + Element target = paragraph.getElement(index); + Edit edit = getEditForParagraphAndIndex(paragraph, index); + + if (paragraph.getStartOffset() > pos) + { + Element first = paragraph.getElement(0); + Element newEl = createLeafElement(paragraph, + first.getAttributes(), pos, + first.getEndOffset()); + edit.addAddedElement(newEl); + edit.addRemovedElement(first); + } + else if (paragraph.getElementCount() > (index + 1) + && (pos == target.getStartOffset() && !target.equals(lastFractured))) + { + Element next = paragraph.getElement(index + 1); + Element newEl = createLeafElement(paragraph, + next.getAttributes(), pos, + next.getEndOffset()); + edit.addAddedElement(newEl); + edit.addRemovedElement(next); + edit.addRemovedElement(target); + } + else + { + BranchElement parent = (BranchElement) paragraph.getParentElement(); + int i = parent.getElementIndex(pos); + BranchElement next = (BranchElement) parent.getElement(i + 1); + AttributeSet atts = tag.getAttributes(); + + if (next != null) + { + Element nextLeaf = next.getElement(0); + Edit e = getEditForParagraphAndIndex(next, 0); + Element newEl2 = createLeafElement(next, atts, pos, nextLeaf.getEndOffset()); + e.addAddedElement(newEl2); + e.addRemovedElement(nextLeaf); + } + } + } + else + { + int end = pos + len; + Element leaf = createLeafElement(paragraph, tag.getAttributes(), pos, end); + + // Check for overlap with other leaves/branches + if (paragraph.getElementCount() > 0) + { + int index = paragraph.getElementIndex(pos); + Element target = paragraph.getElement(index); + boolean onlyContent = target.isLeaf(); + + BranchElement toRec = paragraph; + if (!onlyContent) + toRec = (BranchElement) target; + + // Check if we should place the leaf before or after target + if (pos > target.getStartOffset()) + index++; + + Edit edit = getEditForParagraphAndIndex(paragraph, index); + edit.addAddedElement(leaf); + + if (end != toRec.getEndOffset()) + { + recreateLeaves(end, toRec, onlyContent); + + if (onlyContent) + edit.addRemovedElement(target); + } + } + else + paragraph.replace(0, 0, new Element[] { leaf }); + } + + pos += len; + } + + /** + * This method fractures the child at offset. + * + * @param data + * the ElementSpecs used for the entire insertion + */ + private void createFracture(ElementSpec[] data) + { + BranchElement paragraph = (BranchElement) elementStack.peek(); + int index = paragraph.getElementIndex(offset); + Element child = paragraph.getElement(index); + Edit edit = getEditForParagraphAndIndex(paragraph, index); + AttributeSet atts = data[0].getAttributes(); + + if (offset != 0) + { + Element newEl1 = createLeafElement(paragraph, atts, + child.getStartOffset(), offset); + edit.addAddedElement(newEl1); + edit.addRemovedElement(child); + } + } + + /** + * Recreates a specified part of a the tree after a new leaf + * has been inserted. + * + * @param start - where to start recreating from + * @param paragraph - the paragraph to recreate + * @param onlyContent - true if this is the only content + */ + private void recreateLeaves(int start, BranchElement paragraph, boolean onlyContent) + { + int index = paragraph.getElementIndex(start); + Element child = paragraph.getElement(index); + AttributeSet atts = child.getAttributes(); + + if (!onlyContent) + { + BranchElement newBranch = (BranchElement) createBranchElement(paragraph, + atts); + Element newLeaf = createLeafElement(newBranch, atts, start, + child.getEndOffset()); + newBranch.replace(0, 0, new Element[] { newLeaf }); + + BranchElement parent = (BranchElement) paragraph.getParentElement(); + int parSize = parent.getElementCount(); + Edit edit = getEditForParagraphAndIndex(parent, parSize); + edit.addAddedElement(newBranch); + + int paragraphSize = paragraph.getElementCount(); + Element[] removed = new Element[paragraphSize - (index + 1)]; + int s = 0; + for (int j = index + 1; j < paragraphSize; j++) + removed[s++] = paragraph.getElement(j); + + edit = getEditForParagraphAndIndex(paragraph, index); + edit.addRemovedElements(removed); + Element[] added = recreateAfterFracture(removed, newBranch, 0, child.getEndOffset()); + newBranch.replace(1, 0, added); + + lastFractured = newLeaf; + offset = newBranch.getEndOffset(); + } + else + { + Element newLeaf = createLeafElement(paragraph, atts, start, + child.getEndOffset()); + Edit edit = getEditForParagraphAndIndex(paragraph, index); + edit.addAddedElement(newLeaf); + } + } + + /** + * Splits an element if offset is not already at its + * boundary. + * + * @param el + * the Element to possibly split + * @param offset + * the offset at which to possibly split + * @param space + * the amount of space to create between the splitted parts + * @param editIndex + * the index of the edit to use + * @return An array of elements which represent the split result. This array + * has two elements, the two parts of the split. The first element + * might be null, which means that the element which should be + * splitted can remain in place. The second element might also be + * null, which means that the offset is already at an element + * boundary and the element doesn't need to be splitted. + */ + private Element[] split(Element el, int offset, int space, int editIndex) + { + // If we are at an element boundary, then return an empty array. + if ((offset == el.getStartOffset() || offset == el.getEndOffset()) + && space == 0 && el.isLeaf()) + return new Element[2]; + + // If the element is an instance of BranchElement, then we + // recursivly + // call this method to perform the split. + Element[] res = new Element[2]; + if (el instanceof BranchElement) + { + int index = el.getElementIndex(offset); + Element child = el.getElement(index); + Element[] result = split(child, offset, space, editIndex); + Element[] removed; + Element[] added; + Element[] newAdded; + + int count = el.getElementCount(); + if (result[1] != null) + { + // This is the case when we can keep the first element. + if (result[0] == null) + { + removed = new Element[count - index - 1]; + newAdded = new Element[count - index - 1]; + added = new Element[] {}; + + } + // This is the case when we may not keep the first + // element. + else + { + removed = new Element[count - index]; + newAdded = new Element[count - index]; + added = new Element[] { result[0] }; + } + newAdded[0] = result[1]; + for (int i = index; i < count; i++) + { + Element el2 = el.getElement(i); + int ind = i - count + removed.length; + removed[ind] = el2; + if (ind != 0) + newAdded[ind] = el2; + } + + Edit edit = getEditForParagraphAndIndex((BranchElement) el, editIndex); + edit.addRemovedElements(removed); + edit.addAddedElements(added); + + BranchElement newPar = + (BranchElement) createBranchElement(el.getParentElement(), + el.getAttributes()); + newPar.replace(0, 0, newAdded); + res = new Element[] { null, newPar }; + } + else + { + removed = new Element[count - index]; + for (int i = index; i < count; ++i) + removed[i - index] = el.getElement(i); + + Edit edit = getEditForParagraphAndIndex((BranchElement) el, editIndex); + edit.addRemovedElements(removed); + + BranchElement newPar = (BranchElement) createBranchElement(el.getParentElement(), + el.getAttributes()); + + newPar.replace(0, 0, removed); + res = new Element[] { null, newPar }; } - par.replace(index, removed.length, added); - addEdit(par, index, removed, added); } - else + else if (el instanceof LeafElement) { - ret = createBranchElement(par, null); - Element[] added = new Element[]{ ret }; - par.replace(index, 0, added); - addEdit(par, index, new Element[0], added); + BranchElement par = (BranchElement) el.getParentElement(); + Element el1 = createLeafElement(par, el.getAttributes(), + el.getStartOffset(), offset); + + Element el2 = createLeafElement(par, el.getAttributes(), + offset + space, + el.getEndOffset()); + res = new Element[] { el1, el2 }; } - return ret; + return res; } - + /** * Inserts a fracture into the document structure. * - * @param tag - the element spec. + * @param tag - + * the element spec. */ private void insertFracture(ElementSpec tag) { - // This is the parent of the paragraph about to be fractured. We will - // create a new child of this parent. + // insert the fracture at offset. BranchElement parent = (BranchElement) elementStack.peek(); int parentIndex = parent.getElementIndex(offset); - - // This is the old paragraph. We must remove all its children that - // occur after offset and move them to a new paragraph. We must - // also recreate its child that occurs at offset to have the proper - // end offset. The remainder of this child will also go in the new - // paragraph. - BranchElement previous = (BranchElement) parent.getElement(parentIndex); - - // This is the new paragraph. - BranchElement newBranch = - (BranchElement) createBranchElement(parent, previous.getAttributes()); - - - // The steps we must take to properly fracture are: - // 1. Recreate the LeafElement at offset to have the correct end offset. - // 2. Create a new LeafElement with the remainder of the LeafElement in - // #1 ==> this is whatever was in that LeafElement to the right of the - // inserted newline. - // 3. Find the paragraph at offset and remove all its children that - // occur _after_ offset. These will be moved to the newly created - // paragraph. - // 4. Move the LeafElement created in #2 and all the LeafElements removed - // in #3 to the newly created paragraph. - // 5. Add the new paragraph to the parent. - int previousIndex = previous.getElementIndex(offset); - int numReplaced = previous.getElementCount() - previousIndex; - Element previousLeaf = previous.getElement(previousIndex); - AttributeSet prevLeafAtts = previous.getAttributes(); - - // This recreates the child at offset to have the proper end offset. - // (Step 1). - Element newPreviousLeaf = - createLeafElement(previous, - prevLeafAtts, previousLeaf.getStartOffset(), - offset); - // This creates the new child, which is the remainder of the old child. - // (Step 2). - - Element firstLeafInNewBranch = - createLeafElement(newBranch, prevLeafAtts, - offset, previousLeaf.getEndOffset()); - - // Now we move the new LeafElement and all the old children that occurred - // after the offset to the new paragraph. (Step 4). - Element[] newLeaves = new Element[numReplaced]; - newLeaves[0] = firstLeafInNewBranch; - for (int i = 1; i < numReplaced; i++) - newLeaves[i] = previous.getElement(previousIndex + i); - newBranch.replace(0, 0, newLeaves); - addEdit(newBranch, 0, null, newLeaves); - - // Now we remove the children after the offset from the previous - // paragraph. (Step 3). - int removeSize = previous.getElementCount() - previousIndex; - Element[] add = new Element[] { newPreviousLeaf }; - Element[] remove = new Element[removeSize]; - for (int j = 0; j < removeSize; j++) - remove[j] = previous.getElement(previousIndex + j); - previous.replace(previousIndex, removeSize, add); - addEdit(previous, previousIndex, remove, add); - - // Finally we add the new paragraph to the parent. (Step 5). - Element[] nb = new Element[] { newBranch }; - int index = parentIndex + 1; - parent.replace(index, 0, nb); - addEdit(parent, index, null, nb); - } - - /** - * Inserts a content element into the document structure. - * - * @param tag the element spec - */ - private void insertContentTag(ElementSpec tag) - { - prepareContentInsertion(); - int len = tag.getLength(); - int dir = tag.getDirection(); - AttributeSet tagAtts = tag.getAttributes(); - if (dir == ElementSpec.JoinPreviousDirection) - { - // The mauve tests to this class show that a JoinPrevious insertion - // does not add any edits to the document event. To me this means - // that nothing is done here. The previous element naturally should - // expand so that it covers the new characters. - } - else if (dir == ElementSpec.JoinNextDirection) + AttributeSet parentAtts = parent.getAttributes(); + Element toFracture = parent.getElement(parentIndex); + int parSize = parent.getElementCount(); + Edit edit = getEditForParagraphAndIndex(parent, parentIndex); + + Element frac = toFracture; + int leftIns = 0; + int indexOfFrac = toFracture.getElementIndex(offset); + int size = toFracture.getElementCount(); + + // gets the leaf that falls along the fracture + frac = toFracture.getElement(indexOfFrac); + while (!frac.isLeaf()) + frac = frac.getElement(frac.getElementIndex(offset)); + + AttributeSet atts = frac.getAttributes(); + int fracStart = frac.getStartOffset(); + int fracEnd = frac.getEndOffset(); + if (offset > fracStart && offset < fracEnd) { - // FIXME: - // Have to handle JoinNext differently depending on whether - // or not it comes after a fracture. If comes after a fracture, - // the insertFracture method takes care of everything and nothing - // needs to be done here. Otherwise, we need to adjust the - // Element structure. For now, I check if the elementStack's - // top Element is the immediate parent of the LeafElement at - // offset - if so, we did not come immediately after a - // fracture. This seems awkward and should probably be improved. - // We may be doing too much in insertFracture because we are - // adjusting the offsets, the correct thing to do may be to - // create a new branch element and push it on to element stack - // and then this method here can be more general. + // recreate left-side of branch and all its children before offset + // add the fractured leaves to the right branch + BranchElement rightBranch = + (BranchElement) createBranchElement(parent, parentAtts); - BranchElement paragraph = (BranchElement) elementStack.peek(); - int index = paragraph.getElementIndex(offset); - Element target = paragraph.getElement(index); - if (target.isLeaf() && paragraph.getElementCount() > (index + 1)) + // Check if left branch has already been edited. If so, we only + // need to create the right branch. + BranchElement leftBranch = null; + Element[] added = null; + if (edit.added.size() > 0 || edit.removed.size() > 0) { - Element next = paragraph.getElement(index + 1); - Element newEl1 = createLeafElement(paragraph, - target.getAttributes(), - target.getStartOffset(), - offset); - Element newEl2 = createLeafElement(paragraph, - next.getAttributes(), offset, - next.getEndOffset()); - Element[] add = new Element[] { newEl1, newEl2 }; - paragraph.replace (index, 2, add); - addEdit(paragraph, index, new Element[] { target, next }, add); + added = new Element[] { rightBranch }; + + // don't try to remove left part of tree + parentIndex++; + } + else + { + leftBranch = + (BranchElement) createBranchElement(parent, parentAtts); + added = new Element[] { leftBranch, rightBranch }; + + // add fracture to leftBranch + Element leftFracturedLeaf = createLeafElement(leftBranch, atts, + fracStart, offset); + leftBranch.replace(leftIns, 0, new Element[] { leftFracturedLeaf }); } - } - else if (dir == ElementSpec.OriginateDirection) - { - BranchElement paragraph = (BranchElement) elementStack.peek(); - int index = paragraph.getElementIndex(offset); - Element current = paragraph.getElement(index); - Element[] added; - Element[] removed = new Element[] {current}; - Element[] splitRes = split(current, offset, length); - if (splitRes[0] == null) + if (!toFracture.isLeaf()) { - added = new Element[2]; - added[0] = createLeafElement(paragraph, tagAtts, - offset, endOffset); - added[1] = splitRes[1]; - removed = new Element[0]; - index++; + // add all non-fracture elements to the branches + if (indexOfFrac > 0 && leftBranch != null) + { + Element[] add = new Element[indexOfFrac]; + for (int i = 0; i < indexOfFrac; i++) + add[i] = toFracture.getElement(i); + leftIns = add.length; + leftBranch.replace(0, 0, add); + } + + int count = size - indexOfFrac - 1; + if (count > 0) + { + Element[] add = new Element[count]; + int j = 0; + int i = indexOfFrac + 1; + while (j < count) + add[j++] = toFracture.getElement(i++); + rightBranch.replace(0, 0, add); + } } - else if (current.getStartOffset() == offset) - { - // This is if the new insertion happens immediately before - // the current Element. In this case there are 2 - // resulting Elements. - added = new Element[2]; - added[0] = createLeafElement(paragraph, tagAtts, offset, - endOffset); - added[1] = splitRes[1]; + + // add to fracture to rightBranch + // Check if we can join the right frac leaf with the next leaf + int rm = 0; + int end = fracEnd; + Element next = rightBranch.getElement(0); + if (next != null && next.isLeaf() + && next.getAttributes().isEqual(atts)) + { + end = next.getEndOffset(); + rm = 1; } - else if (current.getEndOffset() == endOffset) + + Element rightFracturedLeaf = createLeafElement(rightBranch, atts, + offset, end); + rightBranch.replace(0, rm, new Element[] { rightFracturedLeaf }); + + // recreate those elements after parentIndex and add/remove all + // new/old elements to parent + int remove = parSize - parentIndex; + Element[] removed = new Element[0]; + Element[] added2 = new Element[0]; + if (remove > 0) { - // This is if the new insertion happens right at the end of - // the current Element. In this case there are - // 2 resulting Elements. - added = new Element[2]; - added[0] = splitRes[0]; - added[1] = createLeafElement(paragraph, tagAtts, offset, - endOffset); + removed = new Element[remove]; + int s = 0; + for (int j = parentIndex; j < parSize; j++) + removed[s++] = parent.getElement(j); + edit.addRemovedElements(removed); + added2 = recreateAfterFracture(removed, parent, 1, + rightBranch.getEndOffset()); } + + edit.addAddedElements(added); + edit.addAddedElements(added2); + elementStack.push(rightBranch); + lastFractured = rightFracturedLeaf; + } + else + fracNotCreated = true; + } + + /** + * Recreates all the elements from the parent to the element on the top of + * the stack, starting from startFrom with the starting offset of + * startOffset. + * + * @param recreate - + * the elements to recreate + * @param parent - + * the element to add the new elements to + * @param startFrom - + * where to start recreating from + * @param startOffset - + * the offset of the first element + * @return the array of added elements + */ + private Element[] recreateAfterFracture(Element[] recreate, + BranchElement parent, int startFrom, + int startOffset) + { + Element[] added = new Element[recreate.length - startFrom]; + int j = 0; + for (int i = startFrom; i < recreate.length; i++) + { + Element curr = recreate[i]; + int len = curr.getEndOffset() - curr.getStartOffset(); + if (curr instanceof LeafElement) + added[j] = createLeafElement(parent, curr.getAttributes(), + startOffset, startOffset + len); else { - // This is if the new insertion is in the middle of the - // current Element. In this case - // there will be 3 resulting Elements. - added = new Element[3]; - added[0] = splitRes[0]; - added[1] = createLeafElement(paragraph, tagAtts, offset, - endOffset); - added[2] = splitRes[1]; - } - paragraph.replace(index, removed.length, added); - addEdit(paragraph, index, removed, added); + BranchElement br = + (BranchElement) createBranchElement(parent, + curr.getAttributes()); + int bSize = curr.getElementCount(); + for (int k = 0; k < bSize; k++) + { + Element bCurr = curr.getElement(k); + Element[] add = recreateAfterFracture(new Element[] { bCurr }, br, 0, + startOffset); + br.replace(0, 0, add); + + } + added[j] = br; + } + startOffset += len; + j++; } - offset += len; + + return added; } + } + + /** + * This method looks through the Vector of Edits to see if there is already an + * Edit object associated with the given paragraph. If there is, then we + * return it. Otherwise we create a new Edit object, add it to the vector, and + * return it. Note: this method is package private to avoid accessors. + * + * @param index + * the index associated with the Edit we want to create + * @param para + * the paragraph associated with the Edit we want + * @return the found or created Edit object + */ + Edit getEditForParagraphAndIndex(BranchElement para, int index) + { + Edit curr; + int size = edits.size(); + for (int i = 0; i < size; i++) + { + curr = (Edit) edits.elementAt(i); + if (curr.e.equals(para)) + return curr; + } + curr = new Edit(para, index, null, null); + edits.add(curr); + return curr; + } + /** + * Instance of all editing information for an object in the Vector. This class + * is used to add information to the DocumentEvent associated with an + * insertion/removal/change as well as to store the changes that need to be + * made so they can be made all at the same (appropriate) time. + */ + class Edit + { + /** The element to edit . */ + Element e; + + /** The index of the change. */ + int index; + + /** The removed elements. */ + Vector removed = new Vector(); + + /** The added elements. */ + Vector added = new Vector(); + /** - * Creates a copy of the element clonee that has the parent - * parent. - * @param parent the parent of the newly created Element - * @param clonee the Element to clone - * @return the cloned Element + * Return an array containing the Elements that have been removed from the + * paragraph associated with this Edit. + * + * @return an array of removed Elements */ - public Element clone (Element parent, Element clonee) + public Element[] getRemovedElements() { - // If the Element we want to clone is a leaf, then simply copy it - if (clonee.isLeaf()) - return createLeafElement(parent, clonee.getAttributes(), - clonee.getStartOffset(), clonee.getEndOffset()); - - // Otherwise create a new BranchElement with the desired parent and - // the clonee's attributes - BranchElement result = (BranchElement) createBranchElement(parent, clonee.getAttributes()); - - // And clone all the of clonee's children - Element[] children = new Element[clonee.getElementCount()]; - for (int i = 0; i < children.length; i++) - children[i] = clone(result, clonee.getElement(i)); + int size = removed.size(); + Element[] removedElements = new Element[size]; + for (int i = 0; i < size; i++) + removedElements[i] = (Element) removed.elementAt(i); + return removedElements; + } + + /** + * Return an array containing the Elements that have been added to the + * paragraph associated with this Edit. + * + * @return an array of added Elements + */ + public Element[] getAddedElements() + { + int size = added.size(); + Element[] addedElements = new Element[size]; + for (int i = 0; i < size; i++) + addedElements[i] = (Element) added.elementAt(i); + return addedElements; + } + + /** + * Checks if e is already in the vector. + * + * @param e - the Element to look for + * @param v - the vector to search + * @return true if e is in v. + */ + private boolean contains(Vector v, Element e) + { + if (e == null) + return false; - // Make the cloned children the children of the BranchElement - result.replace(0, 0, children); - return result; + int i = v.size(); + for (int j = 0; j < i; j++) + { + Element e1 = (Element) v.get(j); + if ((e1 != null) && (e1.getAttributes().isEqual(e.getAttributes())) + && (e1.getName().equals(e.getName())) + && (e1.getStartOffset() == e.getStartOffset()) + && (e1.getEndOffset() == e.getEndOffset()) + && (e1.getParentElement().equals(e.getParentElement())) + && (e1.getElementCount() == e.getElementCount())) + return true; + } + return false; } /** - * Adds an ElementChange for a given element modification to the document - * event. If there already is an ElementChange registered for this element, - * this method tries to merge the ElementChanges together. However, this - * is only possible if the indices of the new and old ElementChange are - * equal. - * - * @param e the element - * @param i the index of the change - * @param removed the removed elements, or null - * @param added the added elements, or null + * Adds one Element to the vector of removed Elements. + * + * @param e + * the Element to add */ - private void addEdit(Element e, int i, Element[] removed, Element[] added) + public void addRemovedElement(Element e) { - // Perform sanity check first. - DocumentEvent.ElementChange ec = documentEvent.getChange(e); + if (!contains(removed, e)) + removed.add(e); + } - // Merge the existing stuff with the new stuff. - Element[] oldAdded = ec == null ? null: ec.getChildrenAdded(); - Element[] newAdded; - if (oldAdded != null && added != null) + /** + * Adds each Element in the given array to the vector of removed Elements + * + * @param e + * the array containing the Elements to be added + */ + public void addRemovedElements(Element[] e) + { + if (e == null || e.length == 0) + return; + for (int i = 0; i < e.length; i++) { - if (ec.getIndex() <= i) - { - int index = i - ec.getIndex(); - // Merge adds together. - newAdded = new Element[oldAdded.length + added.length]; - System.arraycopy(oldAdded, 0, newAdded, 0, index); - System.arraycopy(added, 0, newAdded, index, added.length); - System.arraycopy(oldAdded, index, newAdded, index + added.length, - oldAdded.length - index); - i = ec.getIndex(); - } - else - throw new AssertionError("Not yet implemented case."); + if (!contains(removed, e[i])) + removed.add(e[i]); } - else if (added != null) - newAdded = added; - else if (oldAdded != null) - newAdded = oldAdded; - else - newAdded = new Element[0]; + } + + /** + * Adds one Element to the vector of added Elements. + * + * @param e + * the Element to add + */ + public void addAddedElement(Element e) + { + if (!contains(added, e)) + added.add(e); + } - Element[] oldRemoved = ec == null ? null: ec.getChildrenRemoved(); - Element[] newRemoved; - if (oldRemoved != null && removed != null) + /** + * Adds each Element in the given array to the vector of added Elements. + * + * @param e + * the array containing the Elements to be added + */ + public void addAddedElements(Element[] e) + { + if (e == null || e.length == 0) + return; + for (int i = 0; i < e.length; i++) { - if (ec.getIndex() <= i) - { - int index = i - ec.getIndex(); - // Merge removes together. - newRemoved = new Element[oldRemoved.length + removed.length]; - System.arraycopy(oldAdded, 0, newRemoved, 0, index); - System.arraycopy(removed, 0, newRemoved, index, removed.length); - System.arraycopy(oldRemoved, index, newRemoved, - index + removed.length, - oldRemoved.length - index); - i = ec.getIndex(); - } - else - throw new AssertionError("Not yet implemented case."); + if (!contains(added, e[i])) + added.add(e[i]); } - else if (removed != null) - newRemoved = removed; - else if (oldRemoved != null) - newRemoved = oldRemoved; - else - newRemoved = new Element[0]; + } - // Replace the existing edit for the element with the merged. - documentEvent.addEdit(new ElementEdit(e, i, newRemoved, newAdded)); + /** + * Creates a new Edit object with the given parameters + * + * @param e + * the paragraph Element associated with this Edit + * @param i + * the index within the paragraph where changes are started + * @param removed + * an array containing Elements that should be removed from the + * paragraph Element + * @param added + * an array containing Elements that should be added to the + * paragraph Element + */ + public Edit(Element e, int i, Element[] removed, Element[] added) + { + this.e = e; + this.index = i; + addRemovedElements(removed); + addAddedElements(added); } } /** - * An element type for sections. This is a simple BranchElement with - * a unique name. + * An element type for sections. This is a simple BranchElement with a unique + * name. */ protected class SectionElement extends BranchElement { @@ -1295,6 +1679,11 @@ public class DefaultStyledDocument extends AbstractDocument */ private StyleChangeListener styleChangeListener; + /** + * Vector that contains all the edits. Maybe replace by a HashMap. + */ + Vector edits = new Vector(); + /** * Creates a new DefaultStyledDocument. */ @@ -1304,10 +1693,11 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Creates a new DefaultStyledDocument that uses the - * specified {@link StyleContext}. - * - * @param context the StyleContext to use + * Creates a new DefaultStyledDocument that uses the specified + * {@link StyleContext}. + * + * @param context + * the StyleContext to use */ public DefaultStyledDocument(StyleContext context) { @@ -1315,14 +1705,16 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Creates a new DefaultStyledDocument that uses the - * specified {@link StyleContext} and {@link Content} buffer. - * - * @param content the Content buffer to use - * @param context the StyleContext to use + * Creates a new DefaultStyledDocument that uses the specified + * {@link StyleContext} and {@link Content} buffer. + * + * @param content + * the Content buffer to use + * @param context + * the StyleContext to use */ public DefaultStyledDocument(AbstractDocument.Content content, - StyleContext context) + StyleContext context) { super(content, context); buffer = new ElementBuffer(createDefaultRoot()); @@ -1330,10 +1722,9 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Adds a style into the style hierarchy. Unspecified style attributes - * can be resolved in the parent style, if one is specified. - * - * While it is legal to add nameless styles (nm == nullparent style, if one is specified. While it + * is legal to add nameless styles (nm == nullElement that corresponds to the character - * at the specified position. - * - * @param position the position of which we query the corresponding - * Element - * - * @return the Element that corresponds to the character - * at the specified position + * Returns the Element that corresponds to the character at the + * specified position. + * + * @param position + * the position of which we query the corresponding + * Element + * @return the Element that corresponds to the character at the + * specified position */ public Element getCharacterElement(int position) { @@ -1402,15 +1792,15 @@ public class DefaultStyledDocument extends AbstractDocument int index = element.getElementIndex(position); element = element.getElement(index); } - + return element; } /** * Extracts a background color from a set of attributes. - * - * @param attributes the attributes from which to get a background color - * + * + * @param attributes + * the attributes from which to get a background color * @return the background color that correspond to the attributes */ public Color getBackground(AttributeSet attributes) @@ -1421,7 +1811,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the default root element. - * + * * @return the default root element */ public Element getDefaultRootElement() @@ -1431,9 +1821,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Extracts a font from a set of attributes. - * - * @param attributes the attributes from which to get a font - * + * + * @param attributes + * the attributes from which to get a font * @return the font that correspond to the attributes */ public Font getFont(AttributeSet attributes) @@ -1441,12 +1831,12 @@ public class DefaultStyledDocument extends AbstractDocument StyleContext context = (StyleContext) getAttributeContext(); return context.getFont(attributes); } - + /** * Extracts a foreground color from a set of attributes. - * - * @param attributes the attributes from which to get a foreground color - * + * + * @param attributes + * the attributes from which to get a foreground color * @return the foreground color that correspond to the attributes */ public Color getForeground(AttributeSet attributes) @@ -1457,9 +1847,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns the logical Style for the specified position. - * - * @param position the position from which to query to logical style - * + * + * @param position + * the position from which to query to logical style * @return the logical Style for the specified position */ public Style getLogicalStyle(int position) @@ -1474,37 +1864,32 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Returns the paragraph element for the specified position. - * If the position is outside the bounds of the document's root element, - * then the closest element is returned. That is the last paragraph if + * Returns the paragraph element for the specified position. If the position + * is outside the bounds of the document's root element, then the closest + * element is returned. That is the last paragraph if * position >= endIndex or the first paragraph if * position < startIndex. - * - * @param position the position for which to query the paragraph element - * + * + * @param position + * the position for which to query the paragraph element * @return the paragraph element for the specified position */ public Element getParagraphElement(int position) { - BranchElement root = (BranchElement) getDefaultRootElement(); - int start = root.getStartOffset(); - int end = root.getEndOffset(); - if (position >= end) - position = end - 1; - else if (position < start) - position = start; - - Element par = root.positionToElement(position); - - assert par != null : "The paragraph element must not be null"; - return par; + Element e = getDefaultRootElement(); + while (!e.isLeaf()) + e = e.getElement(e.getElementIndex(position)); + + if (e != null) + return e.getParentElement(); + return e; } /** * Looks up and returns a named Style. - * - * @param nm the name of the Style - * + * + * @param nm + * the name of the Style * @return the found Style of null if no such * Style exists */ @@ -1516,8 +1901,9 @@ public class DefaultStyledDocument extends AbstractDocument /** * Removes a named Style from the style hierarchy. - * - * @param nm the name of the Style to be removed + * + * @param nm + * the name of the Style to be removed */ public void removeStyle(String nm) { @@ -1528,31 +1914,32 @@ public class DefaultStyledDocument extends AbstractDocument /** * Sets text attributes for the fragment specified by offset * and length. - * - * @param offset the start offset of the fragment - * @param length the length of the fragment - * @param attributes the text attributes to set - * @param replace if true, the attributes of the current - * selection are overridden, otherwise they are merged + * + * @param offset + * the start offset of the fragment + * @param length + * the length of the fragment + * @param attributes + * the text attributes to set + * @param replace + * if true, the attributes of the current selection + * are overridden, otherwise they are merged */ public void setCharacterAttributes(int offset, int length, - AttributeSet attributes, - boolean replace) + AttributeSet attributes, boolean replace) { // Exit early if length is 0, so no DocumentEvent is created or fired. if (length == 0) return; try { - // Must obtain a write lock for this method. writeLock() and + // Must obtain a write lock for this method. writeLock() and // writeUnlock() should always be in try/finally block to make // sure that locking happens in a balanced manner. writeLock(); - DefaultDocumentEvent ev = - new DefaultDocumentEvent( - offset, - length, - DocumentEvent.EventType.CHANGE); + DefaultDocumentEvent ev = new DefaultDocumentEvent(offset, + length, + DocumentEvent.EventType.CHANGE); // Modify the element structure so that the interval begins at an // element @@ -1563,13 +1950,13 @@ public class DefaultStyledDocument extends AbstractDocument // Visit all paragraph elements within the specified interval int end = offset + length; Element curr; - for (int pos = offset; pos < end; ) + for (int pos = offset; pos < end;) { // Get the CharacterElement at offset pos. curr = getCharacterElement(pos); if (pos == curr.getEndOffset()) break; - + MutableAttributeSet a = (MutableAttributeSet) curr.getAttributes(); ev.addEdit(new AttributeUndoableEdit(curr, attributes, replace)); // If replace is true, remove all the old attributes. @@ -1588,12 +1975,14 @@ public class DefaultStyledDocument extends AbstractDocument writeUnlock(); } } - + /** * Sets the logical style for the paragraph at the specified position. - * - * @param position the position at which the logical style is added - * @param style the style to set for the current paragraph + * + * @param position + * the position at which the logical style is added + * @param style + * the style to set for the current paragraph */ public void setLogicalStyle(int position, Style style) { @@ -1603,60 +1992,59 @@ public class DefaultStyledDocument extends AbstractDocument if (el == null) return; try - { - writeLock(); - if (el instanceof AbstractElement) - { - AbstractElement ael = (AbstractElement) el; - ael.setResolveParent(style); - int start = el.getStartOffset(); - int end = el.getEndOffset(); - DefaultDocumentEvent ev = - new DefaultDocumentEvent ( - start, - end - start, - DocumentEvent.EventType.CHANGE); - // FIXME: Add an UndoableEdit to this event and fire it. - fireChangedUpdate(ev); - } - else - throw new - AssertionError("paragraph elements are expected to be" - + "instances of AbstractDocument.AbstractElement"); - } + { + writeLock(); + if (el instanceof AbstractElement) + { + AbstractElement ael = (AbstractElement) el; + ael.setResolveParent(style); + int start = el.getStartOffset(); + int end = el.getEndOffset(); + DefaultDocumentEvent ev = new DefaultDocumentEvent(start, + end - start, + DocumentEvent.EventType.CHANGE); + fireChangedUpdate(ev); + fireUndoableEditUpdate(new UndoableEditEvent(this, ev)); + } + else + throw new AssertionError( + "paragraph elements are expected to be" + + "instances of AbstractDocument.AbstractElement"); + } finally - { - writeUnlock(); - } + { + writeUnlock(); + } } /** * Sets text attributes for the paragraph at the specified fragment. - * - * @param offset the beginning of the fragment - * @param length the length of the fragment - * @param attributes the text attributes to set - * @param replace if true, the attributes of the current - * selection are overridden, otherwise they are merged + * + * @param offset + * the beginning of the fragment + * @param length + * the length of the fragment + * @param attributes + * the text attributes to set + * @param replace + * if true, the attributes of the current selection + * are overridden, otherwise they are merged */ public void setParagraphAttributes(int offset, int length, - AttributeSet attributes, - boolean replace) + AttributeSet attributes, boolean replace) { try { - // Must obtain a write lock for this method. writeLock() and + // Must obtain a write lock for this method. writeLock() and // writeUnlock() should always be in try/finally blocks to make // sure that locking occurs in a balanced manner. writeLock(); - + // Create a DocumentEvent to use for changedUpdate(). - DefaultDocumentEvent ev = - new DefaultDocumentEvent ( - offset, - length, - DocumentEvent.EventType.CHANGE); - + DefaultDocumentEvent ev = new DefaultDocumentEvent(offset, + length, + DocumentEvent.EventType.CHANGE); + // Have to iterate through all the _paragraph_ elements that are // contained or partially contained in the interval // (offset, offset + length). @@ -1665,7 +2053,7 @@ public class DefaultStyledDocument extends AbstractDocument int endElement = rootElement.getElementIndex(offset + length - 1); if (endElement < startElement) endElement = startElement; - + for (int i = startElement; i <= endElement; i++) { Element par = rootElement.getElement(i); @@ -1688,11 +2076,13 @@ public class DefaultStyledDocument extends AbstractDocument } /** - * Called in response to content insert actions. This is used to - * update the element structure. - * - * @param ev the DocumentEvent describing the change - * @param attr the attributes for the change + * Called in response to content insert actions. This is used to update the + * element structure. + * + * @param ev + * the DocumentEvent describing the change + * @param attr + * the attributes for the change */ protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr) { @@ -1703,8 +2093,7 @@ public class DefaultStyledDocument extends AbstractDocument int offset = ev.getOffset(); int length = ev.getLength(); int endOffset = offset + length; - AttributeSet paragraphAttributes = - getParagraphElement(endOffset).getAttributes(); + AttributeSet paragraphAttributes = getParagraphElement(endOffset).getAttributes(); Segment txt = new Segment(); try { @@ -1723,91 +2112,75 @@ public class DefaultStyledDocument extends AbstractDocument short finalStartDirection = ElementSpec.OriginateDirection; boolean prevCharWasNewline = false; Element prev = getCharacterElement(offset); - Element next = getCharacterElement(endOffset); + Element next = getCharacterElement(endOffset); Element prevParagraph = getParagraphElement(offset); Element paragraph = getParagraphElement(endOffset); - + int segmentEnd = txt.offset + txt.count; - + // Check to see if we're inserting immediately after a newline. if (offset > 0) { try - { - String s = getText(offset - 1, 1); - if (s.equals("\n")) - { - finalStartDirection = - handleInsertAfterNewline(specs, offset, endOffset, - prevParagraph, - paragraph, - paragraphAttributes); - - prevCharWasNewline = true; - // Find the final start tag from the ones just created. - for (int i = 0; i < specs.size(); i++) - if (((ElementSpec) specs.get(i)).getType() - == ElementSpec.StartTagType) - finalStartTag = (ElementSpec)specs.get(i); - } - } + { + String s = getText(offset - 1, 1); + if (s.equals("\n")) + { + finalStartDirection = handleInsertAfterNewline(specs, offset, + endOffset, + prevParagraph, + paragraph, + paragraphAttributes); + + prevCharWasNewline = true; + // Find the final start tag from the ones just created. + for (int i = 0; i < specs.size(); i++) + if (((ElementSpec) specs.get(i)).getType() == ElementSpec.StartTagType) + finalStartTag = (ElementSpec) specs.get(i); + } + } catch (BadLocationException ble) - { - // This shouldn't happen. - AssertionError ae = new AssertionError(); - ae.initCause(ble); - throw ae; - } + { + // This shouldn't happen. + AssertionError ae = new AssertionError(); + ae.initCause(ble); + throw ae; + } } - for (int i = txt.offset; i < segmentEnd; ++i) { len++; if (txt.array[i] == '\n') { // Add the ElementSpec for the content. - specs.add(new ElementSpec(attr, ElementSpec.ContentType, len)); + specs.add(new ElementSpec(attr, ElementSpec.ContentType, len)); // Add ElementSpecs for the newline. specs.add(new ElementSpec(null, ElementSpec.EndTagType)); finalStartTag = new ElementSpec(paragraphAttributes, - ElementSpec.StartTagType); + ElementSpec.StartTagType); specs.add(finalStartTag); len = 0; } } // Create last element if last character hasn't been a newline. - if (len > 0) + if (len > 0) specs.add(new ElementSpec(attr, ElementSpec.ContentType, len)); - // Set the direction of the last spec of type StartTagType. - // If we are inserting after a newline then this value comes from + // Set the direction of the last spec of type StartTagType. + // If we are inserting after a newline then this value comes from // handleInsertAfterNewline. if (finalStartTag != null) { if (prevCharWasNewline) finalStartTag.setDirection(finalStartDirection); else if (prevParagraph.getEndOffset() != endOffset) - { - try - { - String last = getText(endOffset - 1, 1); - if (!last.equals("\n")) - finalStartTag.setDirection(ElementSpec.JoinFractureDirection); - } - catch (BadLocationException ble) - { - // This shouldn't happen. - AssertionError ae = new AssertionError(); - ae.initCause(ble); - throw ae; - } - } + finalStartTag.setDirection(ElementSpec.JoinFractureDirection); else { - // If there is an element AFTER this one, then set the + // If there is an element AFTER this one, then set the // direction to JoinNextDirection. Element parent = prevParagraph.getParentElement(); int index = parent.getElementIndex(offset); @@ -1863,6 +2236,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * A helper method to set up the ElementSpec buffer for the special * case of an insertion occurring immediately after a newline. + * * @param specs the ElementSpec buffer to initialize. */ short handleInsertAfterNewline(Vector specs, int offset, int endOffset, @@ -1877,23 +2251,20 @@ public class DefaultStyledDocument extends AbstractDocument return ElementSpec.JoinFractureDirection; // If there is an Element after this one, use JoinNextDirection. Element parent = paragraph.getParentElement(); - if (parent.getElementCount() > parent.getElementIndex(offset) + 1) + if (parent.getElementCount() > (parent.getElementIndex(offset) + 1)) return ElementSpec.JoinNextDirection; } - else - { - // TODO: What to do here? - } return ElementSpec.OriginateDirection; } - + /** * Updates the document structure in response to text removal. This is - * forwarded to the {@link ElementBuffer} of this document. Any changes to - * the document structure are added to the specified document event and - * sent to registered listeners. - * - * @param ev the document event that records the changes to the document + * forwarded to the {@link ElementBuffer} of this document. Any changes to the + * document structure are added to the specified document event and sent to + * registered listeners. + * + * @param ev + * the document event that records the changes to the document */ protected void removeUpdate(DefaultDocumentEvent ev) { @@ -1903,7 +2274,7 @@ public class DefaultStyledDocument extends AbstractDocument /** * Returns an enumeration of all style names. - * + * * @return an enumeration of all style names */ public Enumeration getStyleNames() @@ -1922,35 +2293,6 @@ public class DefaultStyledDocument extends AbstractDocument // Nothing to do here. This is intended to be overridden by subclasses. } - void printElements (Element start, int pad) - { - for (int i = 0; i < pad; i++) - System.out.print(" "); - if (pad == 0) - System.out.println ("ROOT ELEMENT ("+start.getStartOffset()+", "+start.getEndOffset()+")"); - else if (start instanceof AbstractDocument.BranchElement) - System.out.println ("BranchElement ("+start.getStartOffset()+", "+start.getEndOffset()+")"); - else - { - { - try - { - System.out.println ("LeafElement ("+start.getStartOffset()+", " - + start.getEndOffset()+"): "+ - start.getDocument(). - getText(start.getStartOffset(), - start.getEndOffset() - - start.getStartOffset())); - } - catch (BadLocationException ble) - { - } - } - } - for (int i = 0; i < start.getElementCount(); i ++) - printElements (start.getElement(i), pad+3); - } - /** * Inserts a bulk of structured content at once. * @@ -2012,20 +2354,66 @@ public class DefaultStyledDocument extends AbstractDocument /** * Initializes the DefaultStyledDocument with the specified * data. - * - * @param data the specification of the content with which the document is - * initialized + * + * @param data + * the specification of the content with which the document is + * initialized */ protected void create(ElementSpec[] data) { + writeLock(); try { - // Clear content. - content.remove(0, content.length()); - // Clear buffer and root element. - buffer = new ElementBuffer(createDefaultRoot()); - // Insert the data. - insert(0, data); + // Clear content if there is some. + int len = getLength(); + if (len > 0) + remove(0, len); + + // Now we insert the content. + StringBuilder b = new StringBuilder(); + for (int i = 0; i < data.length; ++i) + { + ElementSpec el = data[i]; + if (el.getArray() != null && el.getLength() > 0) + b.append(el.getArray(), el.getOffset(), el.getLength()); + } + Content content = getContent(); + UndoableEdit cEdit = content.insertString(0, b.toString()); + + DefaultDocumentEvent ev = + new DefaultDocumentEvent(0, b.length(), + DocumentEvent.EventType.INSERT); + ev.addEdit(cEdit); + + // We do a little trick here to get the new structure: We instantiate + // a new ElementBuffer with a new root element, insert into that root + // and then reparent the newly created elements to the old root + // element. + BranchElement createRoot = + (BranchElement) createBranchElement(null, null); + Element dummyLeaf = createLeafElement(createRoot, null, 0, 1); + createRoot.replace(0, 0, new Element[]{ dummyLeaf }); + ElementBuffer createBuffer = new ElementBuffer(createRoot); + createBuffer.insert(0, b.length(), data, new DefaultDocumentEvent(0, b.length(), DocumentEvent.EventType.INSERT)); + // Now the new root is the first child of the createRoot. + Element newRoot = createRoot.getElement(0); + BranchElement root = (BranchElement) getDefaultRootElement(); + Element[] added = new Element[newRoot.getElementCount()]; + for (int i = 0; i < added.length; ++i) + { + added[i] = newRoot.getElement(i); + ((AbstractElement) added[i]).element_parent = root; + } + Element[] removed = new Element[root.getElementCount()]; + for (int i = 0; i < removed.length; ++i) + removed[i] = root.getElement(i); + + // Replace the old elements in root with the new and update the event. + root.replace(0, removed.length, added); + ev.addEdit(new ElementEdit(root, 0, removed, added)); + + fireInsertUpdate(ev); + fireUndoableEditUpdate(new UndoableEditEvent(this, ev)); } catch (BadLocationException ex) { @@ -2033,10 +2421,9 @@ public class DefaultStyledDocument extends AbstractDocument err.initCause(ex); throw err; } - } - - static boolean attributeSetsAreSame (AttributeSet a, AttributeSet b) - { - return (a == null && b == null) || (a != null && a.isEqual(b)); + finally + { + writeUnlock(); + } } } diff --git a/javax/swing/text/DefaultTextUI.java b/javax/swing/text/DefaultTextUI.java index e7ff01845..c347668b9 100644 --- a/javax/swing/text/DefaultTextUI.java +++ b/javax/swing/text/DefaultTextUI.java @@ -45,6 +45,7 @@ import javax.swing.plaf.basic.BasicTextUI; * all text components is now {@link BasicTextUI}. * * @author Roman Kennke (kennke@aicas.com) + * @deprecated as of 1.5 use {@link BasicTextUI} instead */ public abstract class DefaultTextUI extends BasicTextUI { diff --git a/javax/swing/text/FlowView.java b/javax/swing/text/FlowView.java index 6d4b9cd31..219ab8ebe 100644 --- a/javax/swing/text/FlowView.java +++ b/javax/swing/text/FlowView.java @@ -38,14 +38,10 @@ exception statement from your version. */ package javax.swing.text; -import java.awt.Container; -import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; -import java.util.Iterator; -import java.util.Vector; -import javax.swing.SwingConstants; +import javax.swing.SizeRequirements; import javax.swing.event.DocumentEvent; /** @@ -89,7 +85,7 @@ public abstract class FlowView extends BoxView */ public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) { - layout(fv); + // The default implementation does nothing. } /** @@ -105,7 +101,7 @@ public abstract class FlowView extends BoxView */ public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) { - layout(fv); + // The default implementation does nothing. } /** @@ -121,7 +117,7 @@ public abstract class FlowView extends BoxView */ public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) { - layout(fv); + // The default implementation does nothing. } /** @@ -166,43 +162,57 @@ public abstract class FlowView extends BoxView * Lays out one row of the flow view. This is called by {@link #layout} * to fill one row with child views until the available span is exhausted. * + * The default implementation fills the row by calling + * {@link #createView(FlowView, int, int, int)} until the available space + * is exhausted, a forced break is encountered or there are no more views + * in the logical view. If the available space is exhausted, + * {@link #adjustRow(FlowView, int, int, int)} is called to fit the row + * into the available span. + * * @param fv the flow view for which we perform the layout * @param rowIndex the index of the row - * @param pos the start position for the row + * @param pos the model position for the beginning of the row * * @return the start position of the next row */ protected int layoutRow(FlowView fv, int rowIndex, int pos) { - int spanLeft = fv.getFlowSpan(rowIndex); - if (spanLeft <= 0) - return -1; - - int offset = pos; View row = fv.getView(rowIndex); - int flowAxis = fv.getFlowAxis(); + int axis = fv.getFlowAxis(); + int span = fv.getFlowSpan(rowIndex); + int x = fv.getFlowStart(rowIndex); + int offset = pos; + View logicalView = getLogicalView(fv); + // Special case when span == 0. We need to layout the row as if it had + // a span of Integer.MAX_VALUE. + if (span == 0) + span = Integer.MAX_VALUE; - while (spanLeft > 0) + while (span > 0) { - View child = createView(fv, offset, spanLeft, rowIndex); - if (child == null) - { - offset = -1; - break; - } - - int span = (int) child.getPreferredSpan(flowAxis); - if (span > spanLeft) - { - offset = -1; - break; - } - - row.append(child); - spanLeft -= span; - offset = child.getEndOffset(); + if (logicalView.getViewIndex(offset, Position.Bias.Forward) == -1) + break; + View view = createView(fv, offset, span, rowIndex); + if (view == null) + break; + int viewSpan = (int) view.getPreferredSpan(axis); + row.append(view); + int breakWeight = view.getBreakWeight(axis, x, span); + if (breakWeight >= View.ForcedBreakWeight) + break; + x += viewSpan; + span -= viewSpan; + offset += (view.getEndOffset() - view.getStartOffset()); } - return offset; + if (span < 0) + { + int flowStart = fv.getFlowStart(axis); + int flowSpan = fv.getFlowSpan(axis); + adjustRow(fv, rowIndex, flowSpan, flowStart); + int rowViewCount = row.getViewCount(); + offset = row.getView(rowViewCount - 1).getEndOffset(); + } + return offset != pos ? offset : -1; } /** @@ -212,189 +222,106 @@ public abstract class FlowView extends BoxView * available span and can be broken down) or null (if it does * not fit in the available span and also cannot be broken down). * + * The default implementation fetches the logical view at the specified + * startOffset. If that view has a different startOffset than + * specified in the argument, a fragment is created using + * {@link View#createFragment(int, int)} that has the correct startOffset + * and the logical view's endOffset. + * * @param fv the flow view - * @param offset the start offset for the view to be created + * @param startOffset the start offset for the view to be created * @param spanLeft the available span * @param rowIndex the index of the row * * @return a view to fill the row with, or null if there * is no view or view fragment that fits in the available span */ - protected View createView(FlowView fv, int offset, int spanLeft, + protected View createView(FlowView fv, int startOffset, int spanLeft, int rowIndex) { - // Find the logical element for the given offset. - View logicalView = getLogicalView(fv); - - int viewIndex = logicalView.getViewIndex(offset, Position.Bias.Forward); - if (viewIndex == -1) - return null; - - View child = logicalView.getView(viewIndex); - int flowAxis = fv.getFlowAxis(); - int span = (int) child.getPreferredSpan(flowAxis); - - if (span <= spanLeft) - return child; - else if (child.getBreakWeight(flowAxis, offset, spanLeft) - > BadBreakWeight) - // FIXME: What to do with the pos parameter here? - return child.breakView(flowAxis, offset, 0, spanLeft); - else - return null; - } - } - - /** - * This special subclass of View is used to represent - * the logical representation of this view. It does not support any - * visual representation, this is handled by the physical view implemented - * in the FlowView. - */ - class LogicalView extends View - { - /** - * The child views of this logical view. - */ - Vector children; - - /** - * Creates a new LogicalView instance. - */ - LogicalView(Element el) - { - super(el); - children = new Vector(); - } - - /** - * Returns the container that holds this view. The logical view returns - * the enclosing FlowView's container here. - * - * @return the container that holds this view - */ - public Container getContainer() - { - return FlowView.this.getContainer(); - } - - /** - * Returns the number of child views of this logical view. - * - * @return the number of child views of this logical view - */ - public int getViewCount() - { - return children.size(); - } - - /** - * Returns the child view at the specified index. - * - * @param index the index - * - * @return the child view at the specified index - */ - public View getView(int index) - { - return (View) children.get(index); - } - - /** - * Replaces some child views with other child views. - * - * @param offset the offset at which to replace child views - * @param length the number of children to remove - * @param views the views to be inserted - */ - public void replace(int offset, int length, View[] views) - { - if (length > 0) - { - for (int count = 0; count < length; ++count) - children.remove(offset); - } - - int endOffset = offset + views.length; - for (int i = offset; i < endOffset; ++i) - { - children.add(i, views[i - offset]); - // Set the parent of the child views to the flow view itself so - // it has something to resolve. - views[i - offset].setParent(FlowView.this); - } + View logicalView = getLogicalView(fv); + // FIXME: Handle the bias thing correctly. + int index = logicalView.getViewIndex(startOffset, Position.Bias.Forward); + View retVal = null; + if (index >= 0) + { + retVal = logicalView.getView(index); + if (retVal.getStartOffset() != startOffset) + retVal = retVal.createFragment(startOffset, retVal.getEndOffset()); + } + return retVal; } /** - * Returns the index of the child view that contains the specified - * position in the document model. + * Tries to adjust the specified row to fit within the desired span. The + * default implementation iterates through the children of the specified + * row to find the view that has the highest break weight and - if there + * is more than one view with such a break weight - which is nearest to + * the end of the row. If there is such a view that has a break weight > + * {@link View#BadBreakWeight}, this view is broken using the + * {@link View#breakView(int, int, float, float)} method and this view and + * all views after the now broken view are replaced by the broken view. * - * @param pos the position for which we are searching the child view - * @param b the bias - * - * @return the index of the child view that contains the specified - * position in the document model + * @param fv the flow view + * @param rowIndex the index of the row to be adjusted + * @param desiredSpan the layout span + * @param x the X location at which the row starts */ - public int getViewIndex(int pos, Position.Bias b) - { - int index = -1; - int i = 0; - for (Iterator it = children.iterator(); it.hasNext(); i++) + protected void adjustRow(FlowView fv, int rowIndex, int desiredSpan, int x) { + // Determine the last view that has the highest break weight. + int axis = fv.getFlowAxis(); + View row = fv.getView(rowIndex); + int count = row.getViewCount(); + int breakIndex = -1; + int maxBreakWeight = View.BadBreakWeight; + int breakX = x; + int breakSpan = desiredSpan; + int currentX = x; + int currentSpan = desiredSpan; + for (int i = 0; i < count; ++i) { - View child = (View) it.next(); - if (child.getStartOffset() >= pos - && child.getEndOffset() < pos) + View view = row.getView(i); + int weight = view.getBreakWeight(axis, currentX, currentSpan); + if (weight >= maxBreakWeight) { - index = i; - break; + breakIndex = i; + breakX = currentX; + breakSpan = currentSpan; + maxBreakWeight = weight; } + int size = (int) view.getPreferredSpan(axis); + currentX += size; + currentSpan -= size; } - return index; - } - /** - * Throws an AssertionError because it must never be called. LogicalView - * only serves as a holder for child views and has no visual - * representation. - */ - public float getPreferredSpan(int axis) - { - throw new AssertionError("This method must not be called in " - + "LogicalView."); - } - - /** - * Throws an AssertionError because it must never be called. LogicalView - * only serves as a holder for child views and has no visual - * representation. - */ - public Shape modelToView(int pos, Shape a, Position.Bias b) - throws BadLocationException - { - throw new AssertionError("This method must not be called in " - + "LogicalView."); - } - - /** - * Throws an AssertionError because it must never be called. LogicalView - * only serves as a holder for child views and has no visual - * representation. - */ - public void paint(Graphics g, Shape s) - { - throw new AssertionError("This method must not be called in " - + "LogicalView."); + // If there is a potential break location found, break the row at + // this location. + if (breakIndex > -1) + { + View toBeBroken = row.getView(breakIndex); + View brokenView = toBeBroken.breakView(axis, + toBeBroken.getStartOffset(), + breakX, breakSpan); + row.replace(breakIndex, count - breakIndex, + new View[]{brokenView}); + } } + } + /** + * This special subclass of View is used to represent + * the logical representation of this view. It does not support any + * visual representation, this is handled by the physical view implemented + * in the FlowView. + */ + class LogicalView extends BoxView + { /** - * Throws an AssertionError because it must never be called. LogicalView - * only serves as a holder for child views and has no visual - * representation. + * Creates a new LogicalView instance. */ - public int viewToModel(float x, float y, Shape a, Position.Bias[] b) + LogicalView(Element el, int axis) { - throw new AssertionError("This method must not be called in " - + "LogicalView."); + super(el, axis); } } @@ -423,6 +350,11 @@ public abstract class FlowView extends BoxView */ protected FlowStrategy strategy; + /** + * Indicates if the flow should be rebuild during the next layout. + */ + private boolean layoutDirty; + /** * Creates a new FlowView for the given * Element and axis. @@ -436,6 +368,7 @@ public abstract class FlowView extends BoxView { super(element, axis); strategy = sharedStrategy; + layoutDirty = true; } /** @@ -510,16 +443,8 @@ public abstract class FlowView extends BoxView { if (layoutPool == null) { - layoutPool = new LogicalView(getElement()); - - Element el = getElement(); - int count = el.getElementCount(); - for (int i = 0; i < count; ++i) - { - Element childEl = el.getElement(i); - View childView = vf.create(childEl); - layoutPool.append(childView); - } + layoutPool = new LogicalView(getElement(), getAxis()); + layoutPool.setParent(this); } } @@ -534,27 +459,32 @@ public abstract class FlowView extends BoxView */ protected void layout(int width, int height) { - boolean rebuild = false; - int flowAxis = getFlowAxis(); if (flowAxis == X_AXIS) { - rebuild = !(width == layoutSpan); - layoutSpan = width; + if (layoutSpan != width) + { + layoutChanged(Y_AXIS); + layoutSpan = width; + } } else { - rebuild = !(height == layoutSpan); - layoutSpan = height; + if (layoutSpan != height) + { + layoutChanged(X_AXIS); + layoutSpan = height; + } } - if (rebuild) - strategy.layout(this); + if (layoutDirty) + { + strategy.layout(this); + layoutDirty = false; + } - // TODO: If the span along the box axis has changed in the process of - // relayouting the rows (that is, if rows have been added or removed), - // call preferenceChanged in order to throw away cached layout information - // of the surrounding BoxView. + if (getPreferredSpan(getAxis()) != height) + preferenceChanged(this, false, true); super.layout(width, height); } @@ -574,6 +504,7 @@ public abstract class FlowView extends BoxView // be updated accordingly. layoutPool.insertUpdate(changes, a, vf); strategy.insertUpdate(this, changes, getInsideAllocation(a)); + layoutDirty = true; } /** @@ -588,6 +519,7 @@ public abstract class FlowView extends BoxView public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory vf) { strategy.removeUpdate(this, changes, getInsideAllocation(a)); + layoutDirty = true; } /** @@ -602,6 +534,7 @@ public abstract class FlowView extends BoxView public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory vf) { strategy.changedUpdate(this, changes, getInsideAllocation(a)); + layoutDirty = true; } /** @@ -640,4 +573,30 @@ public abstract class FlowView extends BoxView } return result; } + + /** + * Calculates the size requirements of this BoxView along + * its minor axis, that is the axis opposite to the axis specified in the + * constructor. + * + * This is overridden and forwards the request to the logical view. + * + * @param axis the axis that is examined + * @param r the SizeRequirements object to hold the result, + * if null, a new one is created + * + * @return the size requirements for this BoxView along + * the specified axis + */ + protected SizeRequirements calculateMinorAxisRequirements(int axis, + SizeRequirements r) + { + // We need to call super here so that the alignment is properly + // calculated. + SizeRequirements res = super.calculateMinorAxisRequirements(axis, r); + res.minimum = (int) layoutPool.getMinimumSpan(axis); + res.preferred = (int) layoutPool.getPreferredSpan(axis); + res.maximum = (int) layoutPool.getMaximumSpan(axis); + return res; + } } diff --git a/javax/swing/text/GapContent.java b/javax/swing/text/GapContent.java index cce7a8a27..fb67ebd2a 100644 --- a/javax/swing/text/GapContent.java +++ b/javax/swing/text/GapContent.java @@ -1,5 +1,5 @@ /* GapContent.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,8 +39,10 @@ exception statement from your version. */ package javax.swing.text; import java.io.Serializable; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.ListIterator; import java.util.Vector; @@ -68,8 +70,8 @@ public class GapContent /** * A {@link Position} implementation for GapContent. */ - class GapContentPosition - implements Position, Comparable + private class GapContentPosition + implements Position, Comparable { /** The index within the buffer array. */ @@ -123,15 +125,14 @@ public class GapContent assert mark <= gapStart || mark >= gapEnd : "mark: " + mark + ", gapStart: " + gapStart + ", gapEnd: " + gapEnd; - - if (mark <= gapEnd) + if (mark <= gapStart) return mark; else return mark - (gapEnd - gapStart); } } - class InsertUndo extends AbstractUndoableEdit + private class InsertUndo extends AbstractUndoableEdit { public int where, length; String text; @@ -170,7 +171,7 @@ public class GapContent } - class UndoRemove extends AbstractUndoableEdit + private class UndoRemove extends AbstractUndoableEdit { public int where; String text; @@ -207,7 +208,41 @@ public class GapContent } } - + + /** + * Compares WeakReference objects in a List by comparing the referenced + * objects instead. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class WeakPositionComparator + implements Comparator + { + + /** + * Compares two objects of type WeakReference. The objects are compared + * using the referenced objects compareTo() method. + */ + public int compare(Object o1, Object o2) + { + // Unwrap references. + if (o1 instanceof WeakReference) + o1 = ((WeakReference) o1).get(); + if (o2 instanceof WeakReference) + o2 = ((WeakReference) o2).get(); + + GapContentPosition p1 = (GapContentPosition) o1; + GapContentPosition p2 = (GapContentPosition) o2; + + int retVal; + if (p1 == null || p2 == null) + retVal = -1; + else + retVal = p1.compareTo(p2); + return retVal; + } + } + /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = -6226052713477823730L; @@ -234,9 +269,10 @@ public class GapContent /** * The positions generated by this GapContent. They are kept in an ordered - * fashion, so they can be looked up easily. + * fashion, so they can be looked up easily. The value objects will be + * WeakReference objects that in turn hold GapContentPosition objects. */ - ArrayList positions; + private ArrayList positions; /** * Creates a new GapContent object. @@ -447,18 +483,22 @@ public class GapContent throw new BadLocationException("The offset was out of the bounds of this" + " buffer", offset); + clearPositionReferences(); + // We store the actual array index in the GapContentPosition. The real // offset is then calculated in the GapContentPosition. int mark = offset; if (offset >= gapStart) mark += gapEnd - gapStart; GapContentPosition pos = new GapContentPosition(mark); + WeakReference r = new WeakReference(pos); // Add this into our list in a sorted fashion. - int index = Collections.binarySearch(positions, pos); + int index = Collections.binarySearch(positions, r, + new WeakPositionComparator()); if (index < 0) index = -(index + 1); - positions.add(index, pos); + positions.add(index, r); return pos; } @@ -558,7 +598,7 @@ public class GapContent assert newGapEnd > gapEnd : "The new gap end must be greater than the " + "old gap end."; - setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd + 1); + setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd); gapEnd = newGapEnd; } @@ -643,19 +683,30 @@ public class GapContent int endOffset = offset + length; int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset)); + new GapContentPosition(offset), + new WeakPositionComparator()); if (index1 < 0) index1 = -(index1 + 1); // Search the first index with the specified offset. The binarySearch does // not necessarily find the first one. - while (index1 > 0 - && ((GapContentPosition) positions.get(index1 - 1)).mark == offset) - index1--; + while (index1 > 0) + { + WeakReference r = (WeakReference) positions.get(index1 - 1); + GapContentPosition p = (GapContentPosition) r.get(); + if (p != null && p.mark == offset || p == null) + index1--; + else + break; + } for (ListIterator i = positions.listIterator(index1); i.hasNext();) { - GapContentPosition p = (GapContentPosition) i.next(); + WeakReference r = (WeakReference) i.next(); + GapContentPosition p = (GapContentPosition) r.get(); + if (p == null) + continue; + if (p.mark > endOffset) break; if (p.mark >= offset && p.mark <= endOffset) @@ -673,24 +724,35 @@ public class GapContent * @param length the length of the range to search * @param value the new value for each mark */ - void setPositionsInRange(int offset, int length, int value) + private void setPositionsInRange(int offset, int length, int value) { int endOffset = offset + length; int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset)); + new GapContentPosition(offset), + new WeakPositionComparator()); if (index1 < 0) index1 = -(index1 + 1); // Search the first index with the specified offset. The binarySearch does // not necessarily find the first one. - while (index1 > 0 - && ((GapContentPosition) positions.get(index1 - 1)).mark == offset) - index1--; + while (index1 > 0) + { + WeakReference r = (WeakReference) positions.get(index1 - 1); + GapContentPosition p = (GapContentPosition) r.get(); + if (p != null && p.mark == offset || p == null) + index1--; + else + break; + } for (ListIterator i = positions.listIterator(index1); i.hasNext();) { - GapContentPosition p = (GapContentPosition) i.next(); + WeakReference r = (WeakReference) i.next(); + GapContentPosition p = (GapContentPosition) r.get(); + if (p == null) + continue; + if (p.mark > endOffset) break; @@ -708,23 +770,35 @@ public class GapContent * @param length the length of the range to search * @param incr the increment */ - void adjustPositionsInRange(int offset, int length, int incr) + private void adjustPositionsInRange(int offset, int length, int incr) { int endOffset = offset + length; int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset)); + new GapContentPosition(offset), + new WeakPositionComparator()); if (index1 < 0) index1 = -(index1 + 1); // Search the first index with the specified offset. The binarySearch does // not necessarily find the first one. - while (index1 > 0 - && ((GapContentPosition) positions.get(index1 - 1)).mark == offset) - index1--; + while (index1 > 0) + { + WeakReference r = (WeakReference) positions.get(index1 - 1); + GapContentPosition p = (GapContentPosition) r.get(); + if (p != null && p.mark == offset || p == null) + index1--; + else + break; + } + for (ListIterator i = positions.listIterator(index1); i.hasNext();) { - GapContentPosition p = (GapContentPosition) i.next(); + WeakReference r = (WeakReference) i.next(); + GapContentPosition p = (GapContentPosition) r.get(); + if (p == null) + continue; + if (p.mark > endOffset) break; @@ -747,6 +821,17 @@ public class GapContent setPositionsInRange(gapEnd, 0, 0); } + /** + * @specnote This method is not very well specified and the positions vector + * is implementation specific. The undo positions are managed + * differently in this implementation, this method is only here + * for binary compatibility. + */ + protected void updateUndoPositions(Vector positions, int offset, int length) + { + // We do nothing here. + } + /** * Outputs debugging info to System.err. It prints out the buffer array, * the gapStart is marked by a < sign, the gapEnd is marked by a > @@ -777,8 +862,23 @@ public class GapContent { for (Iterator i = positions.iterator(); i.hasNext();) { - GapContentPosition pos = (GapContentPosition) i.next(); + WeakReference r = (WeakReference) i.next(); + GapContentPosition pos = (GapContentPosition) r.get(); System.err.println("position at: " + pos.mark); } } + + /** + * Clears all GC'ed references in the positions array. + */ + private void clearPositionReferences() + { + Iterator i = positions.iterator(); + while (i.hasNext()) + { + WeakReference r = (WeakReference) i.next(); + if (r.get() == null) + i.remove(); + } + } } diff --git a/javax/swing/text/GlyphView.java b/javax/swing/text/GlyphView.java index 47deb50d0..d505274c9 100644 --- a/javax/swing/text/GlyphView.java +++ b/javax/swing/text/GlyphView.java @@ -277,38 +277,41 @@ public class GlyphView extends View implements TabableView, Cloneable public void paint(GlyphView view, Graphics g, Shape a, int p0, int p1) { + Color oldColor = g.getColor(); int height = (int) getHeight(view); Segment txt = view.getText(p0, p1); Rectangle bounds = a.getBounds(); - TabExpander tabEx = null; View parent = view.getParent(); if (parent instanceof TabExpander) tabEx = (TabExpander) parent; - // Fill the background of the text run. - Color background = view.getBackground(); - g.setColor(background); int width = Utilities.getTabbedTextWidth(txt, g.getFontMetrics(), bounds.x, tabEx, txt.offset); - g.fillRect(bounds.x, bounds.y, width, height); - + // Fill the background of the text run. + Color background = view.getBackground(); + if (background != null) + { + g.setColor(background); + g.fillRect(bounds.x, bounds.y, width, height); + } // Draw the actual text. g.setColor(view.getForeground()); g.setFont(view.getFont()); + int ascent = g.getFontMetrics().getAscent(); if (view.isSuperscript()) // TODO: Adjust font for superscripting. - Utilities.drawTabbedText(txt, bounds.x, bounds.y - height / 2, g, tabEx, - txt.offset); + Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent - height / 2, + g, tabEx, txt.offset); else if (view.isSubscript()) // TODO: Adjust font for subscripting. - Utilities.drawTabbedText(txt, bounds.x, bounds.y + height / 2, g, tabEx, - txt.offset); + Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent + height / 2, + g, tabEx, txt.offset); else - Utilities.drawTabbedText(txt, bounds.x, bounds.y, g, tabEx, + Utilities.drawTabbedText(txt, bounds.x, bounds.y + ascent, g, tabEx, txt.offset); - if (view.isStikeThrough()) + if (view.isStrikeThrough()) { int strikeHeight = (int) (getAscent(view) / 2); g.drawLine(bounds.x, bounds.y + strikeHeight, bounds.height + width, @@ -320,6 +323,7 @@ public class GlyphView extends View implements TabableView, Cloneable g.drawLine(bounds.x, bounds.y + lineHeight, bounds.height + width, bounds.y + lineHeight); } + g.setColor(oldColor); } /** @@ -470,12 +474,12 @@ public class GlyphView extends View implements TabableView, Cloneable /** * The start offset within the document for this view. */ - int startOffset; + private int startOffset; /** * The end offset within the document for this view. */ - int endOffset; + private int endOffset; /** * Creates a new GlyphView for the given Element. @@ -485,8 +489,8 @@ public class GlyphView extends View implements TabableView, Cloneable public GlyphView(Element element) { super(element); - startOffset = element.getStartOffset(); - endOffset = element.getEndOffset(); + startOffset = -1; + endOffset = -1; } /** @@ -534,8 +538,7 @@ public class GlyphView extends View implements TabableView, Cloneable { Element el = getElement(); checkPainter(); - getGlyphPainter().paint(this, g, a, el.getStartOffset(), - el.getEndOffset()); + getGlyphPainter().paint(this, g, a, getStartOffset(), getEndOffset()); } @@ -563,7 +566,8 @@ public class GlyphView extends View implements TabableView, Cloneable tabEx, 0.F); } else - span = painter.getHeight(this); + span = painter.getHeight(this); + return span; } @@ -682,7 +686,10 @@ public class GlyphView extends View implements TabableView, Cloneable */ public int getStartOffset() { - return startOffset; + int start = startOffset; + if (start < 0) + start = super.getStartOffset(); + return start; } /** @@ -694,7 +701,10 @@ public class GlyphView extends View implements TabableView, Cloneable */ public int getEndOffset() { - return endOffset; + int end = endOffset; + if (end < 0) + end = super.getEndOffset(); + return end; } /** @@ -771,7 +781,11 @@ public class GlyphView extends View implements TabableView, Cloneable { Element el = getElement(); AttributeSet atts = el.getAttributes(); - return StyleConstants.getBackground(atts); + // We cannot use StyleConstants.getBackground() here, because that returns + // BLACK as default (when background == null). What we need is the + // background setting of the text component instead, which is what we get + // when background == null anyway. + return (Color) atts.getAttribute(StyleConstants.Background); } /** @@ -782,7 +796,7 @@ public class GlyphView extends View implements TabableView, Cloneable * * @return whether the text should be rendered strike-through or not */ - public boolean isStikeThrough() + public boolean isStrikeThrough() { Element el = getElement(); AttributeSet atts = el.getAttributes(); @@ -876,13 +890,15 @@ public class GlyphView extends View implements TabableView, Cloneable checkPainter(); GlyphPainter painter = getGlyphPainter(); - int breakLocation = painter.getBoundedPosition(this, p0, pos, len); + // Try to find a suitable line break. BreakIterator lineBreaker = BreakIterator.getLineInstance(); Segment txt = new Segment(); try { - getDocument().getText(getStartOffset(), getEndOffset(), txt); + int start = getStartOffset(); + int length = getEndOffset() - start; + getDocument().getText(start, length, txt); } catch (BadLocationException ex) { @@ -891,11 +907,10 @@ public class GlyphView extends View implements TabableView, Cloneable err.initCause(ex); throw err; } - lineBreaker.setText(txt); - int goodBreakLocation = lineBreaker.previous(); - if (goodBreakLocation != BreakIterator.DONE) - breakLocation = goodBreakLocation; - + int breakLocation = + Utilities.getBreakLocation(txt, getContainer().getFontMetrics(getFont()), + (int) pos, (int) (pos + len), + getTabExpander(), p0); View brokenView = createFragment(p0, breakLocation); return brokenView; } @@ -922,23 +937,24 @@ public class GlyphView extends View implements TabableView, Cloneable weight = super.getBreakWeight(axis, pos, len); else { - // Determine the model locations at pos and pos + len. - int spanX = (int) getPreferredSpan(X_AXIS); - int spanY = (int) getPreferredSpan(Y_AXIS); - Rectangle dummyAlloc = new Rectangle(0, 0, spanX, spanY); - Position.Bias[] biasRet = new Position.Bias[1]; - int offset1 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet); - int offset2 = viewToModel(pos, spanY / 2, dummyAlloc, biasRet); - Segment txt = getText(offset1, offset2); - BreakIterator lineBreaker = BreakIterator.getLineInstance(); - lineBreaker.setText(txt); - int breakLoc = lineBreaker.previous(); - if (breakLoc == offset1) - weight = View.BadBreakWeight; - else if(breakLoc == BreakIterator.DONE) - weight = View.GoodBreakWeight; - else - weight = View.ExcellentBreakWeight; + // FIXME: Commented out because the Utilities.getBreakLocation method + // is still buggy. The GoodBreakWeight is a reasonable workaround for + // now. +// int startOffset = getStartOffset(); +// int endOffset = getEndOffset() - 1; +// Segment s = getText(startOffset, endOffset); +// Container c = getContainer(); +// FontMetrics fm = c.getFontMetrics(c.getFont()); +// int x0 = (int) pos; +// int x = (int) (pos + len); +// int breakLoc = Utilities.getBreakLocation(s, fm, x0, x, +// getTabExpander(), +// startOffset); +// if (breakLoc == startOffset || breakLoc == endOffset) +// weight = GoodBreakWeight; +// else +// weight = ExcellentBreakWeight; + weight = GoodBreakWeight; } return weight; } @@ -955,14 +971,14 @@ public class GlyphView extends View implements TabableView, Cloneable */ public void changedUpdate(DocumentEvent e, Shape a, ViewFactory vf) { - getParent().preferenceChanged(this, true, true); + preferenceChanged(this, true, true); } /** * Receives notification that some text has been inserted within the * text fragment that this view is responsible for. This calls - * {@link View#preferenceChanged(View, boolean, boolean)} on the parent for - * width. + * {@link View#preferenceChanged(View, boolean, boolean)} for the + * direction in which the glyphs are rendered. * * @param e the document event describing the change; not used here * @param a the view allocation on screen; not used here @@ -970,7 +986,7 @@ public class GlyphView extends View implements TabableView, Cloneable */ public void insertUpdate(DocumentEvent e, Shape a, ViewFactory vf) { - getParent().preferenceChanged(this, true, false); + preferenceChanged(this, true, false); } /** @@ -985,7 +1001,7 @@ public class GlyphView extends View implements TabableView, Cloneable */ public void removeUpdate(DocumentEvent e, Shape a, ViewFactory vf) { - getParent().preferenceChanged(this, true, false); + preferenceChanged(this, true, false); } /** @@ -1000,8 +1016,10 @@ public class GlyphView extends View implements TabableView, Cloneable public View createFragment(int p0, int p1) { GlyphView fragment = (GlyphView) clone(); - fragment.startOffset = p0; - fragment.endOffset = p1; + if (p0 != getStartOffset()) + fragment.startOffset = p0; + if (p1 != getEndOffset()) + fragment.endOffset = p1; return fragment; } diff --git a/javax/swing/text/IconView.java b/javax/swing/text/IconView.java index af2581a88..699cda90e 100644 --- a/javax/swing/text/IconView.java +++ b/javax/swing/text/IconView.java @@ -130,8 +130,6 @@ public class IconView throws BadLocationException { Element el = getElement(); - if (pos < el.getStartOffset() || pos >= el.getEndOffset()) - throw new BadLocationException("Illegal offset for this view", pos); Rectangle r = a.getBounds(); Icon icon = StyleConstants.getIcon(el.getAttributes()); return new Rectangle(r.x, r.y, icon.getIconWidth(), icon.getIconHeight()); diff --git a/javax/swing/text/JTextComponent.java b/javax/swing/text/JTextComponent.java index afa1f24a6..b23c53413 100644 --- a/javax/swing/text/JTextComponent.java +++ b/javax/swing/text/JTextComponent.java @@ -60,7 +60,9 @@ import java.util.Enumeration; import java.util.Hashtable; import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleEditableText; import javax.accessibility.AccessibleRole; import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleText; @@ -86,200 +88,415 @@ public abstract class JTextComponent extends JComponent implements Scrollable, Accessible { /** - * AccessibleJTextComponent + * This class implements accessibility support for the JTextComponent class. + * It provides an implementation of the Java Accessibility API appropriate + * to menu user-interface elements. */ - // FIXME: This inner class is a complete stub and needs to be implemented. - public class AccessibleJTextComponent extends AccessibleJComponent - implements AccessibleText, CaretListener, DocumentListener + public class AccessibleJTextComponent extends AccessibleJComponent implements + AccessibleText, CaretListener, DocumentListener, AccessibleAction, + AccessibleEditableText { private static final long serialVersionUID = 7664188944091413696L; + /** The caret's offset. */ + int dot = 0; + + /** The current JTextComponent. */ + JTextComponent textComp = JTextComponent.this; + /** - * Constructor AccessibleJTextComponent + * Constructs an AccessibleJTextComponent. + * Adds a listener to track caret change. */ public AccessibleJTextComponent() { - // Nothing to do here. + super(); + textComp.addCaretListener(this); } /** - * getCaretPosition - * @return int + * Returns the zero-based offset of the caret. Note: The character + * to the right of the caret will have the same index value as the + * offset (the caret is between two characters). + * + * @return offset of caret */ public int getCaretPosition() { - return 0; // TODO + dot = textComp.getCaretPosition(); + return dot; } /** - * getSelectedText - * @return String + * Returns the portion of the text that is selected. + * + * @return null if no text is selected. */ public String getSelectedText() { - return null; // TODO + return textComp.getSelectedText(); } /** - * getSelectionStart - * @return int + * Returns the start offset within the selected text. If there is no + * selection, but there is a caret, the start and end offsets will be + * the same. Return 0 if the text is empty, or the caret position if no selection. + * + * @return index of the start of the text >= 0. */ public int getSelectionStart() { - return 0; // TODO + if (getSelectedText() == null || (textComp.getText().equals(""))) + return 0; + return textComp.getSelectionStart(); } /** - * getSelectionEnd - * @return int + * Returns the end offset within the selected text. If there is no + * selection, but there is a caret, the start and end offsets will + * be the same. Return 0 if the text is empty, or the caret position + * if no selection. + * + * @return index of the end of the text >= 0. */ public int getSelectionEnd() { - return 0; // TODO + if (getSelectedText() == null || (textComp.getText().equals(""))) + return 0; + return textComp.getSelectionEnd(); } /** - * caretUpdate - * @param value0 TODO + * Handles caret updates (fire appropriate property change event, which are + * AccessibleContext.ACCESSIBLE_CARET_PROPERTY and + * AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY). This keeps track of + * the dot position internally. When the caret moves, the internal position + * is updated after firing the event. + * + * @param e - caret event */ - public void caretUpdate(CaretEvent value0) + public void caretUpdate(CaretEvent e) { - // TODO + // TODO: fire appropriate event. + dot = e.getDot(); } /** - * getAccessibleStateSet - * @return AccessibleStateSet + * Returns the accessible state set of this component. + * + * @return the accessible state set of this component */ public AccessibleStateSet getAccessibleStateSet() { - return null; // TODO + AccessibleStateSet state = super.getAccessibleStateSet(); + // TODO: Figure out what state must be added here to the super's state. + return state; } /** - * getAccessibleRole - * @return AccessibleRole + * Returns the accessible role of this component. + * + * @return the accessible role of this component + * + * @see AccessibleRole */ public AccessibleRole getAccessibleRole() { - return null; // TODO + return AccessibleRole.TEXT; } /** - * getAccessibleText - * @return AccessibleText + * Returns the AccessibleEditableText interface for this text component. + * + * @return this + */ + public AccessibleEditableText getAccessibleEditableText() + { + return this; + } + + /** + * Get the AccessibleText associated with this object. In the implementation + * of the Java Accessibility API for this class, return this object, + * which is responsible for implementing the AccessibleText interface on + * behalf of itself. + * + * @return this + * + * @see AccessibleText */ public AccessibleText getAccessibleText() { - return null; // TODO + return this; } - + /** - * insertUpdate - * @param value0 TODO + * Insert update. Fire appropriate property change event which + * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY. + * + * @param e - document event */ - public void insertUpdate(DocumentEvent value0) + public void insertUpdate(DocumentEvent e) { // TODO } /** - * removeUpdate - * @param value0 TODO + * Remove update. Fire appropriate property change event which + * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY. + * + * @param e - document event */ - public void removeUpdate(DocumentEvent value0) + public void removeUpdate(DocumentEvent e) { // TODO } /** - * changedUpdate - * @param value0 TODO + * Changed update. Fire appropriate property change event which + * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY. + * + * @param e - document event */ - public void changedUpdate(DocumentEvent value0) + public void changedUpdate(DocumentEvent e) { // TODO } /** - * getIndexAtPoint - * @param value0 TODO - * @return int + * Given a point in the coordinate system of this object, return the + * 0-based index of the character at that point, or -1 if there is none. + * + * @param p the point to look at + * @return the character index, or -1 */ - public int getIndexAtPoint(Point value0) + public int getIndexAtPoint(Point p) { return 0; // TODO } /** - * getRootEditorRect - * @return Rectangle + * Determines the bounding box of the indexed character. Returns an empty + * rectangle if the index is out of bounds. The bounds are returned in local coordinates. + * If the index is invalid a null rectangle is returned. The screen coordinates returned are + * "unscrolled coordinates" if the JTextComponent is contained in a JScrollPane in which + * case the resulting rectangle should be composed with the parent coordinates. + * Note: the JTextComponent must have a valid size (e.g. have been added to a parent + * container whose ancestor container is a valid top-level window) for this method to + * be able to return a meaningful (non-null) value. + * + * @param index the 0-based character index + * @return the bounding box, may be empty or null. */ - Rectangle getRootEditorRect() + public Rectangle getCharacterBounds(int index) { - return null; + return null; // TODO } /** - * getCharacterBounds - * @param value0 TODO - * @return Rectangle + * Return the number of characters. + * + * @return the character count */ - public Rectangle getCharacterBounds(int value0) + public int getCharCount() + { + return textComp.getText().length(); + } + + /** + * Returns the attributes of a character at an index, or null if the index + * is out of bounds. + * + * @param index the 0-based character index + * @return the character's attributes + */ + public AttributeSet getCharacterAttribute(int index) { return null; // TODO } /** - * getCharCount - * @return int + * Returns the section of text at the index, or null if the index or part + * is invalid. + * + * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE} + * @param index the 0-based character index + * @return the selection of text at that index, or null */ - public int getCharCount() + public String getAtIndex(int part, int index) { - return 0; // TODO + return null; // TODO } /** - * getCharacterAttribute - * @param value0 TODO - * @return AttributeSet + * Returns the section of text after the index, or null if the index or part + * is invalid. + * + * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE} + * @param index the 0-based character index + * @return the selection of text after that index, or null */ - public AttributeSet getCharacterAttribute(int value0) + public String getAfterIndex(int part, int index) { return null; // TODO } /** - * getAtIndex - * @param value0 TODO - * @param value1 TODO - * @return String + * Returns the section of text before the index, or null if the index or part + * is invalid. + * + * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE} + * @param index the 0-based character index + * @return the selection of text before that index, or null */ - public String getAtIndex(int value0, int value1) + public String getBeforeIndex(int part, int index) { return null; // TODO } + + /** + * Get the number possible actions for this object, with the zeroth + * representing the default action. + * + * @return the 0-based number of actions + */ + public int getAccessibleActionCount() + { + return 0; // TODO + } + + /** + * Get a description for the specified action. Returns null if out of + * bounds. + * + * @param i + * the action to describe, 0-based + * @return description of the action + */ + public String getAccessibleActionDescription(int i) + { + // TODO: Not implemented fully + return super.getAccessibleDescription(); + } + + /** + * Perform the specified action. Does nothing if out of bounds. + * + * @param i the action to perform, 0-based + * @return true if the action was performed + */ + public boolean doAccessibleAction(int i) + { + return false; // TODO + } + + /** + * Set the text contents to the given string. + * + * @param s the new text + */ + public void setTextContents(String s) + { + // TODO + } /** - * getAfterIndex - * @param value0 TODO - * @param value1 TODO - * @return String + * Inserts the given string at the specified location. + * + * @param index the index for insertion + * @param s the new text */ - public String getAfterIndex(int value0, int value1) + public void insertTextAtIndex(int index, String s) { - return null; // TODO + replaceText(index, index, s); } /** - * getBeforeIndex - * @param value0 TODO - * @param value1 TODO - * @return String + * Return the text between two points. + * + * @param start the start position, inclusive + * @param end the end position, exclusive */ - public String getBeforeIndex(int value0, int value1) + public String getTextRange(int start, int end) { - return null; // TODO + try + { + return textComp.getText(start, end - start); + } + catch (BadLocationException ble) + { + return ""; + } + } + + /** + * Delete the text between two points. + * + * @param start the start position, inclusive + * @param end the end position, exclusive + */ + public void delete(int start, int end) + { + replaceText(start, end, ""); + } + + /** + * Cut the text between two points to the system clipboard. + * + * @param start the start position, inclusive + * @param end the end position, exclusive + */ + public void cut(int start, int end) + { + textComp.select(start, end); + textComp.cut(); + } + + /** + * Paste the text from the system clipboard at the given index. + * + * @param start the start position + */ + public void paste(int start) + { + textComp.setCaretPosition(start); + textComp.paste(); + } + + /** + * Replace the text between two points with the given string. + * + * @param start the start position, inclusive + * @param end the end position, exclusive + * @param s the string to paste + */ + public void replaceText(int start, int end, String s) + { + textComp.select(start, end); + textComp.replaceSelection(s); + } + + /** + * Select the text between two points. + * + * @param start the start position, inclusive + * @param end the end position, exclusive + */ + public void selectText(int start, int end) + { + textComp.select(start, end); + } + + /** + * Set the attributes of text between two points. + * + * @param start the start position, inclusive + * @param end the end position, exclusive + * @param s the new attribute set for the range + */ + public void setAttributes(int start, int end, AttributeSet s) + { + // TODO } } @@ -945,7 +1162,7 @@ public abstract class JTextComponent extends JComponent */ public AccessibleContext getAccessibleContext() { - return null; + return new AccessibleJTextComponent(); } public void setMargin(Insets m) @@ -1024,9 +1241,15 @@ public abstract class JTextComponent extends JComponent */ public String getSelectedText() { + int start = getSelectionStart(); + int offset = getSelectionEnd() - start; + + if (offset <= 0) + return null; + try { - return doc.getText(getSelectionStart(), getSelectionEnd()); + return doc.getText(start, offset); } catch (BadLocationException e) { @@ -1375,8 +1598,12 @@ public abstract class JTextComponent extends JComponent // Insert new text. doc.insertString(start, content, null); - // Set dot to new position. - setCaretPosition(start + content.length()); + // Set dot to new position, + dot = start + content.length(); + setCaretPosition(dot); + + // and update it's magic position. + caret.setMagicCaretPosition(modelToView(dot).getLocation()); } catch (BadLocationException e) { diff --git a/javax/swing/text/LabelView.java b/javax/swing/text/LabelView.java index 4890735b9..03279c4b2 100644 --- a/javax/swing/text/LabelView.java +++ b/javax/swing/text/LabelView.java @@ -109,7 +109,11 @@ public class LabelView extends GlyphView { Element el = getElement(); AttributeSet atts = el.getAttributes(); - background = StyleConstants.getBackground(atts); + // We cannot use StyleConstants.getBackground() here, because that returns + // BLACK as default (when background == null). What we need is the + // background setting of the text component instead, which is what we get + // when background == null anyway. + background = (Color) atts.getAttribute(StyleConstants.Background); foreground = StyleConstants.getForeground(atts); strikeThrough = StyleConstants.isStrikeThrough(atts); subscript = StyleConstants.isSubscript(atts); diff --git a/javax/swing/text/MutableAttributeSet.java b/javax/swing/text/MutableAttributeSet.java index 1eb92ebb4..5dd2406a3 100644 --- a/javax/swing/text/MutableAttributeSet.java +++ b/javax/swing/text/MutableAttributeSet.java @@ -1,5 +1,5 @@ /* MutableAttributeSet.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -40,46 +40,78 @@ package javax.swing.text; import java.util.Enumeration; /** - * MutableAttributeSet + * An {@link AttributeSet} that supports modification of the stored + * attributes. + * * @author Andrew Selkirk - * @version 1.0 + * @since 1.2 */ public interface MutableAttributeSet extends AttributeSet { /** - * addAttribute - * @param name TODO - * @param value TODO + * Adds an attribute with the given name and value + * to the set. If the set already contains an attribute with the given + * name, the attribute value is updated. + * + * @param name the attribute name (null not permitted). + * @param value the value (null not permitted). + * + * @throws NullPointerException if either argument is null. */ void addAttribute(Object name, Object value); /** - * addAttributes - * @param attributes TODO + * Adds all the attributes from attributes to this set. + * + * @param attributes the set of attributes to add (null not + * permitted). + * + * @throws NullPointerException if attributes is + * null. */ void addAttributes(AttributeSet attributes); /** - * removeAttribute - * @param name TODO + * Removes the attribute with the specified name, if this + * attribute is defined. This method will only remove an attribute from + * this set, not from the resolving parent. + * + * @param name the attribute name (null not permitted). + * + * @throws NullPointerException if name is null. */ void removeAttribute(Object name); /** - * removeAttributes - * @param names TODO + * Removes the attributes listed in names. + * + * @param names the attribute names (null not permitted). + * + * @throws NullPointerException if names is null + * or contains any null values. */ void removeAttributes(Enumeration names); /** - * removeAttributes - * @param attributes TODO + * Removes attributes from this set if they are found in the + * given set. Only attributes whose key AND value are removed. + * Removes attributes only from this set, not from the resolving parent. + * Since the resolving parent is stored as an attribute, if + * attributes has the same resolving parent as this set, the + * parent will be removed from this set. + * + * @param attributes the attributes (null not permitted). */ void removeAttributes(AttributeSet attributes); /** - * setResolveParent - * @param parent TODO + * Sets the reolving parent for this set. When looking up an attribute, if + * it is not found in this set, then the resolving parent is also used for + * the lookup. + * + * @param parent the parent attribute set (null not permitted). + * + * @throws NullPointerException if parent is null. */ void setResolveParent(AttributeSet parent); } diff --git a/javax/swing/text/NavigationFilter.java b/javax/swing/text/NavigationFilter.java index 45f58f9e2..ea9b29db8 100644 --- a/javax/swing/text/NavigationFilter.java +++ b/javax/swing/text/NavigationFilter.java @@ -68,4 +68,31 @@ public class NavigationFilter { fb.setDot(dot, bias); } + + /** + * Returns the next visual position in the specified direction at which one + * would place a caret. The default implementation forwards to the text + * component's root view. Subclasses may wish to restrict that more. + * + * @param c the text component + * @param pos the current model position + * @param bias the bias of pos + * @param dir the direction, one of {@link javax.swing.SwingConstants#NORTH}, + * {@link javax.swing.SwingConstants#SOUTH}, + * {@link javax.swing.SwingConstants#WEST} or + * {@link javax.swing.SwingConstants#EAST} + * @param retBias the bias of the returned position + * + * @return the next model location to place the caret + * + * @throws BadLocationException when pos is not a valid model + * position + */ + public int getNextVisualPositionFrom(JTextComponent c, int pos, + Position.Bias bias, int dir, + Position.Bias[] retBias) + throws BadLocationException + { + return c.getUI().getNextVisualPositionFrom(c, pos, bias, dir, retBias); + } } diff --git a/javax/swing/text/ParagraphView.java b/javax/swing/text/ParagraphView.java index c48645031..15bed7818 100644 --- a/javax/swing/text/ParagraphView.java +++ b/javax/swing/text/ParagraphView.java @@ -63,10 +63,20 @@ public class ParagraphView extends FlowView implements TabExpander { super(el, X_AXIS); } + public float getAlignment(int axis) { - // FIXME: This is very likely not 100% correct. Work this out. - return 0.0F; + float align; + if (axis == X_AXIS) + align = 0.0F; // TODO: Implement according to justification + else + align = super.getAlignment(axis); + return align; + } + + protected void loadChildren(ViewFactory vf) + { + // Do nothing here. The children are added while layouting. } } @@ -128,17 +138,18 @@ public class ParagraphView extends FlowView implements TabExpander */ public float getAlignment(int axis) { + float align; if (axis == X_AXIS) - return 0.0F; + align = super.getAlignment(axis); else if (getViewCount() > 0) { - float prefHeight = getPreferredSpan(Y_AXIS); float firstRowHeight = getView(0).getPreferredSpan(Y_AXIS); - return (firstRowHeight / 2.F) / prefHeight; + align = (firstRowHeight / 2.F) / prefHeight; } else - return 0.0F; + align = 0.0F; + return align; } /** @@ -229,4 +240,184 @@ public class ParagraphView extends FlowView implements TabExpander { return tabSet; } + + /** + * Finds the next offset in the document that has one of the characters + * specified in string. If there is no such character found, + * this returns -1. + * + * @param string the characters to search for + * @param start the start offset + * + * @return the next offset in the document that has one of the characters + * specified in string + */ + protected int findOffsetToCharactersInString(char[] string, int start) + { + int offset = -1; + Document doc = getDocument(); + Segment text = new Segment(); + try + { + doc.getText(start, doc.getLength() - start, text); + int index = start; + + searchLoop: + while (true) + { + char ch = text.next(); + if (ch == Segment.DONE) + break; + + for (int j = 0; j < string.length; ++j) + { + if (string[j] == ch) + { + offset = index; + break searchLoop; + } + } + index++; + } + } + catch (BadLocationException ex) + { + // Ignore this and return -1. + } + return offset; + } + + protected int getClosestPositionTo(int pos, Position.Bias bias, Shape a, + int direction, Position.Bias[] biasRet, + int rowIndex, int x) + throws BadLocationException + { + // FIXME: Implement this properly. However, this looks like it might + // have been replaced by viewToModel. + return pos; + } + + /** + * Returns the size that is used by this view (or it's child views) between + * startOffset and endOffset. If the child views + * implement the {@link TabableView} interface, then this is used to + * determine the span, otherwise we use the preferred span of the child + * views. + * + * @param startOffset the start offset + * @param endOffset the end offset + * + * @return the span used by the view between startOffset and + * endOffset + */ + protected float getPartialSize(int startOffset, int endOffset) + { + int startIndex = getViewIndex(startOffset, Position.Bias.Backward); + int endIndex = getViewIndex(endOffset, Position.Bias.Forward); + float span; + if (startIndex == endIndex) + { + View child = getView(startIndex); + if (child instanceof TabableView) + { + TabableView tabable = (TabableView) child; + span = tabable.getPartialSpan(startOffset, endOffset); + } + else + span = child.getPreferredSpan(X_AXIS); + } + else if (endIndex - startIndex == 1) + { + View child1 = getView(startIndex); + if (child1 instanceof TabableView) + { + TabableView tabable = (TabableView) child1; + span = tabable.getPartialSpan(startOffset, child1.getEndOffset()); + } + else + span = child1.getPreferredSpan(X_AXIS); + View child2 = getView(endIndex); + if (child2 instanceof TabableView) + { + TabableView tabable = (TabableView) child2; + span += tabable.getPartialSpan(child2.getStartOffset(), endOffset); + } + else + span += child2.getPreferredSpan(X_AXIS); + } + else + { + // Start with the first view. + View child1 = getView(startIndex); + if (child1 instanceof TabableView) + { + TabableView tabable = (TabableView) child1; + span = tabable.getPartialSpan(startOffset, child1.getEndOffset()); + } + else + span = child1.getPreferredSpan(X_AXIS); + + // Add up the view spans between the start and the end view. + for (int i = startIndex + 1; i < endIndex; i++) + { + View child = getView(i); + span += child.getPreferredSpan(X_AXIS); + } + + // Add the span of the last view. + View child2 = getView(endIndex); + if (child2 instanceof TabableView) + { + TabableView tabable = (TabableView) child2; + span += tabable.getPartialSpan(child2.getStartOffset(), endOffset); + } + else + span += child2.getPreferredSpan(X_AXIS); + } + return span; + } + + /** + * Returns the location where the tabs are calculated from. This returns + * 0.0F by default. + * + * @return the location where the tabs are calculated from + */ + protected float getTabBase() + { + return 0.0F; + } + + /** + * @specnote This method is specified to take a Row parameter, which is a + * private inner class of that class, which makes it unusable from + * application code. Also, this method seems to be replaced by + * {@link FlowStrategy#adjustRow(FlowView, int, int, int)}. + * + */ + protected void adjustRow(Row r, int desiredSpan, int x) + { + } + + /** + * @specnote This method's signature differs from the one defined in + * {@link View} and is therefore never called. It is probably there + * for historical reasons. + */ + public View breakView(int axis, float len, Shape a) + { + // This method is not used. + return null; + } + + /** + * @specnote This method's signature differs from the one defined in + * {@link View} and is therefore never called. It is probably there + * for historical reasons. + */ + public int getBreakWeight(int axis, float len) + { + // This method is not used. + return 0; + } } diff --git a/javax/swing/text/PasswordView.java b/javax/swing/text/PasswordView.java index e54331c5a..9d4c86a83 100644 --- a/javax/swing/text/PasswordView.java +++ b/javax/swing/text/PasswordView.java @@ -107,8 +107,6 @@ public class PasswordView protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException { - // FIXME: Throw BadLocationException somehow. - // Update font metrics. updateMetrics(); @@ -119,25 +117,18 @@ public class PasswordView g.setColor(selectedColor); g.setColor(Color.BLACK); - // Initialize buffer for faster drawing of all characters. - int len = p1 - p0; - char[] buffer = new char[len]; - for (int index = 0; index < len; ++index) - buffer[index] = ch; - - // Draw echo charaters. - g.drawChars(buffer, 0, len, x, y); - - // Return new x position right of all drawn characters. - return x + len * metrics.charWidth(ch); + // Draw echo character using drawEchoCharacter() method. + for (int index = p0; index < p1; ++index) + x = drawEchoCharacter(g, x, y, ch); + return x; } /** * Draws unselected text at a given position. * * @param g the Graphics object to draw to - * @param x the x-position - * @param y the y-position + * @param x the x-position of the start of the baseline + * @param y the y-position of the start of the baseline * @param p0 the position of the first character to draw * @param p1 the position of the first character not to draw * @@ -146,35 +137,20 @@ public class PasswordView protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException { - // FIXME: Throw BadLocationException somehow. - // Update font metrics. updateMetrics(); // Get echo character. char ch = getEchoChar(); - Segment segment = new Segment(); // Set color for unselected text. g.setColor(unselectedColor); g.setColor(Color.BLACK); - // Initialize buffer for faster drawing of all characters. - p1--; - getDocument().getText(p0, p1 - p0, segment); - int len = segment.toString().length(); - - char[] buffer = new char[len]; - for (int index = 0; index < len; ++index) - buffer[index] = ch; - - y += getPreferredSpan(Y_AXIS)/2; - - // Draw echo charaters. - g.drawChars(buffer, 0, len, x, y); - - // Return new x position right of all drawn characters. - return x + (len * metrics.charWidth(ch)); + // Draw echo character using drawEchoCharacter() method. + for (int index = p0; index < p1; ++index) + x = drawEchoCharacter(g, x, y, ch); + return x; } /** diff --git a/javax/swing/text/PlainView.java b/javax/swing/text/PlainView.java index a318ee71a..2eec7af54 100644 --- a/javax/swing/text/PlainView.java +++ b/javax/swing/text/PlainView.java @@ -1,5 +1,5 @@ /* PlainView.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -46,7 +46,6 @@ import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; -import javax.swing.SwingConstants; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentEvent.ElementChange; @@ -137,22 +136,32 @@ public class PlainView extends View implements TabExpander return rect; } + /** + * Draws a line of text. The X and Y coordinates specify the start of + * the baseline of the line. + * + * @param lineIndex the index of the line + * @param g the graphics to use for drawing the text + * @param x the X coordinate of the baseline + * @param y the Y coordinate of the baseline + */ protected void drawLine(int lineIndex, Graphics g, int x, int y) { try { - metrics = g.getFontMetrics(); - // FIXME: Selected text are not drawn yet. - Element line = getElement().getElement(lineIndex); - drawUnselectedText(g, x, y, line.getStartOffset(), line.getEndOffset()); - //drawSelectedText(g, , , , ); + metrics = g.getFontMetrics(); + // FIXME: Selected text are not drawn yet. + Element line = getElement().getElement(lineIndex); + drawUnselectedText(g, x, y, line.getStartOffset(), + line.getEndOffset() - 1); + //drawSelectedText(g, , , , ); } catch (BadLocationException e) - { - AssertionError ae = new AssertionError("Unexpected bad location"); - ae.initCause(e); - throw ae; - } + { + AssertionError ae = new AssertionError("Unexpected bad location"); + ae.initCause(e); + throw ae; + } } protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1) @@ -164,6 +173,20 @@ public class PlainView extends View implements TabExpander return Utilities.drawTabbedText(segment, x, y, g, this, 0); } + /** + * Draws a chunk of unselected text. + * + * @param g the graphics to use for drawing the text + * @param x the X coordinate of the baseline + * @param y the Y coordinate of the baseline + * @param p0 the start position in the text model + * @param p1 the end position in the text model + * + * @return the X location of the end of the range + * + * @throws BadLocationException if p0 or p1 are + * invalid + */ protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException { @@ -194,12 +217,12 @@ public class PlainView extends View implements TabExpander // FIXME: Text may be scrolled. Document document = textComponent.getDocument(); Element root = document.getDefaultRootElement(); - int y = rect.y; + int y = rect.y + metrics.getAscent(); for (int i = 0; i < root.getElementCount(); i++) { - drawLine(i, g, rect.x, y); - y += metrics.getHeight(); + drawLine(i, g, rect.x, y); + y += metrics.getHeight(); } } @@ -284,18 +307,20 @@ public class PlainView extends View implements TabExpander // make sure we have the metrics updateMetrics(); - float span = 0; Element el = getElement(); + float span; switch (axis) { case X_AXIS: span = determineMaxLineLength(); + break; case Y_AXIS: default: span = metrics.getHeight() * el.getElementCount(); break; } + return span; } @@ -318,12 +343,19 @@ public class PlainView extends View implements TabExpander Element root = doc.getDefaultRootElement(); // PlainView doesn't support line-wrapping so we can find out which - // Element was clicked on just by the y-position - int lineClicked = (int) (y - rec.y) / metrics.getHeight(); - if (lineClicked >= root.getElementCount()) - return getEndOffset() - 1; + // Element was clicked on just by the y-position. + // Since the coordinates may be outside of the coordinate space + // of the allocation area (e.g. user dragged mouse outside + // the component) we have to limit the values. + // This has the nice effect that the user can drag the + // mouse above or below the component and it will still + // react to the x values (e.g. when selecting). + int lineClicked + = Math.min(Math.max((int) (y - rec.y) / metrics.getHeight(), 0), + root.getElementCount() - 1); Element line = root.getElement(lineClicked); + Segment s = getLineBuffer(); int start = line.getStartOffset(); // We don't want the \n at the end of the line. @@ -353,6 +385,8 @@ public class PlainView extends View implements TabExpander */ protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f) { + float oldMaxLineLength = maxLineLength; + Rectangle alloc = a.getBounds(); Element el = getElement(); ElementChange ec = changes.getChange(el); @@ -360,7 +394,19 @@ public class PlainView extends View implements TabExpander // repaint the changed line if (ec == null) { - int line = getElement().getElementIndex(changes.getOffset()); + int line = el.getElementIndex(changes.getOffset()); + + // If characters have been removed from the current longest line + // we have to find out which one is the longest now otherwise + // the preferred x-axis span will not shrink. + if (changes.getType() == DocumentEvent.EventType.REMOVE + && el.getElement(line) == longestLine) + { + maxLineLength = -1; + if (determineMaxLineLength() != alloc.width) + preferenceChanged(this, true, false); + } + damageLineRange(line, line, a, getContainer()); return; } @@ -373,12 +419,13 @@ public class PlainView extends View implements TabExpander if (removed == null && newElements == null) { int line = getElement().getElementIndex(changes.getOffset()); + damageLineRange(line, line, a, getContainer()); return; } // Check to see if we removed the longest line, if so we have to - // search through all lines and find the longest one again + // search through all lines and find the longest one again. if (removed != null) { for (int i = 0; i < removed.length; i++) @@ -386,8 +433,11 @@ public class PlainView extends View implements TabExpander { // reset maxLineLength and search through all lines for longest one maxLineLength = -1; - determineMaxLineLength(); + if (determineMaxLineLength() != alloc.width) + preferenceChanged(this, true, removed.length != newElements.length); + ((JTextComponent)getContainer()).repaint(); + return; } } @@ -397,6 +447,7 @@ public class PlainView extends View implements TabExpander { // No lines were added, just repaint the container and exit ((JTextComponent)getContainer()).repaint(); + return; } @@ -445,6 +496,14 @@ public class PlainView extends View implements TabExpander maxLineLength = longestNewLength; longestLine = longestNewLine; } + + // Report any changes to the preferred sizes of the view + // which may cause the underlying component to be revalidated. + boolean widthChanged = oldMaxLineLength != maxLineLength; + boolean heightChanged = removed.length != newElements.length; + if (widthChanged || heightChanged) + preferenceChanged(this, widthChanged, heightChanged); + // Repaint the container ((JTextComponent)getContainer()).repaint(); } diff --git a/javax/swing/text/Segment.java b/javax/swing/text/Segment.java index 84e0e700f..6ae291bd1 100644 --- a/javax/swing/text/Segment.java +++ b/javax/swing/text/Segment.java @@ -1,5 +1,5 @@ /* Segment.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,20 +39,40 @@ package javax.swing.text; import java.text.CharacterIterator; +/** + * A text fragment represented by a sequence of characters stored in an array. + */ public class Segment implements Cloneable, CharacterIterator { private boolean partialReturn; + + /** The current index. */ private int current; + /** Storage for the characters (may contain additional characters). */ public char[] array; + + /** The number of characters in the segment. */ public int count; + + /** The offset of the first character in the segment. */ public int offset; + /** + * Creates a new Segment. + */ public Segment() { // Nothing to do here. } + /** + * Creates a new Segment. + * + * @param array the underlying character data. + * @param offset the offset of the first character in the segment. + * @param count the number of characters in the segment. + */ public Segment(char[] array, int offset, int count) { this.array = array; @@ -60,6 +80,12 @@ public class Segment implements Cloneable, CharacterIterator this.count = count; } + /** + * Clones the segment (note that the underlying character array is not cloned, + * just the reference to it). + * + * @return A clone of the segment. + */ public Object clone() { try @@ -72,6 +98,13 @@ public class Segment implements Cloneable, CharacterIterator } } + /** + * Returns the character at the current index. If the segment consists of + * zero characters, or the current index has passed the end of the + * characters in the segment, this method returns {@link #DONE}. + * + * @return The character at the current index. + */ public char current() { if (count == 0 @@ -81,6 +114,14 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Sets the current index to the first character in the segment and returns + * that character. If the segment contains zero characters, this method + * returns {@link #DONE}. + * + * @return The first character in the segment, or {@link #DONE} if the + * segment contains zero characters. + */ public char first() { if (count == 0) @@ -90,21 +131,46 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Returns the index of the first character in the segment. + * + * @return The index of the first character. + */ public int getBeginIndex() { return offset; } + /** + * Returns the end index for the segment (one position beyond the last + * character in the segment - note that this can be outside the range of the + * underlying character array). + * + * @return The end index for the segment. + */ public int getEndIndex() { return offset + count; } + /** + * Returns the index of the current character in the segment. + * + * @return The index of the current character. + */ public int getIndex() { return current; } + /** + * Sets the current index to point to the last character in the segment and + * returns that character. If the segment contains zero characters, this + * method returns {@link #DONE}. + * + * @return The last character in the segment, or {@link #DONE} if the + * segment contains zero characters. + */ public char last() { if (count == 0) @@ -114,6 +180,17 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Sets the current index to point to the next character in the segment and + * returns that character. If the next character position is past the end of + * the segment, the index is set to {@link #getEndIndex()} and the method + * returns {@link #DONE}. If the segment contains zero characters, this + * method returns {@link #DONE}. + * + * @return The next character in the segment or {@link #DONE} (if the next + * character position is past the end of the segment or if the + * segment contains zero characters). + */ public char next() { if (count == 0) @@ -129,6 +206,16 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Sets the current index to point to the previous character in the segment + * and returns that character. If the current index is equal to + * {@link #getBeginIndex()}, or if the segment contains zero characters, this + * method returns {@link #DONE}. + * + * @return The previous character in the segment or {@link #DONE} (if the + * current character position is at the beginning of the segment or + * if the segment contains zero characters). + */ public char previous() { if (count == 0 @@ -139,6 +226,19 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Sets the current index and returns the character at that position (or + * {@link #DONE} if the index is equal to {@link #getEndIndex()}. + * + * @param position the current position. + * + * @return The character at the specified position, or + * {@link #DONE} if position is equal to + * {@link #getEndIndex()}. + * + * @throws IllegalArgumentException if position is not in the + * range {@link #getBeginIndex()} to {@link #getEndIndex()}. + */ public char setIndex(int position) { if (position < getBeginIndex() @@ -153,12 +253,23 @@ public class Segment implements Cloneable, CharacterIterator return array[current]; } + /** + * Returns a String containing the same characters as this + * Segment. + * + * @return A String containing the same characters as this + * Segment. + */ public String toString() { return new String(array, offset, count); } /** + * Sets the partial return flag. + * + * @param p the new value of the flag. + * * @since 1.4 */ public void setPartialReturn(boolean p) @@ -167,6 +278,9 @@ public class Segment implements Cloneable, CharacterIterator } /** + * Returns the partial return flag. + * + * @return The partial return flag. * @since 1.4 */ public boolean isPartialReturn() diff --git a/javax/swing/text/SimpleAttributeSet.java b/javax/swing/text/SimpleAttributeSet.java index 692bfa634..94073f3af 100644 --- a/javax/swing/text/SimpleAttributeSet.java +++ b/javax/swing/text/SimpleAttributeSet.java @@ -1,5 +1,5 @@ /* SimpleAttributeSet.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,33 +42,67 @@ import java.io.Serializable; import java.util.Enumeration; import java.util.Hashtable; +/** + * A set of attributes. + */ public class SimpleAttributeSet implements MutableAttributeSet, Serializable, Cloneable { /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = 8267656273837665219L; + /** An empty attribute set. */ public static final AttributeSet EMPTY = new SimpleAttributeSet(); + /** Storage for the attributes. */ Hashtable tab; + /** + * Creates a new attribute set that is initially empty. + */ public SimpleAttributeSet() { - this(null); + tab = new Hashtable(); } + /** + * Creates a new SimpleAttributeSet with the same attributes + * and resolve parent as the specified set. + * + * @param a the attributes (null not permitted). + * + * @throws NullPointerException if a is null. + */ public SimpleAttributeSet(AttributeSet a) { tab = new Hashtable(); - if (a != null) - addAttributes(a); + addAttributes(a); } + /** + * Adds an attribute with the given name and value + * to the set. If the set already contains an attribute with the given + * name, the attribute value is updated. + * + * @param name the attribute name (null not permitted). + * @param value the value (null not permitted). + * + * @throws NullPointerException if either argument is null. + */ public void addAttribute(Object name, Object value) { tab.put(name, value); } + /** + * Adds all the attributes from attributes to this set. + * + * @param attributes the set of attributes to add (null not + * permitted). + * + * @throws NullPointerException if attributes is + * null. + */ public void addAttributes(AttributeSet attributes) { Enumeration e = attributes.getAttributeNames(); @@ -80,6 +114,11 @@ public class SimpleAttributeSet } } + /** + * Returns a clone of the attribute set. + * + * @return A clone of the attribute set. + */ public Object clone() { SimpleAttributeSet s = new SimpleAttributeSet(); @@ -97,9 +136,18 @@ public class SimpleAttributeSet */ public boolean containsAttribute(Object name, Object value) { - return (tab.containsKey(name) && tab.get(name).equals(value)) || - (getResolveParent() != null && getResolveParent(). - containsAttribute(name, value)); + if (value == null) + throw new NullPointerException("Null 'value' argument."); + if (tab.containsKey(name)) + return tab.get(name).equals(value); + else + { + AttributeSet p = getResolveParent(); + if (p != null) + return p.containsAttribute(name, value); + else + return false; + } } /** @@ -115,6 +163,15 @@ public class SimpleAttributeSet && tab.get(name).equals(value); } + /** + * Returns true of this AttributeSet contains all + * of the specified attributes. + * + * @param attributes the requested attributes + * + * @return true of this AttributeSet contains all + * of the specified attributes + */ public boolean containsAttributes(AttributeSet attributes) { Enumeration e = attributes.getAttributeNames(); @@ -128,11 +185,24 @@ public class SimpleAttributeSet return true; } + /** + * Creates and returns a copy of this AttributeSet. + * + * @return a copy of this AttributeSet + */ public AttributeSet copyAttributes() { return (AttributeSet) clone(); } + /** + * Checks this set for equality with an arbitrary object. + * + * @param obj the object (null permitted). + * + * @return true if this set is equal to obj, and + * false otherwise. + */ public boolean equals(Object obj) { return @@ -140,44 +210,95 @@ public class SimpleAttributeSet && this.isEqual((AttributeSet) obj); } + /** + * Returns the value of the specified attribute, or null if + * there is no attribute with that name. If the attribute is not defined + * directly in this set, the parent hierarchy (if there is one) will be + * used. + * + * @param name the attribute (null not permitted). + * + * @throws NullPointerException if name is null. + */ public Object getAttribute(Object name) { Object val = tab.get(name); if (val != null) return val; - Object p = getResolveParent(); - if (p != null && p instanceof AttributeSet) - return (((AttributeSet)p).getAttribute(name)); + AttributeSet p = getResolveParent(); + if (p != null) + return p.getAttribute(name); return null; } + /** + * Returns the number of attributes stored in this set, plus 1 if a parent + * has been specified (the reference to the parent is stored as a special + * attribute). The attributes stored in the parent do NOT contribute + * to the count. + * + * @return The attribute count. + */ public int getAttributeCount() { return tab.size(); } + /** + * Returns an enumeration of the attribute names. + * + * @return An enumeration of the attribute names. + */ public Enumeration getAttributeNames() { return tab.keys(); } + /** + * Returns the resolving parent. + * + * @return The resolving parent (possibly null). + * + * @see #setResolveParent(AttributeSet) + */ public AttributeSet getResolveParent() { return (AttributeSet) tab.get(ResolveAttribute); } + /** + * Returns a hash code for this instance. + * + * @return A hash code. + */ public int hashCode() { return tab.hashCode(); } + /** + * Returns true if the given attribute is defined in this set, + * and false otherwise. The parent attribute set is not + * checked. + * + * @param attrName the attribute name (null not permitted). + */ public boolean isDefined(Object attrName) { return tab.containsKey(attrName); } + /** + * Returns true if the set contains no attributes, and + * false otherwise. Note that the resolving parent is + * stored as an attribute, so this method will return false if + * a resolving parent is set. + * + * @return true if the set contains no attributes, and + * false otherwise. + */ public boolean isEmpty() { return tab.isEmpty(); @@ -186,7 +307,13 @@ public class SimpleAttributeSet /** * Returns true if the given set has the same number of attributes * as this set and containsAttributes(attr) returns - * true. + * true. + * + * @param attr the attribute set (null not permitted). + * + * @return A boolean. + * + * @throws NullPointerException if attr is null. */ public boolean isEqual(AttributeSet attr) { @@ -194,6 +321,15 @@ public class SimpleAttributeSet && this.containsAttributes(attr); } + /** + * Removes the attribute with the specified name, if this + * attribute is defined. This method will only remove an attribute from + * this set, not from the resolving parent. + * + * @param name the attribute name (null not permitted). + * + * @throws NullPointerException if name is null. + */ public void removeAttribute(Object name) { tab.remove(name); @@ -202,7 +338,12 @@ public class SimpleAttributeSet /** * Removes attributes from this set if they are found in the * given set. Only attributes whose key AND value are removed. - * Removes attributes only from this set, not from the resolving parent. + * Removes attributes only from this set, not from the resolving parent. + * Since the resolving parent is stored as an attribute, if + * attributes has the same resolving parent as this set, the + * parent will be removed from this set. + * + * @param attributes the attributes (null not permitted). */ public void removeAttributes(AttributeSet attributes) { @@ -216,6 +357,14 @@ public class SimpleAttributeSet } } + /** + * Removes the attributes listed in names. + * + * @param names the attribute names (null not permitted). + * + * @throws NullPointerException if names is null + * or contains any null values. + */ public void removeAttributes(Enumeration names) { while (names.hasMoreElements()) @@ -224,11 +373,31 @@ public class SimpleAttributeSet } } + /** + * Sets the reolving parent for this set. When looking up an attribute, if + * it is not found in this set, then the resolving parent is also used for + * the lookup. + *

      + * Note that the parent is stored as an attribute, and will contribute 1 to + * the count returned by {@link #getAttributeCount()}. + * + * @param parent the parent attribute set (null not permitted). + * + * @throws NullPointerException if parent is null. + * + * @see #setResolveParent(AttributeSet) + */ public void setResolveParent(AttributeSet parent) { addAttribute(ResolveAttribute, parent); } - + + /** + * Returns a string representation of this instance, typically used for + * debugging purposes. + * + * @return A string representation of this instance. + */ public String toString() { return tab.toString(); diff --git a/javax/swing/text/StringContent.java b/javax/swing/text/StringContent.java index 7db377a1c..0a31505f3 100644 --- a/javax/swing/text/StringContent.java +++ b/javax/swing/text/StringContent.java @@ -1,5 +1,5 @@ /* StringContent.java -- - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -54,7 +54,8 @@ import javax.swing.undo.UndoableEdit; * *

      Do not use this class for large size.

      */ -public final class StringContent implements AbstractDocument.Content, Serializable +public final class StringContent + implements AbstractDocument.Content, Serializable { /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = 4755994433709540381L; @@ -87,7 +88,8 @@ public final class StringContent implements AbstractDocument.Content, Serializab try { StringContent.this.checkLocation(this.start, this.length); - this.redoContent = new String(StringContent.this.content, this.start, this.length); + this.redoContent = new String(StringContent.this.content, this.start, + this.length); StringContent.this.remove(this.start, this.length); } catch (BadLocationException b) @@ -175,11 +177,20 @@ public final class StringContent implements AbstractDocument.Content, Serializab } } + /** + * Creates a new instance containing the string "\n". + */ public StringContent() { this(1); } + /** + * Creates a new instance containing the string "\n". + * + * @param initialLength the initial length of the underlying character + * array used to store the content. + */ public StringContent(int initialLength) { super(); @@ -198,7 +209,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab Iterator iter = this.positions.iterator(); while(iter.hasNext()) { - Position p = (Position)iter.next(); + Position p = (Position) iter.next(); if ((offset <= p.getOffset()) && (p.getOffset() <= (offset + length))) refPos.add(p); @@ -206,6 +217,16 @@ public final class StringContent implements AbstractDocument.Content, Serializab return refPos; } + /** + * Creates a position reference for the character at the given offset. The + * position offset will be automatically updated when new characters are + * inserted into or removed from the content. + * + * @param offset the character offset. + * + * @throws BadLocationException if offset is outside the bounds of the + * content. + */ public Position createPosition(int offset) throws BadLocationException { if (offset < this.count || offset > this.count) @@ -215,11 +236,27 @@ public final class StringContent implements AbstractDocument.Content, Serializab return sp; } + /** + * Returns the length of the string content, including the '\n' character at + * the end. + * + * @return The length of the string content. + */ public int length() { return this.count; } + /** + * Inserts str at the given position and returns an + * {@link UndoableEdit} that enables undo/redo support. + * + * @param where the insertion point (must be less than + * length()). + * @param str the string to insert (null not permitted). + * + * @return An object that can undo the insertion. + */ public UndoableEdit insertString(int where, String str) throws BadLocationException { @@ -235,13 +272,15 @@ public final class StringContent implements AbstractDocument.Content, Serializab if (where > 0) System.arraycopy(this.content, 0, temp, 0, where); System.arraycopy(insert, 0, temp, where, insert.length); - System.arraycopy(this.content, where, temp, (where + insert.length), (temp.length - where - insert.length)); + System.arraycopy(this.content, where, temp, (where + insert.length), + (temp.length - where - insert.length)); if (this.content.length < temp.length) this.content = new char[temp.length]; // Copy the result in the original char array. System.arraycopy(temp, 0, this.content, 0, temp.length); // Move all the positions. - Vector refPos = getPositionsInRange(this.positions, where, temp.length - where); + Vector refPos = getPositionsInRange(this.positions, where, + temp.length - where); Iterator iter = refPos.iterator(); while (iter.hasNext()) { @@ -252,20 +291,35 @@ public final class StringContent implements AbstractDocument.Content, Serializab return iundo; } + /** + * Removes the specified range of characters and returns an + * {@link UndoableEdit} that enables undo/redo support. + * + * @param where the starting index. + * @param nitems the number of characters. + * + * @return An object that can undo the removal. + * + * @throws BadLocationException if the character range extends outside the + * bounds of the content OR includes the last character. + */ public UndoableEdit remove(int where, int nitems) throws BadLocationException { - checkLocation(where, nitems); + checkLocation(where, nitems + 1); char[] temp = new char[(this.content.length - nitems)]; this.count = this.count - nitems; - RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where, nitems)); + RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where, + nitems)); // Copy array. System.arraycopy(this.content, 0, temp, 0, where); - System.arraycopy(this.content, where + nitems, temp, where, this.content.length - where - nitems); + System.arraycopy(this.content, where + nitems, temp, where, + this.content.length - where - nitems); this.content = new char[temp.length]; // Then copy the result in the original char array. System.arraycopy(temp, 0, this.content, 0, this.content.length); // Move all the positions. - Vector refPos = getPositionsInRange(this.positions, where, this.content.length + nitems - where); + Vector refPos = getPositionsInRange(this.positions, where, + this.content.length + nitems - where); Iterator iter = refPos.iterator(); while (iter.hasNext()) { @@ -278,31 +332,75 @@ public final class StringContent implements AbstractDocument.Content, Serializab return rundo; } + /** + * Returns a new String containing the characters in the + * specified range. + * + * @param where the start index. + * @param len the number of characters. + * + * @return A string. + * + * @throws BadLocationException if the requested range of characters extends + * outside the bounds of the content. + */ public String getString(int where, int len) throws BadLocationException { checkLocation(where, len); - return new String (this.content, where, len); + return new String(this.content, where, len); } - public void getChars(int where, int len, Segment txt) throws BadLocationException + /** + * Updates txt to contain a direct reference to the underlying + * character array. + * + * @param where the index of the first character. + * @param len the number of characters. + * @param txt a carrier for the return result (null not + * permitted). + * + * @throws BadLocationException if the requested character range is not + * within the bounds of the content. + * @throws NullPointerException if txt is null. + */ + public void getChars(int where, int len, Segment txt) + throws BadLocationException { checkLocation(where, len); - if (txt != null) - { - txt.array = this.content; - txt.offset = where; - txt.count = len; - } + txt.array = this.content; + txt.offset = where; + txt.count = len; } - // This is package-private to avoid an accessor method. + + /** + * @specnote This method is not very well specified and the positions vector + * is implementation specific. The undo positions are managed + * differently in this implementation, this method is only here + * for binary compatibility. + */ + protected void updateUndoPositions(Vector positions) + { + // We do nothing here. + } + + /** + * A utility method that checks the validity of the specified character + * range. + * + * @param where the first character in the range. + * @param len the number of characters in the range. + * + * @throws BadLocationException if the specified range is not within the + * bounds of the content. + */ void checkLocation(int where, int len) throws BadLocationException { if (where < 0) throw new BadLocationException("Invalid location", 1); else if (where > this.count) throw new BadLocationException("Invalid location", this.count); - else if ((where + len)>this.count) + else if ((where + len) > this.count) throw new BadLocationException("Invalid range", this.count); } diff --git a/javax/swing/text/StyleConstants.java b/javax/swing/text/StyleConstants.java index 598eaf621..bd870ad70 100644 --- a/javax/swing/text/StyleConstants.java +++ b/javax/swing/text/StyleConstants.java @@ -1,5 +1,5 @@ /* StyleConstants.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,45 +43,124 @@ import java.awt.Component; import javax.swing.Icon; +/** + * Represents standard attribute keys. This class also contains a set of + * useful static utility methods for querying and populating an + * {@link AttributeSet}. + * + * @since 1.2 + */ public class StyleConstants { + /** + * A value representing left alignment for the + * {@link ParagraphConstants#Alignment} attribute. + */ public static final int ALIGN_LEFT = 0; + + /** + * A value representing center alignment for the + * {@link ParagraphConstants#Alignment} attribute. + */ public static final int ALIGN_CENTER = 1; + + /** + * A value representing right alignment for the + * {@link ParagraphConstants#Alignment} attribute. + */ public static final int ALIGN_RIGHT = 2; + + /** + * A value representing ful justification for the + * {@link ParagraphConstants#Alignment} attribute. + */ public static final int ALIGN_JUSTIFIED = 3; + /** An alias for {@link CharacterConstants#Background}. */ public static final Object Background = CharacterConstants.Background; + + /** An alias for {@link CharacterConstants#BidiLevel}. */ public static final Object BidiLevel = CharacterConstants.BidiLevel; + + /** An alias for {@link CharacterConstants#Bold}. */ public static final Object Bold = CharacterConstants.Bold; - public static final Object ComponentAttribute = CharacterConstants.ComponentAttribute; + + /** An alias for {@link CharacterConstants#ComponentAttribute}. */ + public static final Object ComponentAttribute + = CharacterConstants.ComponentAttribute; + + /** An alias for {@link CharacterConstants#Family}. */ public static final Object Family = CharacterConstants.Family; + + /** An alias for {@link CharacterConstants#Family}. */ public static final Object FontFamily = CharacterConstants.Family; + + /** An alias for {@link CharacterConstants#Size}. */ public static final Object FontSize = CharacterConstants.Size; + + /** An alias for {@link CharacterConstants#Foreground}. */ public static final Object Foreground = CharacterConstants.Foreground; + + /** An alias for {@link CharacterConstants#IconAttribute}. */ public static final Object IconAttribute = CharacterConstants.IconAttribute; + + /** An alias for {@link CharacterConstants#Italic}. */ public static final Object Italic = CharacterConstants.Italic; + + /** An alias for {@link CharacterConstants#Size}. */ public static final Object Size = CharacterConstants.Size; + + /** An alias for {@link CharacterConstants#StrikeThrough}. */ public static final Object StrikeThrough = CharacterConstants.StrikeThrough; + + /** An alias for {@link CharacterConstants#Subscript}. */ public static final Object Subscript = CharacterConstants.Subscript; + + /** An alias for {@link CharacterConstants#Superscript}. */ public static final Object Superscript = CharacterConstants.Superscript; + + /** An alias for {@link CharacterConstants#Underline}. */ public static final Object Underline = CharacterConstants.Underline; + /** An alias for {@link ParagraphConstants#Alignment}. */ public static final Object Alignment = ParagraphConstants.Alignment; - public static final Object FirstLineIndent = ParagraphConstants.FirstLineIndent; + + /** An alias for {@link ParagraphConstants#FirstLineIndent}. */ + public static final Object FirstLineIndent + = ParagraphConstants.FirstLineIndent; + + /** An alias for {@link ParagraphConstants#LeftIndent}. */ public static final Object LeftIndent = ParagraphConstants.LeftIndent; + + /** An alias for {@link ParagraphConstants#LineSpacing}. */ public static final Object LineSpacing = ParagraphConstants.LineSpacing; + + /** An alias for {@link ParagraphConstants#Orientation}. */ public static final Object Orientation = ParagraphConstants.Orientation; + + /** An alias for {@link ParagraphConstants#RightIndent}. */ public static final Object RightIndent = ParagraphConstants.RightIndent; + + /** An alias for {@link ParagraphConstants#SpaceAbove}. */ public static final Object SpaceAbove = ParagraphConstants.SpaceAbove; + + /** An alias for {@link ParagraphConstants#SpaceBelow}. */ public static final Object SpaceBelow = ParagraphConstants.SpaceBelow; + + /** An alias for {@link ParagraphConstants#TabSet}. */ public static final Object TabSet = ParagraphConstants.TabSet; public static final String ComponentElementName = "component"; + public static final String IconElementName = "icon"; - public static final Object ComposedTextAttribute = new StyleConstants("composed text"); + public static final Object ComposedTextAttribute + = new StyleConstants("composed text"); + public static final Object ModelAttribute = new StyleConstants("model"); + public static final Object NameAttribute = new StyleConstants("name"); + public static final Object ResolveAttribute = new StyleConstants("resolver"); String keyname; @@ -93,279 +172,726 @@ public class StyleConstants keyname = k; } + /** + * Returns a string representation of the attribute key. + * + * @return A string representation of the attribute key. + */ public String toString() { return keyname; } + /** + * Returns the alignment specified in the given attributes, or + * {@link #ALIGN_LEFT} if no alignment is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The alignment (typically one of {@link #ALIGN_LEFT}, + * {@link #ALIGN_RIGHT}, {@link #ALIGN_CENTER} or + * {@link #ALIGN_JUSTIFIED}). + * + * @see #setAlignment(MutableAttributeSet, int) + */ public static int getAlignment(AttributeSet a) { - if (a.isDefined(Alignment)) - return ((Integer)a.getAttribute(Alignment)).intValue(); + Integer i = (Integer) a.getAttribute(Alignment); + if (i != null) + return i.intValue(); else return ALIGN_LEFT; } + /** + * Returns the background color specified in the given attributes, or + * {@link Color#BLACK} if no background color is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The background color. + * + * @see #setBackground(MutableAttributeSet, Color) + */ public static Color getBackground(AttributeSet a) { - if (a.isDefined(Background)) - return (Color) a.getAttribute(Background); + Color c = (Color) a.getAttribute(Background); + if (c != null) + return c; else - return Color.WHITE; + return Color.BLACK; } - + + /** + * Returns the bidi level specified in the given attributes, or + * 0 if no bidi level is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The bidi level. + * + * @see #setBidiLevel(MutableAttributeSet, int) + */ public static int getBidiLevel(AttributeSet a) { - if (a.isDefined(BidiLevel)) - return ((Integer)a.getAttribute(BidiLevel)).intValue(); + Integer i = (Integer) a.getAttribute(BidiLevel); + if (i != null) + return i.intValue(); else return 0; } + /** + * Returns the component specified in the given attributes, or + * null if no component is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The component (possibly null). + * + * @see #setComponent(MutableAttributeSet, Component) + */ public static Component getComponent(AttributeSet a) { - if (a.isDefined(ComponentAttribute)) - return (Component) a.getAttribute(ComponentAttribute); + Component c = (Component) a.getAttribute(ComponentAttribute); + if (c != null) + return c; else - return (Component) null; + return null; } + /** + * Returns the indentation specified in the given attributes, or + * 0.0f if no indentation is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The indentation. + * + * @see #setFirstLineIndent(MutableAttributeSet, float) + */ public static float getFirstLineIndent(AttributeSet a) { - if (a.isDefined(FirstLineIndent)) - return ((Float)a.getAttribute(FirstLineIndent)).floatValue(); + Float f = (Float) a.getAttribute(FirstLineIndent); + if (f != null) + return f.floatValue(); else - return 0.f; + return 0.0f; } + /** + * Returns the font family specified in the given attributes, or + * Monospaced if no font family is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The font family. + * + * @see #setFontFamily(MutableAttributeSet, String) + */ public static String getFontFamily(AttributeSet a) { - if (a.isDefined(FontFamily)) - return (String) a.getAttribute(FontFamily); + String ff = (String) a.getAttribute(FontFamily); + if (ff != null) + return ff; else return "Monospaced"; } + /** + * Returns the font size specified in the given attributes, or + * 12 if no font size is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The font size. + * + * @see #setFontSize(MutableAttributeSet, int) + */ public static int getFontSize(AttributeSet a) { - if (a.isDefined(FontSize)) - return ((Integer)a.getAttribute(FontSize)).intValue(); + Integer i = (Integer) a.getAttribute(FontSize); + if (i != null) + return i.intValue(); else return 12; } + /** + * Returns the foreground color specified in the given attributes, or + * {@link Color#BLACK} if no foreground color is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The foreground color. + * + * @see #setForeground(MutableAttributeSet, Color) + */ public static Color getForeground(AttributeSet a) { - if (a.isDefined(Foreground)) - return (Color) a.getAttribute(Foreground); + Color c = (Color) a.getAttribute(Foreground); + if (c != null) + return c; else return Color.BLACK; } + /** + * Returns the icon specified in the given attributes, or + * null if no icon is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The icon (possibly null). + * + * @see #setIcon(MutableAttributeSet, Icon) + */ public static Icon getIcon(AttributeSet a) { - if (a.isDefined(IconAttribute)) - return (Icon) a.getAttribute(IconAttribute); - else - return (Icon) null; + return (Icon) a.getAttribute(IconAttribute); } + /** + * Returns the left indentation specified in the given attributes, or + * 0.0f if no left indentation is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The left indentation. + * + * @see #setLeftIndent(MutableAttributeSet, float) + */ public static float getLeftIndent(AttributeSet a) { - if (a.isDefined(LeftIndent)) - return ((Float)a.getAttribute(LeftIndent)).floatValue(); + Float f = (Float) a.getAttribute(LeftIndent); + if (f != null) + return f.floatValue(); else - return 0.f; + return 0.0f; } + /** + * Returns the line spacing specified in the given attributes, or + * 0.0f if no line spacing is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The line spacing. + * + * @see #setLineSpacing(MutableAttributeSet, float) + */ public static float getLineSpacing(AttributeSet a) { - if (a.isDefined(LineSpacing)) - return ((Float)a.getAttribute(LineSpacing)).floatValue(); + Float f = (Float) a.getAttribute(LineSpacing); + if (f != null) + return f.floatValue(); else - return 0.f; + return 0.0f; } + /** + * Returns the right indentation specified in the given attributes, or + * 0.0f if no right indentation is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The right indentation. + * + * @see #setRightIndent(MutableAttributeSet, float) + */ public static float getRightIndent(AttributeSet a) { - if (a.isDefined(RightIndent)) - return ((Float)a.getAttribute(RightIndent)).floatValue(); + Float f = (Float) a.getAttribute(RightIndent); + if (f != null) + return f.floatValue(); else - return 0.f; + return 0.0f; } + /** + * Returns the 'space above' specified in the given attributes, or + * 0.0f if no 'space above' is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The 'space above'. + * + * @see #setSpaceAbove(MutableAttributeSet, float) + */ public static float getSpaceAbove(AttributeSet a) { - if (a.isDefined(SpaceAbove)) - return ((Float)a.getAttribute(SpaceAbove)).floatValue(); - else - return 0.f; + Float f = (Float) a.getAttribute(SpaceAbove); + if (f != null) + return f.floatValue(); + else + return 0.0f; } + /** + * Returns the 'space below' specified in the given attributes, or + * 0.0f if no 'space below' is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The 'space below'. + * + * @see #setSpaceBelow(MutableAttributeSet, float) + */ public static float getSpaceBelow(AttributeSet a) { - if (a.isDefined(SpaceBelow)) - return ((Float)a.getAttribute(SpaceBelow)).floatValue(); + Float f = (Float) a.getAttribute(SpaceBelow); + if (f != null) + return f.floatValue(); else - return 0.f; + return 0.0f; } + /** + * Returns the tab set specified in the given attributes, or + * null if no tab set is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The tab set. + * + * @see #setTabSet(MutableAttributeSet, javax.swing.text.TabSet) + */ public static javax.swing.text.TabSet getTabSet(AttributeSet a) { - if (a.isDefined(StyleConstants.TabSet)) - return (javax.swing.text.TabSet) a.getAttribute(StyleConstants.TabSet); - else - return (javax.swing.text.TabSet) null; + // I'm guessing that the fully qualified class name is to differentiate + // between the TabSet class and the TabSet (attribute) instance on some + // compiler... + return (javax.swing.text.TabSet) a.getAttribute(StyleConstants.TabSet); } + /** + * Returns the value of the bold flag in the given attributes, or + * false if no bold flag is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The bold flag. + * + * @see #setBold(MutableAttributeSet, boolean) + */ public static boolean isBold(AttributeSet a) { - if (a.isDefined(Bold)) - return ((Boolean) a.getAttribute(Bold)).booleanValue(); + Boolean b = (Boolean) a.getAttribute(Bold); + if (b != null) + return b.booleanValue(); else - return false; + return false; } + /** + * Returns the value of the italic flag in the given attributes, or + * false if no italic flag is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The italic flag. + * + * @see #setItalic(MutableAttributeSet, boolean) + */ public static boolean isItalic(AttributeSet a) { - if (a.isDefined(Italic)) - return ((Boolean) a.getAttribute(Italic)).booleanValue(); + Boolean b = (Boolean) a.getAttribute(Italic); + if (b != null) + return b.booleanValue(); else - return false; + return false; } + /** + * Returns the value of the strike-through flag in the given attributes, or + * false if no strike-through flag is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The strike-through flag. + * + * @see #setStrikeThrough(MutableAttributeSet, boolean) + */ public static boolean isStrikeThrough(AttributeSet a) { - if (a.isDefined(StrikeThrough)) - return ((Boolean) a.getAttribute(StrikeThrough)).booleanValue(); + Boolean b = (Boolean) a.getAttribute(StrikeThrough); + if (b != null) + return b.booleanValue(); else - return false; + return false; } + /** + * Returns the value of the subscript flag in the given attributes, or + * false if no subscript flag is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The subscript flag. + * + * @see #setSubscript(MutableAttributeSet, boolean) + */ public static boolean isSubscript(AttributeSet a) { - if (a.isDefined(Subscript)) - return ((Boolean) a.getAttribute(Subscript)).booleanValue(); + Boolean b = (Boolean) a.getAttribute(Subscript); + if (b != null) + return b.booleanValue(); else - return false; + return false; } + /** + * Returns the value of the superscript flag in the given attributes, or + * false if no superscript flag is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The superscript flag. + * + * @see #setSuperscript(MutableAttributeSet, boolean) + */ public static boolean isSuperscript(AttributeSet a) { - if (a.isDefined(Superscript)) - return ((Boolean) a.getAttribute(Superscript)).booleanValue(); - else - return false; + Boolean b = (Boolean) a.getAttribute(Superscript); + if (b != null) + return b.booleanValue(); + else + return false; } + /** + * Returns the value of the underline flag in the given attributes, or + * false if no underline flag is specified. + * + * @param a the attribute set (null not permitted). + * + * @return The underline flag. + * + * @see #setUnderline(MutableAttributeSet, boolean) + */ public static boolean isUnderline(AttributeSet a) { - if (a.isDefined(Underline)) - return ((Boolean) a.getAttribute(Underline)).booleanValue(); + Boolean b = (Boolean) a.getAttribute(Underline); + if (b != null) + return b.booleanValue(); else - return false; + return false; } + /** + * Adds an alignment attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param align the alignment (typically one of + * {@link StyleConstants#ALIGN_LEFT}, + * {@link StyleConstants#ALIGN_RIGHT}, + * {@link StyleConstants#ALIGN_CENTER} or + * {@link StyleConstants#ALIGN_JUSTIFIED}). + * + * @throws NullPointerException if a is null. + * + * @see #getAlignment(AttributeSet) + */ public static void setAlignment(MutableAttributeSet a, int align) { a.addAttribute(Alignment, new Integer(align)); } - public static void setBackground(MutableAttributeSet a, Color fg) + /** + * Adds a background attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param bg the background (null not permitted). + * + * @throws NullPointerException if either argument is null. + * + * @see #getBackground(AttributeSet) + */ + public static void setBackground(MutableAttributeSet a, Color bg) { - a.addAttribute(Background, fg); + a.addAttribute(Background, bg); } + /** + * Adds a bidi-level attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param lev the level. + * + * @throws NullPointerException if a is null. + * + * @see #getBidiLevel(AttributeSet) + */ public static void setBidiLevel(MutableAttributeSet a, int lev) { a.addAttribute(BidiLevel, new Integer(lev)); } + /** + * Adds a bold attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param b the new value of the bold attribute. + * + * @throws NullPointerException if a is null. + * + * @see #isBold(AttributeSet) + */ public static void setBold(MutableAttributeSet a, boolean b) { a.addAttribute(Bold, Boolean.valueOf(b)); } + /** + * Adds a component attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param c the component (null not permitted). + * + * @throws NullPointerException if either argument is null. + * + * @see #getComponent(AttributeSet) + */ public static void setComponent(MutableAttributeSet a, Component c) { a.addAttribute(ComponentAttribute, c); } + /** + * Adds a first line indentation attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param i the indentation. + * + * @throws NullPointerException if a is null. + * + * @see #getFirstLineIndent(AttributeSet) + */ public static void setFirstLineIndent(MutableAttributeSet a, float i) { a.addAttribute(FirstLineIndent, new Float(i)); } + /** + * Adds a font family attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param fam the font family name (null not permitted). + * + * @throws NullPointerException if either argument is null. + * + * @see #getFontFamily(AttributeSet) + */ public static void setFontFamily(MutableAttributeSet a, String fam) { a.addAttribute(FontFamily, fam); } + /** + * Adds a font size attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param s the font size (in points). + * + * @throws NullPointerException if a is null. + * + * @see #getFontSize(AttributeSet) + */ public static void setFontSize(MutableAttributeSet a, int s) { a.addAttribute(FontSize, new Integer(s)); } + /** + * Adds a foreground color attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param fg the foreground color (null not permitted). + * + * @throws NullPointerException if either argument is null. + * + * @see #getForeground(AttributeSet) + */ public static void setForeground(MutableAttributeSet a, Color fg) { a.addAttribute(Foreground, fg); } + /** + * Adds an icon attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param c the icon (null not permitted). + * + * @throws NullPointerException if either argument is null. + * + * @see #getIcon(AttributeSet) + */ public static void setIcon(MutableAttributeSet a, Icon c) { a.addAttribute(IconAttribute, c); } + /** + * Adds an italic attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param b the new value of the italic attribute. + * + * @throws NullPointerException if a is null. + * + * @see #isItalic(AttributeSet) + */ public static void setItalic(MutableAttributeSet a, boolean b) { a.addAttribute(Italic, Boolean.valueOf(b)); } + /** + * Adds a left indentation attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param i the indentation. + * + * @throws NullPointerException if a is null. + * + * @see #getLeftIndent(AttributeSet) + */ public static void setLeftIndent(MutableAttributeSet a, float i) { a.addAttribute(LeftIndent, new Float(i)); } + /** + * Adds a line spacing attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param i the line spacing. + * + * @throws NullPointerException if a is null. + * + * @see #getLineSpacing(AttributeSet) + */ public static void setLineSpacing(MutableAttributeSet a, float i) { a.addAttribute(LineSpacing, new Float(i)); } + /** + * Adds a right indentation attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param i the right indentation. + * + * @throws NullPointerException if a is null. + * + * @see #getRightIndent(AttributeSet) + */ public static void setRightIndent(MutableAttributeSet a, float i) { a.addAttribute(RightIndent, new Float(i)); } + /** + * Adds a 'space above' attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param i the space above attribute value. + * + * @throws NullPointerException if a is null. + * + * @see #getSpaceAbove(AttributeSet) + */ public static void setSpaceAbove(MutableAttributeSet a, float i) { a.addAttribute(SpaceAbove, new Float(i)); } + /** + * Adds a 'space below' attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param i the space below attribute value. + * + * @throws NullPointerException if a is null. + * + * @see #getSpaceBelow(AttributeSet) + */ public static void setSpaceBelow(MutableAttributeSet a, float i) { a.addAttribute(SpaceBelow, new Float(i)); } + /** + * Adds a strike-through attribue to the specified set. + * + * @param a the attribute set (null not permitted). + * @param b the strike-through attribute value. + * + * @throws NullPointerException if a is null. + * + * @see #isStrikeThrough(AttributeSet) + */ public static void setStrikeThrough(MutableAttributeSet a, boolean b) { a.addAttribute(StrikeThrough, Boolean.valueOf(b)); } + /** + * Adds a subscript attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param b the subscript attribute value. + * + * @throws NullPointerException if a is null. + * + * @see #isSubscript(AttributeSet) + */ public static void setSubscript(MutableAttributeSet a, boolean b) { a.addAttribute(Subscript, Boolean.valueOf(b)); } + /** + * Adds a superscript attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param b the superscript attribute value. + * + * @throws NullPointerException if a is null. + * + * @see #isSuperscript(AttributeSet) + */ public static void setSuperscript(MutableAttributeSet a, boolean b) { a.addAttribute(Superscript, Boolean.valueOf(b)); } + /** + * Adds a {@link TabSet} attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param tabs the tab set (null not permitted). + * + * @throws NullPointerException if either argument is null. + * + * @see #getTabSet(AttributeSet) + */ public static void setTabSet(MutableAttributeSet a, javax.swing.text.TabSet tabs) { a.addAttribute(StyleConstants.TabSet, tabs); } + /** + * Adds an underline attribute to the specified set. + * + * @param a the attribute set (null not permitted). + * @param b the underline attribute value. + * + * @throws NullPointerException if a is null. + * + * @see #isUnderline(AttributeSet) + */ public static void setUnderline(MutableAttributeSet a, boolean b) { a.addAttribute(Underline, Boolean.valueOf(b)); @@ -373,73 +899,164 @@ public class StyleConstants // The remainder are so-called "typesafe enumerations" which // alias subsets of the above constants. + + /** + * A set of keys for attributes that apply to characters. + */ public static class CharacterConstants extends StyleConstants implements AttributeSet.CharacterAttribute { + /** + * Private constructor prevents new instances being created. + * + * @param k the key name. + */ private CharacterConstants(String k) { super(k); } + /** An alias for {@link ColorConstants#Background}. */ public static Object Background = ColorConstants.Background; + + /** A key for the bidi level character attribute. */ public static Object BidiLevel = new CharacterConstants("bidiLevel"); + + /** An alias for {@link FontConstants#Bold}. */ public static Object Bold = FontConstants.Bold; + + /** A key for the component character attribute. */ public static Object ComponentAttribute = new CharacterConstants("component"); + + /** An alias for {@link FontConstants#Family}. */ public static Object Family = FontConstants.Family; + + /** An alias for {@link FontConstants#Size}. */ public static Object Size = FontConstants.Size; + + /** An alias for {@link ColorConstants#Foreground}. */ public static Object Foreground = ColorConstants.Foreground; + + /** A key for the icon character attribute. */ public static Object IconAttribute = new CharacterConstants("icon"); + + /** A key for the italic character attribute. */ public static Object Italic = FontConstants.Italic; + + /** A key for the strike through character attribute. */ public static Object StrikeThrough = new CharacterConstants("strikethrough"); + + /** A key for the subscript character attribute. */ public static Object Subscript = new CharacterConstants("subscript"); + + /** A key for the superscript character attribute. */ public static Object Superscript = new CharacterConstants("superscript"); + + /** A key for the underline character attribute. */ public static Object Underline = new CharacterConstants("underline"); + } + /** + * A set of keys for attributes that relate to colors. + */ public static class ColorConstants extends StyleConstants implements AttributeSet.ColorAttribute, AttributeSet.CharacterAttribute { + /** + * Private constructor prevents new instances being created. + * + * @param k the key name. + */ private ColorConstants(String k) { super(k); } + + /** A key for the foreground color attribute. */ public static Object Foreground = new ColorConstants("foreground"); + + /** A key for the background color attribute. */ public static Object Background = new ColorConstants("background"); } + /** + * A set of keys for attributes that apply to fonts. + */ public static class FontConstants extends StyleConstants implements AttributeSet.FontAttribute, AttributeSet.CharacterAttribute { + /** + * Private constructor prevents new instances being created. + * + * @param k the key name. + */ private FontConstants(String k) { super(k); } + + /** A key for the bold font attribute. */ public static Object Bold = new FontConstants("bold"); + + /** A key for the family font attribute. */ public static Object Family = new FontConstants("family"); + + /** A key for the italic font attribute. */ public static Object Italic = new FontConstants("italic"); + + /** A key for the size font attribute. */ public static Object Size = new FontConstants("size"); } + /** + * A set of keys for attributes that apply to paragraphs. + */ public static class ParagraphConstants extends StyleConstants implements AttributeSet.ParagraphAttribute { + /** + * Private constructor prevents new instances being created. + * + * @param k the key name. + */ private ParagraphConstants(String k) { super(k); } + + /** A key for the alignment paragraph attribute. */ public static Object Alignment = new ParagraphConstants("Alignment"); - public static Object FirstLineIndent = new ParagraphConstants("FirstLineIndent"); + + /** A key for the first line indentation paragraph attribute. */ + public static Object FirstLineIndent + = new ParagraphConstants("FirstLineIndent"); + + /** A key for the left indentation paragraph attribute. */ public static Object LeftIndent = new ParagraphConstants("LeftIndent"); + + /** A key for the line spacing paragraph attribute. */ public static Object LineSpacing = new ParagraphConstants("LineSpacing"); + + /** A key for the orientation paragraph attribute. */ public static Object Orientation = new ParagraphConstants("Orientation"); + + /** A key for the right indentation paragraph attribute. */ public static Object RightIndent = new ParagraphConstants("RightIndent"); + + /** A key for the 'space above' paragraph attribute. */ public static Object SpaceAbove = new ParagraphConstants("SpaceAbove"); + + /** A key for the 'space below' paragraph attribute. */ public static Object SpaceBelow = new ParagraphConstants("SpaceBelow"); + + /** A key for the tabset paragraph attribute. */ public static Object TabSet = new ParagraphConstants("TabSet"); + } } diff --git a/javax/swing/text/StyleContext.java b/javax/swing/text/StyleContext.java index 3735870dc..1df774974 100644 --- a/javax/swing/text/StyleContext.java +++ b/javax/swing/text/StyleContext.java @@ -48,6 +48,7 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Enumeration; import java.util.EventListener; +import java.util.HashSet; import java.util.Hashtable; import javax.swing.event.ChangeEvent; @@ -370,7 +371,7 @@ public class StyleContext { StringBuffer sb = new StringBuffer(); sb.append("[StyleContext.SmallattributeSet:"); - for (int i = 0; i < attrs.length; ++i) + for (int i = 0; i < attrs.length - 1; ++i) { sb.append(" ("); sb.append(attrs[i].toString()); @@ -406,7 +407,12 @@ public class StyleContext static StyleContext defaultStyleContext = new StyleContext(); static final int compressionThreshold = 9; - + + /** + * These attribute keys are handled specially in serialization. + */ + private static HashSet staticAttributeKeys = new HashSet(); + EventListenerList listenerList; Hashtable styleTable; @@ -737,4 +743,19 @@ public class StyleContext { throw new InternalError("not implemented"); } + + /** + * Registers an attribute key as a well-known keys. When an attribute with + * such a key is written to a stream,, a special syntax is used so that it + * can be recognized when it is read back in. All attribute keys defined + * in StyleContext are registered as static keys. If you define + * additional attribute keys that you want to exist as nonreplicated objects, + * then you should register them using this method. + * + * @param key the key to register as static attribute key + */ + public static void registerStaticAttributeKey(Object key) + { + staticAttributeKeys.add(key); + } } diff --git a/javax/swing/text/Utilities.java b/javax/swing/text/Utilities.java index 1adc8ff87..e3437d33c 100644 --- a/javax/swing/text/Utilities.java +++ b/javax/swing/text/Utilities.java @@ -41,12 +41,8 @@ package javax.swing.text; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Point; -import java.awt.Rectangle; import java.text.BreakIterator; -import javax.swing.SwingConstants; -import javax.swing.SwingUtilities; - /** * A set of utilities to deal with text. This is used by several other classes * inside this package. @@ -73,6 +69,10 @@ public class Utilities * are taken into account. Tabs are expanded using the * specified {@link TabExpander}. * + * + * The X and Y coordinates denote the start of the baseline where + * the text should be drawn. + * * @param s the text fragment to be drawn. * @param x the x position for drawing. * @param y the y position for drawing. @@ -88,15 +88,14 @@ public class Utilities // This buffers the chars to be drawn. char[] buffer = s.array; - - // The current x and y pixel coordinates. - int pixelX = x; - int pixelY = y; - // The font metrics of the current selected font. FontMetrics metrics = g.getFontMetrics(); int ascent = metrics.getAscent(); + // The current x and y pixel coordinates. + int pixelX = x; + int pixelY = y - ascent; + int pixelWidth = 0; int pos = s.offset; int len = 0; @@ -238,9 +237,10 @@ public class Utilities int pos; int currentX = x0; - for (pos = p0; pos < s.count; pos++) + for (pos = 0; pos < s.count; pos++) { char nextChar = s.array[s.offset+pos]; + if (nextChar == 0) { if (! round) @@ -256,6 +256,7 @@ public class Utilities else currentX = (int) te.nextTabStop(currentX, pos); } + if (currentX > x) { if (! round) @@ -263,7 +264,8 @@ public class Utilities break; } } - return pos; + + return pos + p0; } /** @@ -510,8 +512,8 @@ public class Utilities { int mark = Utilities.getTabbedTextOffset(s, metrics, x0, x, e, startOffset); BreakIterator breaker = BreakIterator.getWordInstance(); - breaker.setText(s.toString()); - + breaker.setText(s); + // If mark is equal to the end of the string, just use that position if (mark == s.count) return mark; @@ -571,15 +573,29 @@ public class Utilities public static final int getPositionAbove(JTextComponent c, int offset, int x) throws BadLocationException { - View rootView = c.getUI().getRootView(c); - Rectangle r = c.modelToView(offset); - int offs = c.viewToModel(new Point(x, r.y)); - int pos = rootView.getNextVisualPositionFrom(offs, - Position.Bias.Forward, - SwingUtilities.calculateInnerArea(c, null), - SwingConstants.NORTH, - new Position.Bias[1]); - return pos; + int offs = getRowStart(c, offset); + + if(offs == -1) + return -1; + + // Effectively calculates the y value of the previous line. + Point pt = c.modelToView(offs-1).getLocation(); + + pt.x = x; + + // Calculate a simple fitting offset. + offs = c.viewToModel(pt); + + // Find out the real x positions of the calculated character and its + // neighbour. + int offsX = c.modelToView(offs).getLocation().x; + int offsXNext = c.modelToView(offs+1).getLocation().x; + + // Chose the one which is nearer to us and return its offset. + if (Math.abs(offsX-x) <= Math.abs(offsXNext-x)) + return offs; + else + return offs+1; } /** @@ -598,14 +614,31 @@ public class Utilities public static final int getPositionBelow(JTextComponent c, int offset, int x) throws BadLocationException { - View rootView = c.getUI().getRootView(c); - Rectangle r = c.modelToView(offset); - int offs = c.viewToModel(new Point(x, r.y)); - int pos = rootView.getNextVisualPositionFrom(offs, - Position.Bias.Forward, - SwingUtilities.calculateInnerArea(c, null), - SwingConstants.SOUTH, - new Position.Bias[1]); - return pos; - } + int offs = getRowEnd(c, offset); + + if(offs == -1) + return -1; + + // Effectively calculates the y value of the previous line. + Point pt = c.modelToView(offs+1).getLocation(); + + pt.x = x; + + // Calculate a simple fitting offset. + offs = c.viewToModel(pt); + + if (offs == c.getDocument().getLength()) + return offs; + + // Find out the real x positions of the calculated character and its + // neighbour. + int offsX = c.modelToView(offs).getLocation().x; + int offsXNext = c.modelToView(offs+1).getLocation().x; + + // Chose the one which is nearer to us and return its offset. + if (Math.abs(offsX-x) <= Math.abs(offsXNext-x)) + return offs; + else + return offs+1; + } } diff --git a/javax/swing/text/View.java b/javax/swing/text/View.java index b835842bc..b4bdeb4de 100644 --- a/javax/swing/text/View.java +++ b/javax/swing/text/View.java @@ -40,7 +40,6 @@ package javax.swing.text; import java.awt.Container; import java.awt.Graphics; -import java.awt.Rectangle; import java.awt.Shape; import javax.swing.SwingConstants; @@ -72,8 +71,29 @@ public abstract class View implements SwingConstants public abstract void paint(Graphics g, Shape s); + /** + * Sets the parent for this view. This is the first method that is beeing + * called on a view to setup the view hierarchy. This is also the last method + * beeing called when the view is disconnected from the view hierarchy, in + * this case parent is null. + * + * If parent is null, a call to this method also + * calls setParent on the children, thus disconnecting them from + * the view hierarchy. That means that super must be called when this method + * is overridden. + * + * @param parent the parent to set, null when this view is + * beeing disconnected from the view hierarchy + */ public void setParent(View parent) { + if (parent == null) + { + int numChildren = getViewCount(); + for (int i = 0; i < numChildren; i++) + getView(i).setParent(null); + } + this.parent = parent; } @@ -101,27 +121,65 @@ public abstract class View implements SwingConstants return elt; } + /** + * Returns the preferred span along the specified axis. Normally the view is + * rendered with the span returned here if that is possible. + * + * @param axis the axis + * + * @return the preferred span along the specified axis + */ public abstract float getPreferredSpan(int axis); + /** + * Returns the resize weight of this view. A value of 0 or less + * means this view is not resizeable. Positive values make the view + * resizeable. The default implementation returns 0 + * unconditionally. + * + * @param axis the axis + * + * @return the resizability of this view along the specified axis + */ public int getResizeWeight(int axis) { return 0; } + /** + * Returns the maximum span along the specified axis. The default + * implementation will forward to + * {@link #getPreferredSpan(int)} unless {@link #getResizeWeight(int)} + * returns a value > 0, in which case this returns {@link Integer#MIN_VALUE}. + * + * @param axis the axis + * + * @return the maximum span along the specified axis + */ public float getMaximumSpan(int axis) { + float max = Integer.MAX_VALUE; if (getResizeWeight(axis) <= 0) - return getPreferredSpan(axis); - - return Integer.MAX_VALUE; + max = getPreferredSpan(axis); + return max; } + /** + * Returns the minimum span along the specified axis. The default + * implementation will forward to + * {@link #getPreferredSpan(int)} unless {@link #getResizeWeight(int)} + * returns a value > 0, in which case this returns 0. + * + * @param axis the axis + * + * @return the minimum span along the specified axis + */ public float getMinimumSpan(int axis) { + float min = 0; if (getResizeWeight(axis) <= 0) - return getPreferredSpan(axis); - - return Integer.MAX_VALUE; + min = getPreferredSpan(axis); + return min; } public void setSize(float width, float height) @@ -129,6 +187,20 @@ public abstract class View implements SwingConstants // The default implementation does nothing. } + /** + * Returns the alignment of this view along the baseline of the parent view. + * An alignment of 0.0 will align this view with the left edge + * along the baseline, an alignment of 0.5 will align it + * centered to the baseline, an alignment of 1.0 will align + * the right edge along the baseline. + * + * The default implementation returns 0.5 unconditionally. + * + * @param axis the axis + * + * @return the alignment of this view along the parents baseline for the + * specified axis + */ public float getAlignment(int axis) { return 0.5f; @@ -160,6 +232,15 @@ public abstract class View implements SwingConstants return parent != null ? parent.getViewFactory() : null; } + /** + * Replaces a couple of child views with new child views. If + * length == 0 then this is a simple insertion, if + * views == null this only removes some child views. + * + * @param offset the offset at which to replace + * @param length the number of child views to be removed + * @param views the new views to be inserted, may be null + */ public void replace(int offset, int length, View[] views) { // Default implementation does nothing. @@ -392,6 +473,10 @@ public abstract class View implements SwingConstants * of the change to the model. This calles {@link #forwardUpdateToView} * for each View that must be forwarded to. * + * If ec is not null (this means there have been + * structural changes to the element that this view is responsible for) this + * method should recognize this and don't notify newly added child views. + * * @param ec the ElementChange describing the element changes (may be * null if there were no changes) * @param ev the DocumentEvent describing the changes to the model @@ -404,10 +489,32 @@ public abstract class View implements SwingConstants DocumentEvent ev, Shape shape, ViewFactory vf) { int count = getViewCount(); - for (int i = 0; i < count; i++) + if (count > 0) { - View child = getView(i); - forwardUpdateToView(child, ev, shape, vf); + int startOffset = ev.getOffset(); + int endOffset = startOffset + ev.getLength(); + // FIXME: What about this bias stuff? + int startIndex = getViewIndex(startOffset, Position.Bias.Forward); + int endIndex = getViewIndex(endOffset, Position.Bias.Forward); + int index = -1; + int addLength = -1; + if (ec != null) + { + index = ec.getIndex(); + addLength = ec.getChildrenAdded().length; + } + + if (startIndex >= 0 && endIndex >= 0) + { + for (int i = startIndex; i <= endIndex; i++) + { + // Skip newly added child views. + if (index >= 0 && i >= index && i < (index+addLength)) + continue; + View child = getView(i); + forwardUpdateToView(child, ev, shape, vf); + } + } } } diff --git a/javax/swing/text/WrappedPlainView.java b/javax/swing/text/WrappedPlainView.java index baba343c5..e2790a05c 100644 --- a/javax/swing/text/WrappedPlainView.java +++ b/javax/swing/text/WrappedPlainView.java @@ -270,8 +270,7 @@ public class WrappedPlainView extends BoxView implements TabExpander protected int calculateBreakPosition(int p0, int p1) { Container c = getContainer(); - Rectangle alloc = c.isValid() ? c.getBounds() - : new Rectangle(c.getPreferredSize()); + Rectangle alloc = new Rectangle(0, 0, getWidth(), getHeight()); updateMetrics(); try { diff --git a/javax/swing/text/html/FormView.java b/javax/swing/text/html/FormView.java new file mode 100644 index 000000000..b85c69434 --- /dev/null +++ b/javax/swing/text/html/FormView.java @@ -0,0 +1,230 @@ +/* FormView.java -- A view for a variety of HTML form elements + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JPasswordField; +import javax.swing.JRadioButton; +import javax.swing.JTextField; +import javax.swing.UIManager; +import javax.swing.text.AttributeSet; +import javax.swing.text.ComponentView; +import javax.swing.text.Element; +import javax.swing.text.StyleConstants; + +/** + * A View that renders HTML form elements like buttons and input fields. + * This is implemented as a {@link ComponentView} that creates different Swing + * component depending on the type and setting of the different form elements. + * + * Namely, this view creates the following components: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      Element typeSwing component
      input, buttonJButton
      input, checkboxJButton
      input, imageJButton
      input, passwordJButton
      input, radioJButton
      input, resetJButton
      input, submitJButton
      input, textJButton
      select, size > 1 or with multiple attributeJList in JScrollPane
      select, size unspecified or == 1JComboBox
      textarea, textJTextArea in JScrollPane
      input, fileJTextField
      + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FormView + extends ComponentView + implements ActionListener +{ + + /** + * If the value attribute of an <input type="submit">> + * tag is not specified, then this string is used. + * + * @deprecated As of JDK1.3 the value is fetched from the UIManager property + * FormView.submitButtonText. + */ + public static final String SUBMIT = + UIManager.getString("FormView.submitButtonText"); + + /** + * If the value attribute of an <input type="reset">> + * tag is not specified, then this string is used. + * + * @deprecated As of JDK1.3 the value is fetched from the UIManager property + * FormView.resetButtonText. + */ + public static final String RESET = + UIManager.getString("FormView.resetButtonText"); + + /** + * Creates a new FormView. + * + * @param el the element that is displayed by this view. + */ + public FormView(Element el) + { + super(el); + } + + /** + * Creates the correct AWT component for rendering the form element. + */ + protected Component createComponent() + { + Component comp = null; + Element el = getElement(); + Object tag = el.getAttributes().getAttribute(StyleConstants.NameAttribute); + if (tag.equals(HTML.Tag.INPUT)) + { + AttributeSet atts = el.getAttributes(); + String type = (String) atts.getAttribute(HTML.Attribute.TYPE); + String value = (String) atts.getAttribute(HTML.Attribute.VALUE); + if (type.equals("button")) + comp = new JButton(value); + else if (type.equals("checkbox")) + comp = new JCheckBox(value); + else if (type.equals("image")) + comp = new JButton(value); // FIXME: Find out how to fetch the image. + else if (type.equals("password")) + comp = new JPasswordField(value); + else if (type.equals("radio")) + comp = new JRadioButton(value); + else if (type.equals("reset")) + { + if (value == null || value.equals("")) + value = RESET; + comp = new JButton(value); + } + else if (type.equals("submit")) + { + if (value == null || value.equals("")) + value = SUBMIT; + comp = new JButton(value); + } + else if (type.equals("text")) + comp = new JTextField(value); + + } + // FIXME: Implement the remaining components. + return comp; + } + + /** + * Determines the maximum span for this view on the specified axis. + * + * @param axis the axis along which to determine the span + * + * @return the maximum span for this view on the specified axis + * + * @throws IllegalArgumentException if the axis is invalid + */ + public float getMaximumSpan(int axis) + { + // FIXME: The specs say that for some components the maximum span == the + // preferred span of the component. This should be figured out and + // implemented accordingly. + float span; + if (axis == X_AXIS) + span = getComponent().getMaximumSize().width; + else if (axis == Y_AXIS) + span = getComponent().getMaximumSize().height; + else + throw new IllegalArgumentException("Invalid axis parameter"); + return span; + } + + /** + * Processes an action from the Swing component. + * + * If the action comes from a submit button, the form is submitted by calling + * {@link #submitData}. In the case of a reset button, the form is reset to + * the original state. If the action comes from a password or text field, + * then the input focus is transferred to the next input element in the form, + * unless this text/password field is the last one, in which case the form + * is submitted. + * + * @param ev the action event + */ + public void actionPerformed(ActionEvent ev) + { + Element el = getElement(); + Object tag = el.getAttributes().getAttribute(StyleConstants.NameAttribute); + if (tag.equals(HTML.Tag.INPUT)) + { + AttributeSet atts = el.getAttributes(); + String type = (String) atts.getAttribute(HTML.Attribute.TYPE); + if (type.equals("submit")) + submitData(""); // FIXME: How to fetch the actual form data? + } + // FIXME: Implement the remaining actions. + } + + /** + * Submits the form data. A separate thread is created to do the + * transmission. + * + * @param data the form data + */ + protected void submitData(String data) + { + // FIXME: Implement this. + } + + /** + * Submits the form data in response to a click on a + * <input type="image"> element. + * + * @param imageData the mouse click coordinates + */ + protected void imageSubmit(String imageData) + { + // FIXME: Implement this. + } +} diff --git a/javax/swing/text/html/HTML.java b/javax/swing/text/html/HTML.java index 09bf553b5..775bd3bc3 100644 --- a/javax/swing/text/html/HTML.java +++ b/javax/swing/text/html/HTML.java @@ -57,8 +57,7 @@ public class HTML /** * Represents a HTML attribute. */ - public static class Attribute - implements Serializable + public static final class Attribute { /** * The action attribute @@ -464,47 +463,18 @@ public class HTML * The width attribute */ public static final Attribute WIDTH = new Attribute("width"); - private final String name; - - /** - * Creates the attribute with the given name. - */ - protected Attribute(String a_name) - { - name = a_name; - } - - /** - * Calls compareTo on the tag names (Strings) - */ - public int compareTo(Object other) - { - return name.compareTo(((Attribute) other).name); - } /** - * The attributes are equal if the names are equal - * (ignoring case) + * The attribute name. */ - public boolean equals(Object other) - { - if (other == this) - return true; - - if (!(other instanceof Attribute)) - return false; - - Attribute that = (Attribute) other; - - return that.name.equalsIgnoreCase(name); - } + private final String name; /** - * Returns the hash code which corresponds to the string for this tag. + * Creates the attribute with the given name. */ - public int hashCode() + private Attribute(String a_name) { - return name == null ? 0 : name.hashCode(); + name = a_name; } /** @@ -559,7 +529,6 @@ public class HTML * Represents a HTML tag. */ public static class Tag - implements Comparable, Serializable { /** * The <a> tag @@ -1046,42 +1015,6 @@ public class HTML return (flags & BREAKS) != 0; } - /** - * Calls compareTo on the tag names (Strings) - */ - public int compareTo(Object other) - { - return name.compareTo(((Tag) other).name); - } - - /** - * The tags are equal if the names are equal (ignoring case). - */ - public boolean equals(Object other) - { - if (other == this) - { - return true; - } - - if (!(other instanceof Tag)) - { - return false; - } - - Tag that = (Tag) other; - - return that.name.equalsIgnoreCase(name); - } - - /** - * Returns the hash code which corresponds to the string for this tag. - */ - public int hashCode() - { - return name == null ? 0 : name.hashCode(); - } - /** * Returns the tag name. The names of the built-in tags are always * returned in lowercase. diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java index 6e5ab548f..92c9ccc79 100644 --- a/javax/swing/text/html/HTMLDocument.java +++ b/javax/swing/text/html/HTMLDocument.java @@ -38,10 +38,8 @@ exception statement from your version. */ package javax.swing.text.html; -import java.net.URL; - import java.io.IOException; - +import java.net.URL; import java.util.HashMap; import java.util.Stack; import java.util.Vector; @@ -131,16 +129,17 @@ public class HTMLDocument extends DefaultStyledDocument } /** - * Replaces the contents of the document with the given element specifications. - * This is called before insert if the loading is done in bursts. This is the - * only method called if loading the document entirely in one burst. + * Replaces the contents of the document with the given element + * specifications. This is called before insert if the loading is done + * in bursts. This is the only method called if loading the document + * entirely in one burst. * * @param data - the date that replaces the content of the document */ - protected void create(DefaultStyledDocument.ElementSpec[] data) + protected void create(ElementSpec[] data) { - // FIXME: Not implemented - System.out.println("create not implemented"); + // Once the super behaviour is properly implemented it should be sufficient + // to simply call super.create(data). super.create(data); } @@ -149,11 +148,35 @@ public class HTMLDocument extends DefaultStyledDocument * * @return the new default root */ - protected AbstractDocument.AbstractElement createDefaultRoot() + protected AbstractElement createDefaultRoot() { - // FIXME: Not implemented - System.out.println("createDefaultRoot not implemented"); - return super.createDefaultRoot(); + AbstractDocument.AttributeContext ctx = getAttributeContext(); + + // Create html element. + AttributeSet atts = ctx.getEmptySet(); + atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.HTML); + BranchElement html = (BranchElement) createBranchElement(null, atts); + + // Create body element. + atts = ctx.getEmptySet(); + atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.BODY); + BranchElement body = (BranchElement) createBranchElement(html, atts); + html.replace(0, 0, new Element[] { body }); + + // Create p element. + atts = ctx.getEmptySet(); + atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.P); + BranchElement p = (BranchElement) createBranchElement(body, atts); + body.replace(0, 0, new Element[] { p }); + + // Create an empty leaf element. + atts = ctx.getEmptySet(); + atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, + HTML.Tag.CONTENT); + Element leaf = createLeafElement(p, atts, 0, 1); + p.replace(0, 0, new Element[]{ leaf }); + + return html; } /** @@ -165,28 +188,29 @@ public class HTMLDocument extends DefaultStyledDocument * @param a - the attributes for the element * @param p0 - the beginning of the range >= 0 * @param p1 - the end of the range >= p0 + * * @return the new element */ protected Element createLeafElement(Element parent, AttributeSet a, int p0, int p1) { - // FIXME: Not implemented - System.out.println("createLeafElement not implemented"); - return super.createLeafElement(parent, a, p0, p1); + RunElement el = new RunElement(parent, a, p0, p1); + el.addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT); + return new RunElement(parent, a, p0, p1); } - /** This method returns an HTMLDocument.BlockElement object representing the + /** + * This method returns an HTMLDocument.BlockElement object representing the * attribute set a and attached to parent. * * @param parent - the parent element * @param a - the attributes for the element + * * @return the new element */ protected Element createBranchElement(Element parent, AttributeSet a) { - // FIXME: Not implemented - System.out.println("createBranchElement not implemented"); - return super.createBranchElement(parent, a); + return new BlockElement(parent, a); } /** @@ -204,9 +228,9 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void insert(int offset, DefaultStyledDocument.ElementSpec[] data) throws BadLocationException - { - super.insert(offset, data); - } + { + super.insert(offset, data); + } /** * Updates document structure as a result of text insertion. This will happen @@ -451,7 +475,7 @@ public class HTMLDocument extends DefaultStyledDocument { public BlockElement (Element parent, AttributeSet a) { - super (parent, a); + super(parent, a); } /** @@ -470,10 +494,14 @@ public class HTMLDocument extends DefaultStyledDocument */ public String getName() { - return (String) getAttribute(StyleConstants.NameAttribute); + Object tag = getAttribute(StyleConstants.NameAttribute); + String name = null; + if (tag != null) + name = tag.toString(); + return name; } } - + /** * RunElement represents a section of text that has a set of * HTML character level attributes assigned to it. @@ -502,7 +530,11 @@ public class HTMLDocument extends DefaultStyledDocument */ public String getName() { - return (String) getAttribute(StyleConstants.NameAttribute); + Object tag = getAttribute(StyleConstants.NameAttribute); + String name = null; + if (tag != null) + name = tag.toString(); + return name; } /** @@ -699,8 +731,8 @@ public class HTMLDocument extends DefaultStyledDocument */ public void start(HTML.Tag t, MutableAttributeSet a) { - // FIXME: Implement. - print ("ParagraphAction.start not implemented"); + // FIXME: What else must be done here? + blockOpen(t, a); } /** @@ -709,8 +741,8 @@ public class HTMLDocument extends DefaultStyledDocument */ public void end(HTML.Tag t) { - // FIXME: Implement. - print ("ParagraphAction.end not implemented"); + // FIXME: What else must be done here? + blockClose(t); } } @@ -1102,7 +1134,11 @@ public class HTMLDocument extends DefaultStyledDocument elements = new DefaultStyledDocument.ElementSpec[parseBuffer.size()]; parseBuffer.copyInto(elements); parseBuffer.removeAllElements(); - insert(offset, elements); + if (offset == 0) + create(elements); + else + insert(offset, elements); + offset += HTMLDocument.this.getLength() - offset; } @@ -1250,12 +1286,15 @@ public class HTMLDocument extends DefaultStyledDocument { printBuffer(); DefaultStyledDocument.ElementSpec element; - element = new DefaultStyledDocument.ElementSpec(attr.copyAttributes(), - DefaultStyledDocument.ElementSpec.StartTagType); + AbstractDocument.AttributeContext ctx = getAttributeContext(); + AttributeSet copy = attr.copyAttributes(); + copy = ctx.addAttribute(copy, StyleConstants.NameAttribute, t); + element = new DefaultStyledDocument.ElementSpec(copy, + DefaultStyledDocument.ElementSpec.StartTagType); parseBuffer.addElement(element); printBuffer(); } - + /** * Instructs the parse buffer to close the block element associated with * the given HTML.Tag @@ -1300,14 +1339,18 @@ public class HTMLDocument extends DefaultStyledDocument { // Copy the attribute set, don't use the same object because // it may change + AbstractDocument.AttributeContext ctx = getAttributeContext(); AttributeSet attributes = null; if (charAttr != null) attributes = charAttr.copyAttributes(); - + else + attributes = ctx.getEmptySet(); + attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute, + HTML.Tag.CONTENT); DefaultStyledDocument.ElementSpec element; element = new DefaultStyledDocument.ElementSpec(attributes, - DefaultStyledDocument.ElementSpec.ContentType, - data, offs, length); + DefaultStyledDocument.ElementSpec.ContentType, + data, offs, length); printBuffer(); // Add the element to the buffer diff --git a/javax/swing/text/html/HTMLEditorKit.java b/javax/swing/text/html/HTMLEditorKit.java index 79e620327..93e635525 100644 --- a/javax/swing/text/html/HTMLEditorKit.java +++ b/javax/swing/text/html/HTMLEditorKit.java @@ -56,17 +56,11 @@ import javax.accessibility.AccessibleContext; import javax.swing.Action; import javax.swing.JEditorPane; -import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; -import javax.swing.text.BoxView; -import javax.swing.text.ComponentView; import javax.swing.text.Document; import javax.swing.text.EditorKit; import javax.swing.text.Element; -import javax.swing.text.IconView; -import javax.swing.text.LabelView; import javax.swing.text.MutableAttributeSet; -import javax.swing.text.ParagraphView; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; import javax.swing.text.StyledEditorKit; @@ -532,8 +526,8 @@ public class HTMLEditorKit public View create(Element element) { View view = null; - Object attr = element.getAttributes().getAttribute( - StyleConstants.NameAttribute); + Object attr = + element.getAttributes().getAttribute(StyleConstants.NameAttribute); if (attr instanceof HTML.Tag) { HTML.Tag tag = (HTML.Tag) attr; @@ -553,8 +547,12 @@ public class HTMLEditorKit view = new BlockView(element, View.Y_AXIS); // FIXME: Uncomment when the views have been implemented - /* else if (tag.equals(HTML.Tag.CONTENT)) - view = new InlineView(element); + else if (tag.equals(HTML.Tag.CONTENT)) + view = new InlineView(element); + else if (tag == HTML.Tag.HEAD) + view = new NullView(element); + + /* else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR) || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL)) view = new ListView(element); @@ -576,21 +574,6 @@ public class HTMLEditorKit else if (tag.equals(HTML.Tag.FRAME)) view = new FrameView(element); */ } - - if (view == null) - { - String name = element.getName(); - if (name.equals(AbstractDocument.ContentElementName)) - view = new LabelView(element); - else if (name.equals(AbstractDocument.ParagraphElementName)) - view = new ParagraphView(element); - else if (name.equals(AbstractDocument.SectionElementName)) - view = new BoxView(element, View.Y_AXIS); - else if (name.equals(StyleConstants.ComponentElementName)) - view = new ComponentView(element); - else if (name.equals(StyleConstants.IconElementName)) - view = new IconView(element); - } return view; } } diff --git a/javax/swing/text/html/InlineView.java b/javax/swing/text/html/InlineView.java new file mode 100644 index 000000000..77ec86e82 --- /dev/null +++ b/javax/swing/text/html/InlineView.java @@ -0,0 +1,166 @@ +/* InlineView.java -- Renders HTML content + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.awt.Shape; + +import javax.swing.event.DocumentEvent; +import javax.swing.text.AttributeSet; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.LabelView; +import javax.swing.text.View; +import javax.swing.text.ViewFactory; + +/** + * Renders HTML content (identified by {@link HTML.Tag#CONTENT}). This is + * basically a {@link LabelView} that is adjusted to understand styles defined + * by stylesheets. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class InlineView + extends LabelView +{ + + /** + * Creates a new InlineView that renders the specified element. + * + * @param element the element for this view + */ + public InlineView(Element element) + { + super(element); + } + + /** + * Receives notification that something was inserted into the document in + * a location that this view is responsible for. + * + * @param e the document event + * @param a the current allocation of this view + * @param f the view factory for creating new views + * + * @since 1.5 + */ + public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) + { + // FIXME: What to do here? + super.insertUpdate(e, a, f); + } + + /** + * Receives notification that something was removed from the document in + * a location that this view is responsible for. + * + * @param e the document event + * @param a the current allocation of this view + * @param f the view factory for creating new views + * + * @since 1.5 + */ + public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) + { + // FIXME: What to do here? + super.removeUpdate(e, a, f); + } + + /** + * Receives notification that attributes have changed in the document in + * a location that this view is responsible for. This calls + * {@link #setPropertiesFromAttributes}. + * + * @param e the document event + * @param a the current allocation of this view + * @param f the view factory for creating new views + * + * @since 1.5 + */ + public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) + { + super.changedUpdate(e, a, f); + setPropertiesFromAttributes(); + } + + /** + * Returns the attributes that are used for rendering. This is implemented + * to multiplex the attributes specified in the model with a stylesheet. + * + * @return the attributes that are used for rendering + */ + public AttributeSet getAttributes() + { + // FIXME: Implement this. + return super.getAttributes(); + } + + + public int getBreakWeight(int axis, float pos, float len) + { + // FIXME: Implement this. + return super.getBreakWeight(axis, pos, len); + } + + public View breakView(int axis, int offset, float pos, float len) + { + // FIXME: Implement this. + return super.breakView(axis, offset, pos, len); + } + + protected void setPropertiesFromAttributes() + { + // FIXME: Implement this. + super.setPropertiesFromAttributes(); + } + + /** + * Returns the stylesheet used by this view. This returns the stylesheet + * of the HTMLDocument that is rendered by this view. + * + * @return the stylesheet used by this view + */ + protected StyleSheet getStyleSheet() + { + Document doc = getDocument(); + StyleSheet styleSheet = null; + if (doc instanceof HTMLDocument) + styleSheet = ((HTMLDocument) doc).getStyleSheet(); + return styleSheet; + } +} diff --git a/javax/swing/text/html/NullView.java b/javax/swing/text/html/NullView.java new file mode 100644 index 000000000..4b66c5ad8 --- /dev/null +++ b/javax/swing/text/html/NullView.java @@ -0,0 +1,102 @@ +/* NullView.java -- A dummy view that renders nothing + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.awt.Graphics; +import java.awt.Shape; + +import javax.swing.text.BadLocationException; +import javax.swing.text.Element; +import javax.swing.text.View; +import javax.swing.text.Position.Bias; + +/** + * A dummy view that renders nothing. This is used for invisible HTML elements + * like . + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class NullView + extends View +{ + + /** + * Creates a new NullView. + * + * @param elem the element + */ + public NullView(Element elem) + { + super(elem); + } + + /** + * Does nothing. + */ + public void paint(Graphics g, Shape s) + { + // Nothing to do here. + } + + /** + * Returns zero for both directions. + */ + public float getPreferredSpan(int axis) + { + return 0; + } + + /** + * Returns the allocation of this view, which should be empty anyway. + */ + public Shape modelToView(int pos, Shape a, Bias b) + throws BadLocationException + { + return a; + } + + /** + * Returns the start offset of the element. + */ + public int viewToModel(float x, float y, Shape a, Bias[] b) + { + return getElement().getStartOffset(); + } + +} diff --git a/javax/swing/text/html/ObjectView.java b/javax/swing/text/html/ObjectView.java new file mode 100644 index 000000000..d6a77c06a --- /dev/null +++ b/javax/swing/text/html/ObjectView.java @@ -0,0 +1,110 @@ +/* ObjectView.java -- A view for HTML object tags + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.awt.Component; + +import javax.swing.text.AttributeSet; +import javax.swing.text.ComponentView; +import javax.swing.text.Element; + +/** + * A view for HTML <object> tags. + * + * This is a {@link ComponentView} that creates special components depending + * on the object specification. If the object tag has a classid attribute, then + * this view will try to load the class specified by this attribute using the + * classloader that loaded the associated document. If the class could be + * loaded, an instance is created and the type narrowed to {@link Component}. + * + * It is also possible to set bean properties on the created component using + * nested <param> tags. For example: + *
      + * 
      + *   
      + * 
      + * 
      + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class ObjectView extends ComponentView +{ + + /** + * Creates a new ObjectView. + * + * @param el the element for which to create a view + */ + public ObjectView(Element el) + { + super(el); + } + + /** + * Creates a component based on the specification in the element of this + * view. See the class description for details. + */ + protected Component createComponent() + { + Component comp = null; + Element el = getElement(); + AttributeSet atts = el.getAttributes(); + String classId = (String) atts.getAttribute("classid"); + try + { + Class objectClass = Class.forName(classId); + Object instance = objectClass.newInstance(); + comp = (Component) instance; + } + catch (ClassNotFoundException ex) + { + // Ignored. + } + catch (IllegalAccessException ex) + { + // Ignored. + } + catch (InstantiationException ex) + { + // Ignored. + } + // FIXME: Handle param tags and set bean properties accordingly. + return comp; + } +} diff --git a/javax/swing/text/html/Option.java b/javax/swing/text/html/Option.java new file mode 100644 index 000000000..1def51b2f --- /dev/null +++ b/javax/swing/text/html/Option.java @@ -0,0 +1,157 @@ +/* Option.java -- Value class for
      . * Each entry has been adjusted so that the 16-bit sum with the desired * character gives the actual index into DATA. */ - String BLOCKS + String[] BLOCKS = new String[]{ EOF - - for ($i = 0; $i < @blocks / 11; $i++) { - print OUTPUT $i ? "\n + \"" : " = \""; - for $j (0 .. 10) { - last if @blocks <= $i * 11 + $j; - my $val = $blocks[$i * 11 + $j]; - print OUTPUT javaChar($val); - } - print OUTPUT "\""; + for ($plane = 0; $plane <= 0x10; $plane++) { + # The following if statement handles the cases of unassigned planes + # specially so we don't waste space with unused Strings. As of + # Unicode version 4.0.0 only planes 0, 1, 2, and 14 are used. If + # you are updating this script to work with a later version of + # Unicode you may have to alter this if statement. + if ($plane > 2 && $plane != 14) { + print OUTPUT ($plane == 0x10) ? " \"\"}" : " \"\",\n\n"; + } + else { + for ($i = 0; $i < @{$blocksArray[$plane]} / 11; $i++) { + print OUTPUT $i ? "\n + " : " "; + print OUTPUT "\""; + for $j (0 .. 10) { + last if @{$blocksArray[$plane]} <= $i * 11 + $j; + my $val = $blocksArray[$plane]->[$i * 11 + $j]; + print OUTPUT javaChar($val); + } + print OUTPUT "\""; + } + print OUTPUT ",\n\n"; + } } - print OUTPUT < 0){ + print OUTPUT $largeNums[-1], "}"; + } + else { + print OUTPUT " = null"; + } + print OUTPUT < 2 && $plane != 14) { + print OUTPUT ($plane == 0x10) ? " \"\"}" : " \"\",\n\n"; + } + else { + my $len = length($bestblkstr[$plane]) / 2; + for ($i = 0; $i < $len / 11; $i++) { + print OUTPUT $i ? "\n + " : " "; + print OUTPUT "\""; + for $j (0 .. 10) { + last if $len <= $i * 11 + $j; + my $val = unpack "n", substr($bestblkstr[$plane], 2 * ($i * 11 + $j), 2); + print OUTPUT javaChar($val); + } + print OUTPUT "\""; + } + print OUTPUT ",\n\n"; + } } - print OUTPUT < 2 && $plane != 14) { + print OUTPUT ($plane == 0x10) ? " \"\"}" : " \"\",\n\n"; + } + else { + $len = @{$charinfoArray[$plane]}; + for ($i = 0; $i < $len / 11; $i++) { + print OUTPUT $i ? "\n + " : " "; + print OUTPUT "\""; + for $j (0 .. 10) { + last if $len <= $i * 11 + $j; + my $val = $charinfoArray[$plane]->[$i * 11 + $j][0]; + print OUTPUT javaChar($val); + } + print OUTPUT "\""; + } + print OUTPUT ",\n\n"; + } } - print OUTPUT < 2 && $plane != 14) { + print OUTPUT ($plane == 0x10) ? " \"\"}" : " \"\",\n\n"; + } + else { + $len = @{$charinfoArray[$plane]}; + for ($i = 0; $i < $len / 11; $i++) { + print OUTPUT $i ? "\n + " : " "; + print OUTPUT "\""; + for $j (0 .. 10) { + last if $len <= $i * 11 + $j; + my $val = $charinfoArray[$plane]->[$i * 11 + $j][1]; + print OUTPUT javaChar($val); + } + print OUTPUT "\""; + } + print OUTPUT ",\n\n"; + } } - print OUTPUT < 2 && $plane != 14) { + print OUTPUT ($plane == 0x10) ? " \"\"}" : " \"\",\n\n"; + } + else { + $len = @{$charinfoArray[$plane]}; + for ($i = 0; $i < $len / 11; $i++) { + print OUTPUT $i ? "\n + " : " "; + print OUTPUT "\""; + for $j (0 .. 10) { + last if $len <= $i * 11 + $j; + my $val = $charinfoArray[$plane]->[$i * 11 + $j][2]; + print OUTPUT javaChar($val); + } + print OUTPUT "\""; + } + print OUTPUT ",\n\n"; + } } - print OUTPUT < 2 && $plane != 14) { + print OUTPUT ($plane == 0x10) ? " \"\"}" : " \"\",\n\n"; + } + else { + $len = @{$charinfoArray[$plane]}; + for ($i = 0; $i < $len / 11; $i++) { + print OUTPUT $i ? "\n + " : " "; + print OUTPUT "\""; + for $j (0 .. 10) { + last if $len <= $i * 11 + $j; + my $val = $charinfoArray[$plane]->[$i * 11 + $j][3]; + print OUTPUT javaChar($val); + } + print OUTPUT "\""; + } + print OUTPUT ",\n\n"; + } } - print OUTPUT <NOTE: All IDs handled by the ID manager (all object and reference * type IDs) are assumed to be of type long. * + * NOTE: This class does not manage virtual machine-specific types, + * like methods, fields, and frames. These already have unique IDs within + * the virtual machine and do not need further abstraction here. + * * @author Keith Seitz (keiths@redhat.com) */ public class VMIdManager @@ -99,9 +103,6 @@ public class VMIdManager // ObjectId and ArrayId are special cases. See newObjectId. _idList.put (ClassLoaderId.typeClass, ClassLoaderId.class); _idList.put (ClassObjectId.typeClass, ClassObjectId.class); - //_idList.put (FieldId.typeClass, FieldId.class); - //_idList.put (FrameId.typeClass, FrameId.class); - //_idList.put (MethodId.typeClass, MethodId.class); _idList.put (StringId.typeClass, StringId.class); _idList.put (ThreadId.typeClass, ThreadId.class); _idList.put (ThreadGroupId.typeClass, ThreadGroupId.class); @@ -187,6 +188,7 @@ public class VMIdManager id = new InterfaceReferenceTypeId (); else id = new ClassReferenceTypeId (); + id.setReference (ref); synchronized (_ridLock) { id.setId (++_lastRid); diff --git a/vm/reference/java/io/VMObjectInputStream.java b/vm/reference/java/io/VMObjectInputStream.java index 93a42b1ca..5fb56fcd4 100644 --- a/vm/reference/java/io/VMObjectInputStream.java +++ b/vm/reference/java/io/VMObjectInputStream.java @@ -55,25 +55,36 @@ final class VMObjectInputStream } } - // PrivilegedAction needed for Class.getClassLoader() + /** + * PrivilegedAction needed for Class.getClassLoader() + */ private static PrivilegedAction loaderAction = new PrivilegedAction() + { + /** + * Returns the first user defined class loader on the call stack, or the + * context class loader of the current thread, when no non-null class loader + * was found. + */ + public Object run() { - public Object run() - { - Class[] ctx = VMStackWalker.getClassContext(); - for (int i = 0; i < ctx.length; i++) - { - ClassLoader cl = ctx[i].getClassLoader(); - if (cl != null) - return cl; - } - return null; - } + Class[] ctx = VMStackWalker.getClassContext(); + + for (int i = 0; i < ctx.length; i++) + { + ClassLoader cl = ctx[i].getClassLoader(); + if (cl != null) + return cl; + } + return Thread.currentThread().getContextClassLoader(); + } }; /** - * Returns the first user defined class loader on the call stack, or - * null when no non-null class loader was found. + * Returns the first user defined class loader on the call stack, or the + * context class loader of the current thread, when no non-null class loader + * was found. + * + * @return the class loader */ static ClassLoader currentClassLoader() { diff --git a/vm/reference/java/lang/VMMath.java b/vm/reference/java/lang/VMMath.java new file mode 100644 index 000000000..4d3782454 --- /dev/null +++ b/vm/reference/java/lang/VMMath.java @@ -0,0 +1,493 @@ +/* VMMath.java -- Common mathematical functions. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +import gnu.classpath.Configuration; + +class VMMath +{ + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javalang"); + } + } + + /** + * The trigonometric function sin. The sine of NaN or infinity is + * NaN, and the sine of 0 retains its sign. This is accurate within 1 ulp, + * and is semi-monotonic. + * + * @param a the angle (in radians) + * @return sin(a) + */ + public static native double sin(double a); + + /** + * The trigonometric function cos. The cosine of NaN or infinity is + * NaN. This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the angle (in radians) + * @return cos(a) + */ + public static native double cos(double a); + + /** + * The trigonometric function tan. The tangent of NaN or infinity + * is NaN, and the tangent of 0 retains its sign. This is accurate within 1 + * ulp, and is semi-monotonic. + * + * @param a the angle (in radians) + * @return tan(a) + */ + public static native double tan(double a); + + /** + * The trigonometric function arcsin. The range of angles returned + * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN or + * its absolute value is beyond 1, the result is NaN; and the arcsine of + * 0 retains its sign. This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the sin to turn back into an angle + * @return arcsin(a) + */ + public static native double asin(double a); + + /** + * The trigonometric function arccos. The range of angles returned + * is 0 to pi radians (0 to 180 degrees). If the argument is NaN or + * its absolute value is beyond 1, the result is NaN. This is accurate + * within 1 ulp, and is semi-monotonic. + * + * @param a the cos to turn back into an angle + * @return arccos(a) + */ + public static native double acos(double a); + + /** + * The trigonometric function arcsin. The range of angles returned + * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN, the + * result is NaN; and the arctangent of 0 retains its sign. This is accurate + * within 1 ulp, and is semi-monotonic. + * + * @param a the tan to turn back into an angle + * @return arcsin(a) + * @see #atan2(double, double) + */ + public static native double atan(double a); + + /** + * A special version of the trigonometric function arctan, for + * converting rectangular coordinates (x, y) to polar + * (r, theta). This computes the arctangent of x/y in the range + * of -pi to pi radians (-180 to 180 degrees). Special cases:
        + *
      • If either argument is NaN, the result is NaN.
      • + *
      • If the first argument is positive zero and the second argument is + * positive, or the first argument is positive and finite and the second + * argument is positive infinity, then the result is positive zero.
      • + *
      • If the first argument is negative zero and the second argument is + * positive, or the first argument is negative and finite and the second + * argument is positive infinity, then the result is negative zero.
      • + *
      • If the first argument is positive zero and the second argument is + * negative, or the first argument is positive and finite and the second + * argument is negative infinity, then the result is the double value + * closest to pi.
      • + *
      • If the first argument is negative zero and the second argument is + * negative, or the first argument is negative and finite and the second + * argument is negative infinity, then the result is the double value + * closest to -pi.
      • + *
      • If the first argument is positive and the second argument is + * positive zero or negative zero, or the first argument is positive + * infinity and the second argument is finite, then the result is the + * double value closest to pi/2.
      • + *
      • If the first argument is negative and the second argument is + * positive zero or negative zero, or the first argument is negative + * infinity and the second argument is finite, then the result is the + * double value closest to -pi/2.
      • + *
      • If both arguments are positive infinity, then the result is the + * double value closest to pi/4.
      • + *
      • If the first argument is positive infinity and the second argument + * is negative infinity, then the result is the double value closest to + * 3*pi/4.
      • + *
      • If the first argument is negative infinity and the second argument + * is positive infinity, then the result is the double value closest to + * -pi/4.
      • + *
      • If both arguments are negative infinity, then the result is the + * double value closest to -3*pi/4.
      • + * + *

      This is accurate within 2 ulps, and is semi-monotonic. To get r, + * use sqrt(x*x+y*y). + * + * @param y the y position + * @param x the x position + * @return theta in the conversion of (x, y) to (r, theta) + * @see #atan(double) + */ + public static native double atan2(double y, double x); + + /** + * Take ea. The opposite of log(). If the + * argument is NaN, the result is NaN; if the argument is positive infinity, + * the result is positive infinity; and if the argument is negative + * infinity, the result is positive zero. This is accurate within 1 ulp, + * and is semi-monotonic. + * + * @param a the number to raise to the power + * @return the number raised to the power of e + * @see #log(double) + * @see #pow(double, double) + */ + public static native double exp(double a); + + /** + * Take ln(a) (the natural log). The opposite of exp(). If the + * argument is NaN or negative, the result is NaN; if the argument is + * positive infinity, the result is positive infinity; and if the argument + * is either zero, the result is negative infinity. This is accurate within + * 1 ulp, and is semi-monotonic. + * + *

      Note that the way to get logb(a) is to do this: + * ln(a) / ln(b). + * + * @param a the number to take the natural log of + * @return the natural log of a + * @see #exp(double) + */ + public static native double log(double a); + + /** + * Take a square root. If the argument is NaN or negative, the result is + * NaN; if the argument is positive infinity, the result is positive + * infinity; and if the result is either zero, the result is the same. + * This is accurate within the limits of doubles. + * + *

      For other roots, use pow(a, 1 / rootNumber). + * + * @param a the numeric argument + * @return the square root of the argument + * @see #pow(double, double) + */ + public static native double sqrt(double a); + + /** + * Raise a number to a power. Special cases:

        + *
      • If the second argument is positive or negative zero, then the result + * is 1.0.
      • + *
      • If the second argument is 1.0, then the result is the same as the + * first argument.
      • + *
      • If the second argument is NaN, then the result is NaN.
      • + *
      • If the first argument is NaN and the second argument is nonzero, + * then the result is NaN.
      • + *
      • If the absolute value of the first argument is greater than 1 and + * the second argument is positive infinity, or the absolute value of the + * first argument is less than 1 and the second argument is negative + * infinity, then the result is positive infinity.
      • + *
      • If the absolute value of the first argument is greater than 1 and + * the second argument is negative infinity, or the absolute value of the + * first argument is less than 1 and the second argument is positive + * infinity, then the result is positive zero.
      • + *
      • If the absolute value of the first argument equals 1 and the second + * argument is infinite, then the result is NaN.
      • + *
      • If the first argument is positive zero and the second argument is + * greater than zero, or the first argument is positive infinity and the + * second argument is less than zero, then the result is positive zero.
      • + *
      • If the first argument is positive zero and the second argument is + * less than zero, or the first argument is positive infinity and the + * second argument is greater than zero, then the result is positive + * infinity.
      • + *
      • If the first argument is negative zero and the second argument is + * greater than zero but not a finite odd integer, or the first argument is + * negative infinity and the second argument is less than zero but not a + * finite odd integer, then the result is positive zero.
      • + *
      • If the first argument is negative zero and the second argument is a + * positive finite odd integer, or the first argument is negative infinity + * and the second argument is a negative finite odd integer, then the result + * is negative zero.
      • + *
      • If the first argument is negative zero and the second argument is + * less than zero but not a finite odd integer, or the first argument is + * negative infinity and the second argument is greater than zero but not a + * finite odd integer, then the result is positive infinity.
      • + *
      • If the first argument is negative zero and the second argument is a + * negative finite odd integer, or the first argument is negative infinity + * and the second argument is a positive finite odd integer, then the result + * is negative infinity.
      • + *
      • If the first argument is less than zero and the second argument is a + * finite even integer, then the result is equal to the result of raising + * the absolute value of the first argument to the power of the second + * argument.
      • + *
      • If the first argument is less than zero and the second argument is a + * finite odd integer, then the result is equal to the negative of the + * result of raising the absolute value of the first argument to the power + * of the second argument.
      • + *
      • If the first argument is finite and less than zero and the second + * argument is finite and not an integer, then the result is NaN.
      • + *
      • If both arguments are integers, then the result is exactly equal to + * the mathematical result of raising the first argument to the power of + * the second argument if that result can in fact be represented exactly as + * a double value.
      • + * + *

      (In the foregoing descriptions, a floating-point value is + * considered to be an integer if and only if it is a fixed point of the + * method {@link #ceil(double)} or, equivalently, a fixed point of the + * method {@link #floor(double)}. A value is a fixed point of a one-argument + * method if and only if the result of applying the method to the value is + * equal to the value.) This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the number to raise + * @param b the power to raise it to + * @return ab + */ + public static native double pow(double a, double b); + + /** + * Get the IEEE 754 floating point remainder on two numbers. This is the + * value of x - y * n, where n is the closest + * double to x / y (ties go to the even n); for a zero + * remainder, the sign is that of x. If either argument is NaN, + * the first argument is infinite, or the second argument is zero, the result + * is NaN; if x is finite but y is infinite, the result is x. This is + * accurate within the limits of doubles. + * + * @param x the dividend (the top half) + * @param y the divisor (the bottom half) + * @return the IEEE 754-defined floating point remainder of x/y + * @see #rint(double) + */ + public static native double IEEEremainder(double x, double y); + + /** + * Take the nearest integer that is that is greater than or equal to the + * argument. If the argument is NaN, infinite, or zero, the result is the + * same; if the argument is between -1 and 0, the result is negative zero. + * Note that Math.ceil(x) == -Math.floor(-x). + * + * @param a the value to act upon + * @return the nearest integer >= a + */ + public static native double ceil(double a); + + /** + * Take the nearest integer that is that is less than or equal to the + * argument. If the argument is NaN, infinite, or zero, the result is the + * same. Note that Math.ceil(x) == -Math.floor(-x). + * + * @param a the value to act upon + * @return the nearest integer <= a + */ + public static native double floor(double a); + + /** + * Take the nearest integer to the argument. If it is exactly between + * two integers, the even integer is taken. If the argument is NaN, + * infinite, or zero, the result is the same. + * + * @param a the value to act upon + * @return the nearest integer to a + */ + public static native double rint(double a); + + /** + *

      + * Take a cube root. If the argument is NaN, an infinity or zero, then + * the original value is returned. The returned result must be within 1 ulp + * of the exact result. For a finite value, x, the cube root + * of -x is equal to the negation of the cube root + * of x. + *

      + *

      + * For a square root, use sqrt. For other roots, use + * pow(a, 1 / rootNumber). + *

      + * + * @param a the numeric argument + * @return the cube root of the argument + * @see #sqrt(double) + * @see #pow(double, double) + */ + public static native double cbrt(double a); + + /** + *

      + * Returns the hyperbolic cosine of the given value. For a value, + * x, the hyperbolic cosine is (ex + + * e-x)/2 + * with e being Euler's number. The returned + * result must be within 2.5 ulps of the exact result. + *

      + *

      + * If the supplied value is NaN, then the original value is + * returned. For either infinity, positive infinity is returned. + * The hyperbolic cosine of zero must be 1.0. + *

      + * + * @param a the numeric argument + * @return the hyperbolic cosine of a. + * @since 1.5 + */ + public static native double cosh(double a); + + /** + *

      + * Returns ea - 1. For values close to 0, the + * result of expm1(a) + 1 tend to be much closer to the + * exact result than simply exp(x). The result must be within + * 1 ulp of the exact result, and results must be semi-monotonic. For finite + * inputs, the returned value must be greater than or equal to -1.0. Once + * a result enters within half a ulp of this limit, the limit is returned. + *

      + *

      + * For NaN, positive infinity and zero, the original value + * is returned. Negative infinity returns a result of -1.0 (the limit). + *

      + * + * @param a the numeric argument + * @return ea - 1 + * @since 1.5 + */ + public static native double expm1(double a); + + /** + *

      + * Returns the hypotenuse, a2 + b2, + * without intermediate overflow or underflow. The returned result must be + * within 1 ulp of the exact result. If one parameter is held constant, + * then the result in the other parameter must be semi-monotonic. + *

      + *

      + * If either of the arguments is an infinity, then the returned result + * is positive infinity. Otherwise, if either argument is NaN, + * then NaN is returned. + *

      + * + * @param a the first parameter. + * @param b the second parameter. + * @return the hypotenuse matching the supplied parameters. + * @since 1.5 + */ + public static native double hypot(double a, double b); + + /** + *

      + * Returns the base 10 logarithm of the supplied value. The returned + * result must within 1 ulp of the exact result, and the results must be + * semi-monotonic. + *

      + *

      + * Arguments of either NaN or less than zero return + * NaN. An argument of positive infinity returns positive + * infinity. Negative infinity is returned if either positive or negative + * zero is supplied. Where the argument is the result of + * 10n, then n is returned. + *

      + * + * @param a the numeric argument. + * @return the base 10 logarithm of a. + * @since 1.5 + */ + public static native double log10(double a); + + /** + *

      + * Returns the natural logarithm resulting from the sum of the argument, + * a and 1. For values close to 0, the + * result of log1p(a) tend to be much closer to the + * exact result than simply log(1.0+a). The returned + * result must be within 1 ulp of the exact result, and the results must be + * semi-monotonic. + *

      + *

      + * Arguments of either NaN or less than -1 return + * NaN. An argument of positive infinity or zero + * returns the original argument. Negative infinity is returned from an + * argument of -1. + *

      + * + * @param a the numeric argument. + * @return the natural logarithm of a + 1. + * @since 1.5 + */ + public static native double log1p(double a); + + /** + *

      + * Returns the hyperbolic sine of the given value. For a value, + * x, the hyperbolic sine is (ex - + * e-x)/2 + * with e being Euler's number. The returned + * result must be within 2.5 ulps of the exact result. + *

      + *

      + * If the supplied value is NaN, an infinity or a zero, then the + * original value is returned. + *

      + * + * @param a the numeric argument + * @return the hyperbolic sine of a. + * @since 1.5 + */ + public static native double sinh(double a); + + /** + *

      + * Returns the hyperbolic tangent of the given value. For a value, + * x, the hyperbolic tangent is (ex - + * e-x)/(ex + e-x) + * (i.e. sinh(a)/cosh(a)) + * with e being Euler's number. The returned + * result must be within 2.5 ulps of the exact result. The absolute value + * of the exact result is always less than 1. Computed results are thus + * less than or equal to 1 for finite arguments, with results within + * half a ulp of either positive or negative 1 returning the appropriate + * limit value (i.e. as if the argument was an infinity). + *

      + *

      + * If the supplied value is NaN or zero, then the original + * value is returned. Positive infinity returns +1.0 and negative infinity + * returns -1.0. + *

      + * + * @param a the numeric argument + * @return the hyperbolic tangent of a. + * @since 1.5 + */ + public static native double tanh(double a); + +} diff --git a/vm/reference/java/lang/reflect/Constructor.java b/vm/reference/java/lang/reflect/Constructor.java index 075661321..9ec20a151 100644 --- a/vm/reference/java/lang/reflect/Constructor.java +++ b/vm/reference/java/lang/reflect/Constructor.java @@ -67,8 +67,8 @@ import java.util.Arrays; * @author Eric Blake * @see Member * @see Class - * @see java.lang.Class#getConstructor(Object[]) - * @see java.lang.Class#getDeclaredConstructor(Object[]) + * @see java.lang.Class#getConstructor(Class[]) + * @see java.lang.Class#getDeclaredConstructor(Class[]) * @see java.lang.Class#getConstructors() * @see java.lang.Class#getDeclaredConstructors() * @since 1.1 diff --git a/vm/reference/java/lang/reflect/Method.java b/vm/reference/java/lang/reflect/Method.java index 6cc2ca761..29cde5137 100644 --- a/vm/reference/java/lang/reflect/Method.java +++ b/vm/reference/java/lang/reflect/Method.java @@ -67,8 +67,8 @@ import java.util.Arrays; * @author Eric Blake * @see Member * @see Class - * @see java.lang.Class#getMethod(String,Object[]) - * @see java.lang.Class#getDeclaredMethod(String,Object[]) + * @see java.lang.Class#getMethod(String,Class[]) + * @see java.lang.Class#getDeclaredMethod(String,Class[]) * @see java.lang.Class#getMethods() * @see java.lang.Class#getDeclaredMethods() * @since 1.1 -- cgit v1.2.1